├── .github └── workflows │ └── build.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .openshift ├── action_hooks │ └── README.md ├── config │ ├── modules │ │ ├── README │ │ └── jeeshop │ │ │ └── configuration │ │ │ └── main │ │ │ ├── mailer.properties │ │ │ ├── module.xml │ │ │ └── orderconfiguration.properties │ └── standalone.xml ├── cron │ ├── README.cron │ ├── daily │ │ └── .gitignore │ ├── hourly │ │ └── .gitignore │ ├── minutely │ │ └── .gitignore │ ├── monthly │ │ └── .gitignore │ └── weekly │ │ ├── README │ │ ├── chrono.dat │ │ ├── chronograph │ │ ├── jobs.allow │ │ └── jobs.deny └── markers │ └── java8 ├── Dockerfile ├── LICENSE ├── README.md ├── admin ├── pom.xml └── src │ └── main │ ├── docker │ ├── Dockerfile.jvm │ └── Dockerfile.native │ ├── java │ └── org │ │ └── rembx │ │ └── jeeshop │ │ └── admin │ │ └── ApplicationConfig.java │ ├── resources │ ├── META-INF │ │ ├── beans.xml │ │ └── resources │ │ │ ├── orderconfiguration.properties │ │ │ └── server.keystore │ └── application.properties │ └── webapp │ ├── app │ ├── app.js │ ├── catalog │ │ ├── catalog-entries.html │ │ ├── catalogs-form.html │ │ ├── categories-form.html │ │ ├── common-catalog-form-fields.html │ │ ├── discounts-form.html │ │ ├── index.html │ │ ├── js │ │ │ └── catalog.js │ │ ├── pres-features-accordion.html │ │ ├── presentations-accordion.html │ │ ├── products-form.html │ │ ├── relationships-accordion.html │ │ └── skus-form.html │ ├── css │ │ ├── app.css │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.min.css │ │ ├── bootstrap.min.css.map │ │ └── dashboard.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── home │ │ └── index.html │ ├── images │ │ └── loading.gif │ ├── lib │ │ └── stringview.min.js │ ├── mail │ │ ├── index.html │ │ ├── js │ │ │ └── mail.js │ │ ├── mail-operations.html │ │ ├── mailtemplate-entries.html │ │ ├── mailtemplate-form.html │ │ └── newsletters.html │ ├── order │ │ ├── index.html │ │ ├── js │ │ │ └── order.js │ │ ├── order-entries.html │ │ ├── order-form.html │ │ └── order-operations.html │ ├── statistic │ │ └── index.html │ ├── user │ │ ├── index.html │ │ ├── js │ │ │ ├── login.js │ │ │ └── user.js │ │ ├── reset-password-dialog.html │ │ ├── user-entries.html │ │ └── user-form.html │ └── util │ │ ├── confirm-delete-danger.html │ │ ├── confirm-dialog.html │ │ └── js │ │ └── util.js │ ├── errors │ └── error-401.jsp │ ├── index.html │ ├── package-lock.json │ ├── package.json │ └── webpack.config.js ├── catalog ├── pom.xml └── src │ ├── main │ ├── asciidoc │ │ ├── CatalogItem.adoc │ │ ├── CatalogItemRelationShip.adoc │ │ ├── Catalogs.adoc │ │ ├── Categories.adoc │ │ ├── Discounts.adoc │ │ ├── Medias.adoc │ │ ├── Products.adoc │ │ ├── SKUs.adoc │ │ ├── rest-api.adoc │ │ └── snippets │ │ │ ├── catalog.in.json.adoc │ │ │ ├── catalog.json.adoc │ │ │ ├── catalog.list.json.adoc │ │ │ ├── catalog.presentation.json.adoc │ │ │ ├── category.in.json.adoc │ │ │ ├── category.json.adoc │ │ │ ├── category.list.json.adoc │ │ │ ├── category.presentation.json.adoc │ │ │ ├── discount.in.json.adoc │ │ │ ├── discount.json.adoc │ │ │ ├── discount.list.json.adoc │ │ │ ├── discount.presentation.json.adoc │ │ │ ├── product.in.json.adoc │ │ │ ├── product.json.adoc │ │ │ ├── product.list.json.adoc │ │ │ ├── product.presentation.json.adoc │ │ │ ├── sku.in.json.adoc │ │ │ ├── sku.json.adoc │ │ │ ├── sku.list.json.adoc │ │ │ └── sku.presentation.json.adoc │ ├── java │ │ └── org │ │ │ └── rembx │ │ │ └── jeeshop │ │ │ └── catalog │ │ │ ├── CatalogItemFinder.java │ │ │ ├── CatalogItemService.java │ │ │ ├── Catalogs.java │ │ │ ├── Categories.java │ │ │ ├── DiscountFinder.java │ │ │ ├── Discounts.java │ │ │ ├── OwnerUtils.java │ │ │ ├── PresentationResource.java │ │ │ ├── Products.java │ │ │ ├── SKUs.java │ │ │ ├── Stores.java │ │ │ └── model │ │ │ ├── Catalog.java │ │ │ ├── CatalogItem.java │ │ │ ├── CatalogPersistenceUnit.java │ │ │ ├── Category.java │ │ │ ├── Discount.java │ │ │ ├── Premises.java │ │ │ ├── PremisesAddress.java │ │ │ ├── PremisesOpeningSchedules.java │ │ │ ├── Presentation.java │ │ │ ├── Product.java │ │ │ ├── SKU.java │ │ │ └── Store.java │ └── resources │ │ ├── META-INF │ │ └── beans.xml │ │ └── log4j.xml │ └── test │ ├── java │ └── org │ │ └── rembx │ │ └── jeeshop │ │ └── catalog │ │ ├── CatalogItemFinderTest.java │ │ ├── CatalogsCT.java │ │ ├── CategoriesCT.java │ │ ├── DiscountsCT.java │ │ ├── PresentationResourceCT.java │ │ ├── ProductsCT.java │ │ ├── SKUsCT.java │ │ ├── StoresCT.java │ │ ├── model │ │ └── DiscountTest.java │ │ └── test │ │ ├── Assertions.java │ │ ├── CatalogItemCRUDTester.java │ │ ├── PresentationTexts.java │ │ └── TestCatalog.java │ └── resources │ ├── META-INF │ └── persistence.xml │ └── log4j.xml ├── common ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── asciidoc │ │ └── rest-api-general.adoc │ ├── java │ │ └── org │ │ │ └── rembx │ │ │ └── jeeshop │ │ │ ├── configuration │ │ │ ├── ConfigurationProducer.java │ │ │ └── NamedConfiguration.java │ │ │ ├── mail │ │ │ └── Mailer.java │ │ │ ├── rest │ │ │ ├── WebApplicationException.java │ │ │ └── WebApplicationExceptionMapper.java │ │ │ ├── role │ │ │ ├── AuthorizationUtils.java │ │ │ └── JeeshopRoles.java │ │ │ └── util │ │ │ ├── DateUtil.java │ │ │ └── LocaleUtil.java │ └── resources │ │ └── META-INF │ │ └── beans.xml │ └── test │ ├── java │ └── org │ │ └── rembx │ │ └── jeeshop │ │ ├── configuration │ │ ├── ConfigurationProducerCT.java │ │ └── TestProducer.java │ │ ├── mail │ │ └── MailerIT.java │ │ └── util │ │ ├── DateUtilTest.java │ │ └── LocaleUtilTest.java │ └── resources │ ├── META-INF │ └── beans.xml │ ├── mailer.properties │ ├── namedconfigurationcustom.properties │ └── namedconfigurationuse.properties ├── deployments └── .gitkeep ├── docker-compose.yml ├── install ├── pom.xml └── src │ └── main │ └── resources │ ├── db │ ├── mysql │ │ ├── V1.0_1__jeeshop-install.sql │ │ └── V1.0__jeeshop-drop.sql │ └── postgresql │ │ ├── V1.0_1__jeeshop-install.sql │ │ ├── V1.0_2__create_store.sql │ │ └── V1.0__jeeshop-drop.sql │ └── demo │ ├── db │ ├── mysql │ │ └── demo-catalog-data.sql │ └── postgresql │ │ ├── demo-catalog-data.sql │ │ └── demo-order-data.sql │ ├── jeeshop-media │ ├── categories │ │ ├── 1 │ │ │ ├── en │ │ │ │ └── bikes_root_cat.jpg │ │ │ └── fr │ │ │ │ └── bikes_root_cat.jpg │ │ ├── 2 │ │ │ ├── en │ │ │ │ └── accessories_root_cat.jpg │ │ │ └── fr │ │ │ │ └── accessories_root_cat.jpg │ │ ├── 7 │ │ │ ├── en │ │ │ │ └── bikes_root_cat.jpg │ │ │ └── fr │ │ │ │ └── bikes_root_cat.jpg │ │ └── 12 │ │ │ ├── en │ │ │ └── racing-bikes.jpg │ │ │ └── fr │ │ │ └── racing-bikes.jpg │ ├── discounts │ │ ├── 2 │ │ │ ├── en │ │ │ │ └── pastille-livraison.png │ │ │ └── fr │ │ │ │ └── pastille-livraison.png │ │ └── 5 │ │ │ ├── en │ │ │ └── pastille-10-pourcent.png │ │ │ └── fr │ │ │ └── pastille-10-pourcent.png │ └── products │ │ ├── 1 │ │ ├── en │ │ │ └── energy_x1.jpg │ │ └── fr │ │ │ └── energy_x1.jpg │ │ └── 2 │ │ ├── en │ │ └── energy_x2.jpg │ │ └── fr │ │ └── energy_x2.jpg │ └── mailTemplates │ ├── orderValidated_en.ftl │ ├── orderValidated_fr.ftl │ ├── userRegistration_en.ftl │ ├── userRegistration_fr.ftl │ ├── userResetPassword_en.ftl │ └── userResetPassword_fr.ftl ├── media ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── rembx │ │ │ └── jeeshop │ │ │ └── media │ │ │ ├── Medias.java │ │ │ └── model │ │ │ └── Media.java │ └── resources │ │ └── META-INF │ │ └── beans.xml │ └── test │ └── java │ └── org │ └── rembx │ └── jeeshop │ └── media │ └── MediasTest.java ├── mvnw ├── order ├── pom.xml └── src │ ├── main │ ├── asciidoc │ │ ├── EligibleDiscounts.adoc │ │ ├── Orders.adoc │ │ └── rest-api.adoc │ ├── java │ │ └── org │ │ │ └── rembx │ │ │ └── jeeshop │ │ │ └── order │ │ │ ├── DefaultPaymentTransactionEngine.java │ │ │ ├── EligibleDiscounts.java │ │ │ ├── Fees.java │ │ │ ├── OrderConfiguration.java │ │ │ ├── OrderFinder.java │ │ │ ├── Orders.java │ │ │ ├── PaymentTransactionEngine.java │ │ │ ├── PriceEngine.java │ │ │ ├── PriceEngineImpl.java │ │ │ └── mail │ │ │ └── Mails.java │ └── resources │ │ └── META-INF │ │ └── beans.xml │ └── test │ ├── java │ └── org │ │ └── rembx │ │ └── jeeshop │ │ └── order │ │ ├── EligibleDiscountsCT.java │ │ ├── FeesTest.java │ │ ├── OrdersCT.java │ │ ├── PriceEngineImplTest.java │ │ └── test │ │ ├── TestMailTemplate.java │ │ └── TestOrder.java │ └── resources │ ├── META-INF │ └── persistence.xml │ ├── global.properties │ └── log4j.xml ├── pom.xml └── user ├── pom.xml └── src ├── main ├── asciidoc │ ├── MailTemplates.adoc │ ├── Users.adoc │ └── rest-api.adoc ├── java │ └── org │ │ └── rembx │ │ └── jeeshop │ │ ├── order │ │ └── model │ │ │ ├── Order.java │ │ │ ├── OrderDiscount.java │ │ │ ├── OrderItem.java │ │ │ ├── OrderStatus.java │ │ │ └── PaymentInfo.java │ │ └── user │ │ ├── CountryChecker.java │ │ ├── MailTemplateFinder.java │ │ ├── MailTemplates.java │ │ ├── RoleFinder.java │ │ ├── UserFinder.java │ │ ├── Users.java │ │ ├── mail │ │ └── Mails.java │ │ ├── model │ │ ├── Address.java │ │ ├── Email.java │ │ ├── MailTemplate.java │ │ ├── Newsletter.java │ │ ├── Phone.java │ │ ├── Role.java │ │ ├── RoleName.java │ │ ├── User.java │ │ └── UserPersistenceUnit.java │ │ └── tools │ │ └── CryptTools.java └── resources │ ├── META-INF │ └── beans.xml │ └── ValidationMessages.properties └── test ├── java └── org │ └── rembx │ └── jeeshop │ ├── order │ └── model │ │ └── OrderTest.java │ └── user │ ├── MailTemplatesCT.java │ ├── UsersCT.java │ ├── test │ ├── TestMailTemplate.java │ └── TestUser.java │ └── tools │ └── CryptToolsTest.java └── resources ├── META-INF └── persistence.xml ├── global.properties └── log4j.xml /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created 2 | # For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path 3 | 4 | name: Build 5 | 6 | on: [push, pull_request] 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 11 16 | uses: actions/setup-java@v1 17 | with: 18 | java-version: 11 19 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml 20 | settings-path: ${{ github.workspace }} # location for the settings.xml file 21 | 22 | - name: Build with Maven 23 | run: mvn -B package -Dquarkus.package.type=fast-jar --file pom.xml 24 | 25 | - name: Set up QEMU 26 | uses: docker/setup-qemu-action@v1 27 | 28 | - name: Set up Docker Buildx 29 | uses: docker/setup-buildx-action@v1 30 | 31 | - name: Login to DockerHub 32 | if: contains( github.ref, 'master') || contains( github.ref, 'develop') 33 | uses: docker/login-action@v1 34 | with: 35 | username: ${{ secrets.DOCKERHUB_USERNAME }} 36 | password: ${{ secrets.DOCKERHUB_TOKEN }} 37 | 38 | - name: Build and push 39 | if: contains( github.ref, 'develop') 40 | id: docker_build_develop 41 | uses: docker/build-push-action@v2 42 | with: 43 | context: . 44 | file: ./Dockerfile 45 | push: true 46 | tags: jeeshop/admin:dev 47 | 48 | - name: Build and push 49 | if: contains( github.ref, 'master') 50 | id: docker_build_master 51 | uses: docker/build-push-action@v2 52 | with: 53 | context: . 54 | file: ./Dockerfile 55 | push: true 56 | tags: jeeshop/admin:latest 57 | 58 | - name: Image digest 59 | if: contains( github.ref, 'master') 60 | run: echo ${{ steps.docker_build.outputs.digest }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/** 2 | *.iml 3 | .idea 4 | 5 | npm-debug.log 6 | 7 | node_modules 8 | node 9 | 10 | target/ 11 | built 12 | dist 13 | app_bundle.js 14 | 15 | /admin/src/main/webapp/app_bundle.js 16 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -------------------------------------------------------------------------------- /.openshift/action_hooks/README.md: -------------------------------------------------------------------------------- 1 | For information about action hooks supported by OpenShift, consult the documentation: 2 | 3 | https://github.com/openshift/origin-server/tree/master/node/README.writing_applications.md#action-hooks 4 | -------------------------------------------------------------------------------- /.openshift/config/modules/README: -------------------------------------------------------------------------------- 1 | Place your WildFly 8 modules in this directory. This directory is added to the 2 | module path of the WildFly 8 server associated with your application. It has the 3 | same structure as the standard WildFly 8 modules directory. 4 | 5 | The modules placed in this directory will be added to or override the default modules 6 | provided by the OpenShift WildFly 8 cartridge. 7 | 8 | Scenarios: 9 | 1) Replace a default module with a new module that contains a bug fix or new feature 10 | 2) Add a module that does not exist in the base OpenShift WildFly 8 cartridge in order to add 11 | a new component. Typically these new modules will need to be enabled and configured in 12 | standalone.xml 13 | 14 | Unless one of the above scenarios is required there is no need to modify the 15 | modules directory. 16 | 17 | NOTE: Replacing default modules as in scenario 1 can cause conflicts between modules so 18 | should be done with caution and adequate testing. 19 | -------------------------------------------------------------------------------- /.openshift/config/modules/jeeshop/configuration/main/mailer.properties: -------------------------------------------------------------------------------- 1 | mail.smtp.host=localhost 2 | mail.smtp.port=25 3 | mail.smtp.timeout=5000 4 | mail.smtp.connectiontimeout=2000 5 | mail.auth.user= 6 | mail.auth.password= 7 | mail.from= 8 | debug=true 9 | 10 | -------------------------------------------------------------------------------- /.openshift/config/modules/jeeshop/configuration/main/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.openshift/config/modules/jeeshop/configuration/main/orderconfiguration.properties: -------------------------------------------------------------------------------- 1 | fixed.delivery.fee=11.0 2 | vat=20 3 | -------------------------------------------------------------------------------- /.openshift/cron/README.cron: -------------------------------------------------------------------------------- 1 | Run scripts or jobs on a periodic basis 2 | ======================================= 3 | Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly 4 | directories will be run on a scheduled basis (frequency is as indicated by the 5 | name of the directory) using run-parts. 6 | 7 | run-parts ignores any files that are hidden or dotfiles (.*) or backup 8 | files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} 9 | 10 | The presence of two specially named files jobs.deny and jobs.allow controls 11 | how run-parts executes your scripts/jobs. 12 | jobs.deny ===> Prevents specific scripts or jobs from being executed. 13 | jobs.allow ===> Only execute the named scripts or jobs (all other/non-named 14 | scripts that exist in this directory are ignored). 15 | 16 | The principles of jobs.deny and jobs.allow are the same as those of cron.deny 17 | and cron.allow and are described in detail at: 18 | http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access 19 | 20 | See: man crontab or above link for more details and see the the weekly/ 21 | directory for an example. 22 | 23 | PLEASE NOTE: The Cron cartridge must be installed in order to run the configured jobs. 24 | -------------------------------------------------------------------------------- /.openshift/cron/daily/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/.openshift/cron/daily/.gitignore -------------------------------------------------------------------------------- /.openshift/cron/hourly/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/.openshift/cron/hourly/.gitignore -------------------------------------------------------------------------------- /.openshift/cron/minutely/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/.openshift/cron/minutely/.gitignore -------------------------------------------------------------------------------- /.openshift/cron/monthly/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/.openshift/cron/monthly/.gitignore -------------------------------------------------------------------------------- /.openshift/cron/weekly/README: -------------------------------------------------------------------------------- 1 | Run scripts or jobs on a weekly basis 2 | ===================================== 3 | Any scripts or jobs added to this directory will be run on a scheduled basis 4 | (weekly) using run-parts. 5 | 6 | run-parts ignores any files that are hidden or dotfiles (.*) or backup 7 | files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles 8 | the files named jobs.deny and jobs.allow specially. 9 | 10 | In this specific example, the chronograph script is the only script or job file 11 | executed on a weekly basis (due to white-listing it in jobs.allow). And the 12 | README and chrono.dat file are ignored either as a result of being black-listed 13 | in jobs.deny or because they are NOT white-listed in the jobs.allow file. 14 | 15 | For more details, please see ../README.cron file. 16 | 17 | -------------------------------------------------------------------------------- /.openshift/cron/weekly/chrono.dat: -------------------------------------------------------------------------------- 1 | Time And Relative D...n In Execution (Open)Shift! 2 | -------------------------------------------------------------------------------- /.openshift/cron/weekly/chronograph: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "$(date): $(cat $(dirname \"$0\")/chrono.dat)" 4 | -------------------------------------------------------------------------------- /.openshift/cron/weekly/jobs.allow: -------------------------------------------------------------------------------- 1 | # 2 | # Script or job files listed in here (one entry per line) will be 3 | # executed on a weekly-basis. 4 | # 5 | # Example: The chronograph script will be executed weekly but the README 6 | # and chrono.dat files in this directory will be ignored. 7 | # 8 | # The README file is actually ignored due to the entry in the 9 | # jobs.deny which is checked before jobs.allow (this file). 10 | # 11 | chronograph 12 | 13 | -------------------------------------------------------------------------------- /.openshift/cron/weekly/jobs.deny: -------------------------------------------------------------------------------- 1 | # 2 | # Any script or job files listed in here (one entry per line) will NOT be 3 | # executed (read as ignored by run-parts). 4 | # 5 | 6 | README 7 | 8 | -------------------------------------------------------------------------------- /.openshift/markers/java8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/.openshift/markers/java8 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Dquarkus.package.type=fast-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.fast-jar -t quarkus/code-with-quarkus-fast-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-fast-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/code-with-quarkus-fast-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | 32 | # Install java and the run-java script 33 | # Also set up permissions for user `1001` 34 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 35 | && microdnf update \ 36 | && microdnf clean all \ 37 | && mkdir /deployments \ 38 | && chown 1001 /deployments \ 39 | && chmod "g+rwX" /deployments \ 40 | && chown 1001:root /deployments \ 41 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 42 | && chown 1001 /deployments/run-java.sh \ 43 | && chmod 540 /deployments/run-java.sh \ 44 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 45 | 46 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.RUN echo ${PORT} 47 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 48 | 49 | # We make four distinct layers so if there are application changes the library layers can be re-used 50 | COPY --chown=1001 admin/target/quarkus-app/lib/ /deployments/lib/ 51 | COPY --chown=1001 admin/target/quarkus-app/*.jar /deployments/ 52 | COPY --chown=1001 admin/target/quarkus-app/app/ /deployments/app/ 53 | COPY --chown=1001 admin/target/quarkus-app/quarkus/ /deployments/quarkus/ 54 | 55 | ENV DATA_DIR="/jeeshop" 56 | RUN mkdir -p $DATA_DIR 57 | RUN chown -R 1001:1001 $DATA_DIR 58 | RUN chmod -R 760 $DATA_DIR 59 | 60 | EXPOSE ${PORT} 61 | USER 1001 62 | 63 | ENTRYPOINT /deployments/run-java.sh -Dquarkus.http.port=${PORT} 64 | -------------------------------------------------------------------------------- /admin/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/code-with-quarkus-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/code-with-quarkus-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | 29 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 30 | 31 | # Install java and the run-java script 32 | # Also set up permissions for user `1001` 33 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 34 | && microdnf update \ 35 | && microdnf clean all \ 36 | && mkdir /deployments \ 37 | && chown 1001 /deployments \ 38 | && chmod "g+rwX" /deployments \ 39 | && chown 1001:root /deployments \ 40 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 41 | && chown 1001 /deployments/run-java.sh \ 42 | && chmod 540 /deployments/run-java.sh \ 43 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 44 | 45 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 46 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 47 | 48 | COPY target/lib/* /deployments/lib/ 49 | COPY target/*-runner.jar /deployments/app.jar 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] -------------------------------------------------------------------------------- /admin/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # mvn package -Pnative -Dquarkus.native.container-build=true 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/code-with-quarkus . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/code-with-quarkus 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] -------------------------------------------------------------------------------- /admin/src/main/java/org/rembx/jeeshop/admin/ApplicationConfig.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.admin; 2 | 3 | import org.rembx.jeeshop.catalog.*; 4 | import org.rembx.jeeshop.media.Medias; 5 | import org.rembx.jeeshop.order.Orders; 6 | import org.rembx.jeeshop.rest.WebApplicationExceptionMapper; 7 | import org.rembx.jeeshop.user.MailTemplates; 8 | import org.rembx.jeeshop.user.Users; 9 | 10 | import javax.ws.rs.ApplicationPath; 11 | import javax.ws.rs.core.Application; 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | 15 | @ApplicationPath("/") 16 | public class ApplicationConfig extends Application { 17 | 18 | @Override 19 | public Set> getClasses() { 20 | 21 | Set> classes = new HashSet<>(); 22 | classes.add(Stores.class); 23 | classes.add(Catalogs.class); 24 | classes.add(Categories.class); 25 | classes.add(Products.class); 26 | classes.add(SKUs.class); 27 | classes.add(Discounts.class); 28 | classes.add(Users.class); 29 | classes.add(Medias.class); 30 | classes.add(MailTemplates.class); 31 | classes.add(Orders.class); 32 | classes.add(WebApplicationExceptionMapper.class); 33 | return classes; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /admin/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /admin/src/main/resources/META-INF/resources/orderconfiguration.properties: -------------------------------------------------------------------------------- 1 | fixed.delivery.fee=11.0 2 | vat=20 3 | -------------------------------------------------------------------------------- /admin/src/main/resources/META-INF/resources/server.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/admin/src/main/resources/META-INF/resources/server.keystore -------------------------------------------------------------------------------- /admin/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | %dev.database.host= localhost:5432 2 | database.host=${JEESHOP_DATABASE_HOSTNAME:host.docker.internal:5432} 3 | database.name=${JEESHOP_DATABASENAME:jeeshop} 4 | database.username=${JEESHOP_DATABASE_USERNAME:} 5 | database.password=${JEESHOP_DATABASE_PASSWORD:} 6 | database.jdbc.driver=${JEESHOP_JDBC_DRIVER:postgresql} 7 | 8 | %dev.catalog.database.host=${JEESHOP_CATALOG_DATABASE_HOSTNAME:localhost:5432} 9 | catalog.database.host=${JEESHOP_CATALOG_DATABASE_HOSTNAME:host.docker.internal:5432} 10 | catalog.database.name=${JEESHOP_CATALOG_DATABASENAME:jeeshop} 11 | catalog.database.username=${JEESHOP_CATALOG_DATABASE_USERNAME:} 12 | catalog.database.password=${JEESHOP_CATALOG_DATABASE_PASSWORD:} 13 | catalog.database.jdbc.driver=${JEESHOP_CATALOG_JDBC_DRIVER:postgresql} 14 | 15 | quarkus.datasource.CatalogDS.db-kind=${catalog.database.jdbc.driver} 16 | quarkus.datasource.CatalogDS.username=${catalog.database.username} 17 | quarkus.datasource.CatalogDS.password=${catalog.database.password} 18 | quarkus.datasource.CatalogDS.jdbc.url=jdbc:postgresql://${catalog.database.host}/${catalog.database.name} 19 | 20 | quarkus.datasource.UserDS.db-kind=${database.jdbc.driver} 21 | quarkus.datasource.UserDS.username=${database.username} 22 | quarkus.datasource.UserDS.password=${database.password} 23 | quarkus.datasource.UserDS.jdbc.url=jdbc:postgresql://${database.host}/${database.name} 24 | 25 | quarkus.hibernate-orm.Catalog.dialect=org.hibernate.dialect.PostgreSQL95Dialect 26 | quarkus.hibernate-orm.Catalog.database.default-schema=jeeshop 27 | quarkus.hibernate-orm.Catalog.datasource=CatalogDS 28 | quarkus.hibernate-orm.Catalog.packages=org.rembx.jeeshop.catalog.model,org.rembx.jeeshop.media.model 29 | 30 | quarkus.hibernate-orm.User.dialect=org.hibernate.dialect.PostgreSQL95Dialect 31 | quarkus.hibernate-orm.User.database.default-schema=jeeshop 32 | quarkus.hibernate-orm.User.datasource=UserDS 33 | quarkus.hibernate-orm.User.packages=org.rembx.jeeshop.user.model,org.rembx.jeeshop.media.model,org.rembx.jeeshop.order.model 34 | 35 | quarkus.flyway.CatalogDS.migrate-at-start=true 36 | quarkus.flyway.CatalogDS.schemas=jeeshop 37 | quarkus.flyway.CatalogDS.placeholder-prefix=#[ 38 | quarkus.flyway.CatalogDS.sql-migration-prefix=V 39 | quarkus.flyway.CatalogDS.baseline-on-migrate=true 40 | 41 | quarkus.ssl.native=true 42 | quarkus.http.ssl-port=8443 43 | quarkus.http.ssl.certificate.key-store-file=${JEESHOP_SSL_KEYSTORE_PATH:META-INF/resources/server.keystore} 44 | quarkus.http.ssl.certificate.key-store-password=${JEESHOP_SSL_KEYSTORE_PASSWORD:test123} 45 | 46 | quarkus.log.level=INFO 47 | quarkus.log.category."org.hibernate".level=ERROR 48 | quarkus.log.file.enable=true 49 | quarkus.log.file.rotation.max-file-size=1M 50 | %dev.quarkus.log.file.enable=false 51 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/catalog/catalogs-form.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 |
7 | 8 |
9 | 10 |
12 |
13 | 14 |
15 | 16 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/catalog/categories-form.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/catalog/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 20 |
21 |
22 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/catalog/pres-features-accordion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Map of features 5 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 16 | 18 |
19 |
20 | 22 |
23 | 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 43 | 47 | 48 | 49 |
NameValue
38 | {{key}} 39 | 41 | {{value}} 42 | 44 | 46 |
50 |
51 |
52 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/catalog/products-form.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/catalog/skus-form.html: -------------------------------------------------------------------------------- 1 |
2 |
4 | 5 |
6 | 7 |
8 | 9 |
10 |   11 | available 12 | not available 13 |

Available when quantity is greater than availability threshold

14 |
15 |
16 | 17 | 19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | 28 |
29 | 30 |
31 | 32 | 36 |
37 |
38 | 39 |
40 | 41 |
42 | 43 | 45 |
46 | 47 |
48 | 49 | 51 |
52 |
53 | 54 |
55 | 56 | 57 |
58 | 59 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/css/app.css: -------------------------------------------------------------------------------- 1 | #loaderDiv { 2 | position:fixed; 3 | top:0; 4 | left:0; 5 | width:100%; 6 | height:100%; 7 | z-index:1100; 8 | } 9 | 10 | .ajax-loader { 11 | position: absolute; 12 | left: 50%; 13 | top: 50%; 14 | margin-left: -32px; /* -1 * image width / 2 */ 15 | margin-top: -32px; /* -1 * image height / 2 */ 16 | display: block; 17 | } 18 | 19 | .side_menu_item_title { 20 | margin-left:1.5em; 21 | } 22 | 23 | th a{ 24 | color: #333; 25 | } -------------------------------------------------------------------------------- /admin/src/main/webapp/app/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Base structure 3 | */ 4 | 5 | /* Move down content because we have a fixed navbar that is 50px tall */ 6 | body { 7 | padding-top: 50px; 8 | } 9 | 10 | 11 | /* 12 | * Global add-ons 13 | */ 14 | 15 | .sub-header { 16 | padding-bottom: 10px; 17 | border-bottom: 1px solid #eee; 18 | } 19 | 20 | 21 | /* 22 | * Sidebar 23 | */ 24 | 25 | /* Hide for mobile, show later */ 26 | .sidebar { 27 | display: none; 28 | } 29 | @media (min-width: 768px) { 30 | .sidebar { 31 | position: fixed; 32 | top: 51px; 33 | bottom: 0; 34 | left: 0; 35 | z-index: 1000; 36 | display: block; 37 | padding: 20px; 38 | overflow-x: hidden; 39 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 40 | background-color: #f5f5f5; 41 | border-right: 1px solid #eee; 42 | } 43 | } 44 | 45 | /* Sidebar navigation */ 46 | .nav-sidebar { 47 | margin-right: -21px; /* 20px padding + 1px border */ 48 | margin-bottom: 20px; 49 | margin-left: -20px; 50 | } 51 | .nav-sidebar > li > a { 52 | padding-right: 20px; 53 | padding-left: 20px; 54 | } 55 | .nav-sidebar > .active > a, .nav-sidebar > .active > a:focus { 56 | color: #fff; 57 | background-color: #428bca; 58 | } 59 | 60 | 61 | /* 62 | * Main content 63 | */ 64 | 65 | .main { 66 | padding: 20px; 67 | } 68 | @media (min-width: 768px) { 69 | .main { 70 | padding-right: 40px; 71 | padding-left: 40px; 72 | } 73 | } 74 | .main .page-header { 75 | margin-top: 0; 76 | } 77 | 78 | 79 | /* 80 | * Placeholder dashboard ideas 81 | */ 82 | 83 | .placeholders { 84 | margin-bottom: 30px; 85 | text-align: center; 86 | } 87 | .placeholders h4 { 88 | margin-bottom: 0; 89 | } 90 | .placeholder { 91 | margin-bottom: 20px; 92 | } 93 | .placeholder img { 94 | display: inline-block; 95 | border-radius: 50%; 96 | } 97 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/admin/src/main/webapp/app/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /admin/src/main/webapp/app/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/admin/src/main/webapp/app/images/loading.gif -------------------------------------------------------------------------------- /admin/src/main/webapp/app/mail/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/mail/mail-operations.html: -------------------------------------------------------------------------------- 1 |
2 |

Test e-mail templates

3 |

Generate test e-mails based on Jeeshop templates with fake test data inside.

4 |
5 |
6 | 7 | {{alert.msg}} 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 |
18 |
19 | 20 |
21 | 24 | 26 | 27 |

Recipient is required

29 |
30 |
31 |
32 |
34 | 35 | 50 | 51 |

52 | Select an existing mail template 53 |

54 |
55 | 56 |
58 | 59 | 64 |

65 | Select a locale configured for an existing mail template 66 |

67 |
68 | 69 |
70 | 71 | 72 |
73 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/mail/mailtemplate-entries.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 |
8 | Show 9 | 14 | elements per page 15 |
16 |
17 |

18 | 19 | 20 | 21 | 23 | 24 |

25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 |
IDNameLocale
{{entry.id}}{{entry.name}}{{entry.locale}}{{entry.creationDate|date : 'medium'}}{{entry.updateDate|date : 'medium'}} 46 | 47 |
51 | 53 |
54 | 55 |
56 | 57 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/mail/newsletters.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 |
8 | Show 9 | 14 | elements per page 15 |
16 |
17 |

18 | 19 | 20 | 21 | 23 | 24 |

25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 |
IDNameLocale
{{entry.id}}{{entry.name}}{{entry.locale}}{{entry.creationDate|date : 'medium'}}{{entry.updateDate|date : 'medium'}} 46 | 47 |
51 | 53 |
54 | 55 |
56 | 57 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/order/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 11 |
12 |
13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/order/order-operations.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | {{alert.msg}} 7 | 8 | 9 |
10 |
11 |
12 | 13 |
14 | 15 |
16 |
17 |

Process Payed orders

18 | 21 | 23 | 24 |

Filter orders with items matching given SKU identifier

25 |
26 | 29 |

Export orders items for orders with payment validated to a CSV file with items delivery information

30 |
31 |
32 | 33 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/statistic/index.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/user/index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 |
-------------------------------------------------------------------------------- /admin/src/main/webapp/app/user/js/login.js: -------------------------------------------------------------------------------- 1 | (function (){ 2 | var app = angular.module('admin-login',[]); 3 | 4 | app.config(['$httpProvider', function($httpProvider){ 5 | $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 6 | }]); 7 | 8 | app.controller('LoginController', ['AuthService','$scope', function(AuthService,$scope){ 9 | var login = this; 10 | 11 | login.credentials = {}; 12 | login.authenticationFailed = false; 13 | 14 | this.login = function (){ 15 | AuthService.login(login.credentials); 16 | }; 17 | 18 | this.logout = function (){ 19 | AuthService.logout(login.credentials); 20 | login.credentials={}; 21 | }; 22 | 23 | this.isAuthenticated = function(){ 24 | return AuthService.isAuthenticated(); 25 | }; 26 | 27 | this.hasAuthenticationFailed = function(){ 28 | return AuthService.hasAuthenticationFailed(); 29 | }; 30 | }]); 31 | 32 | app.factory('AuthService', ['$http', function ($http) { 33 | var auth = this; 34 | auth.wrapper = { 35 | logged:false, 36 | login:null, 37 | hasAuthenticationFailed:false 38 | }; 39 | 40 | return { 41 | login: function (credentials) { 42 | var stringView= new StringView(credentials.login + ':' + credentials.password); 43 | var encoded = stringView.toBase64(); 44 | $http.defaults.headers.common.Authorization = 'Basic ' + encoded; 45 | var success = false; 46 | $http.head('rs/users/administrators'). 47 | success(function(data){ 48 | auth.wrapper.logged = true; 49 | auth.wrapper.login = credentials.login; 50 | auth.wrapper.hasAuthenticationFailed = false; 51 | }). 52 | error(function(data){ 53 | auth.wrapper.hasAuthenticationFailed = true; 54 | }); 55 | }, 56 | isAuthenticated: function () { 57 | return auth.wrapper.logged === true; 58 | }, 59 | isNotAuthenticated: function () { 60 | return auth.wrapper.logged === false; 61 | }, 62 | hasAuthenticationFailed: function () { 63 | return auth.wrapper.hasAuthenticationFailed; 64 | }, 65 | logout: function () { 66 | auth.wrapper.logged = false; 67 | auth.wrapper.login = null; 68 | $http.defaults.headers.common.Authorization=null; 69 | } 70 | }; 71 | }]); 72 | 73 | 74 | 75 | })(); -------------------------------------------------------------------------------- /admin/src/main/webapp/app/user/reset-password-dialog.html: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 39 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/util/confirm-delete-danger.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /admin/src/main/webapp/app/util/confirm-dialog.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /admin/src/main/webapp/errors/error-401.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/plain"%> 2 | 3 | <% 4 | response.sendError(response.SC_FORBIDDEN, "forbidden"); 5 | %> 6 | -------------------------------------------------------------------------------- /admin/src/main/webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jeeshop-admin", 3 | "version": "0.9.0", 4 | "description": "Jeeshop Admin", 5 | "main": "index.html", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack && cp index.html dist/ && cp -R errors dist/ && cp -R app dist/" 9 | }, 10 | "author": "", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "angular": "1.5.6", 14 | "angular-file-upload-shim": "1.6.4", 15 | "angular-sanitize": "1.5.6", 16 | "angular-ui-bootstrap": "1.3.3", 17 | "angular-ui-router": "0.3.1", 18 | "bootstrap": "3.4.1", 19 | "jquery": "3.5.0", 20 | "webpack": "1.13.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /admin/src/main/webapp/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: { 3 | app : './app/app.js' 4 | }, 5 | output: { 6 | filename: '[name]_bundle.js', 7 | path: './dist' 8 | } 9 | }; -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/CatalogItemRelationShip.adoc: -------------------------------------------------------------------------------- 1 | ==== Get {itemType} related {relationResourcePath} 2 | 3 | [cols="h,5a"] 4 | |==== 5 | | URL 6 | | /rs/{resourcePath}/[id]/{relationResourcePath} 7 | 8 | | Method 9 | | GET 10 | 11 | | Roles allowed 12 | | All 13 | 14 | | Parameters 15 | | 16 | !==== 17 | ! Name ! Mandatory ! Description 18 | 19 | ! {itemType} item id 20 | ! Yes 21 | ! id of the {itemType} item to retrieve 22 | 23 | ! locale 24 | ! No 25 | ! For sample _en_GB_. Can be provided for _user_ role to get localized related presentation items (localized content) matching given locale 26 | !==== 27 | 28 | | Response HTTP statuses 29 | | 30 | !==== 31 | ! Code ! Meaning 32 | ! 200 33 | ! Success 34 | ! 404 35 | ! When no item found with given parameters 36 | 37 | | Response Body 38 | | include::snippets/{relationItemType}.list.json.adoc[] 39 | |==== -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/Catalogs.adoc: -------------------------------------------------------------------------------- 1 | === {resourceName} resource 2 | 3 | Manages {itemType} items and their relationships. 4 | 5 | include::CatalogItem.adoc[] 6 | 7 | :relationResourcePath: categories 8 | :relationItemType: category 9 | include::CatalogItemRelationShip.adoc[] 10 | -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/Categories.adoc: -------------------------------------------------------------------------------- 1 | === {resourceName} resource 2 | 3 | Manages {itemType} items and their relationships. 4 | 5 | include::CatalogItem.adoc[] 6 | 7 | :relationResourcePath: categories 8 | :relationItemType: category 9 | include::CatalogItemRelationShip.adoc[] 10 | 11 | :relationResourcePath: products 12 | :relationItemType: product 13 | include::CatalogItemRelationShip.adoc[] 14 | -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/Discounts.adoc: -------------------------------------------------------------------------------- 1 | === {resourceName} resource 2 | 3 | Manages {itemType} items and their relationships. 4 | 5 | include::CatalogItem.adoc[] 6 | 7 | ==== Get all eligible disounct items related to an order or an item 8 | 9 | [cols="h,5a"] 10 | |==== 11 | | URL 12 | | /rs/{resourcePath}/visible 13 | 14 | | Method 15 | | GET 16 | 17 | | Roles allowed 18 | | ALL 19 | 20 | | Parameters 21 | | 22 | !==== 23 | ! Name ! Mandatory ! Description 24 | 25 | ! applicableTo 26 | ! Yes 27 | ! Possible values are : _ORDER_, _ITEM_ 28 | 29 | ! locale 30 | ! No 31 | ! For sample _en_GB_. Can be provided to get localized related presentation item (localized content) in response 32 | 33 | !==== 34 | 35 | 36 | !==== 37 | ! Code ! Meaning 38 | ! 200 39 | ! Success 40 | 41 | | Response Body 42 | | include::snippets/{itemType}.list.json.adoc[] 43 | |==== -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/Medias.adoc: -------------------------------------------------------------------------------- 1 | === Medias resource 2 | 3 | ==== Get a specific media file 4 | 5 | [cols="h,5a"] 6 | |==== 7 | | URL 8 | | /rs/medias/[type]/[id]/[locale]/[filename] 9 | 10 | | Method 11 | | GET 12 | 13 | | Roles allowed 14 | | _admin_ 15 | 16 | | Parameters 17 | | 18 | !==== 19 | ! Name ! Mandatory ! Description 20 | 21 | ! type 22 | ! Yes 23 | ! Media related item type such as "product" or "category" 24 | 25 | ! id 26 | ! Yes 27 | ! Media related item id 28 | 29 | ! locale 30 | ! No 31 | ! For sample _en_GB_ 32 | 33 | ! filename 34 | ! No 35 | ! media file name 36 | 37 | 38 | | Response HTTP statuses 39 | | 40 | !==== 41 | ! Code ! Meaning 42 | ! 200 43 | ! Success 44 | ! 404 45 | ! No result found matching given parameters 46 | !==== 47 | |==== 48 | 49 | ==== Upload a media file 50 | 51 | [cols="h,5a"] 52 | |==== 53 | | URL 54 | | /rs/medias/[type]/[id]/[locale]/upload 55 | 56 | | Method 57 | | POST 58 | 59 | | Roles allowed 60 | | _admin_ + 61 | 62 | | Parameters 63 | | 64 | !==== 65 | ! Name ! Mandatory ! Description 66 | 67 | ! type 68 | ! Yes 69 | ! Media related item type such as "product" or "category" 70 | 71 | ! id 72 | ! Yes 73 | ! Media related item id 74 | 75 | ! locale 76 | ! No 77 | ! For sample _en_GB_ 78 | 79 | !==== 80 | 81 | | Request header 82 | | Content-Type = "multipart/form-data" 83 | 84 | | Response HTTP statuses 85 | | 86 | !==== 87 | ! Code ! Meaning 88 | ! 200 89 | ! Success 90 | ! 500 91 | ! In case of internal error during upload 92 | 93 | |==== 94 | -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/Products.adoc: -------------------------------------------------------------------------------- 1 | === {resourceName} resource 2 | 3 | Manages {itemType} items and their relationships. 4 | 5 | include::CatalogItem.adoc[] 6 | 7 | :relationResourcePath: skus 8 | :relationItemType: sku 9 | include::CatalogItemRelationShip.adoc[] 10 | 11 | :relationResourcePath: discounts 12 | :relationItemType: discount 13 | include::CatalogItemRelationShip.adoc[] -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/SKUs.adoc: -------------------------------------------------------------------------------- 1 | === {resourceName} resource 2 | 3 | Manages {itemType} items and their relationships. 4 | 5 | include::CatalogItem.adoc[] 6 | 7 | :relationResourcePath: discounts 8 | :relationItemType: discount 9 | include::CatalogItemRelationShip.adoc[] -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/rest-api.adoc: -------------------------------------------------------------------------------- 1 | == Catalog REST API 2 | 3 | include::../../../../common/src/main/asciidoc/rest-api-general.adoc[] 4 | 5 | :resourceName: Catalogs 6 | :itemType: catalog 7 | :resourcePath: catalogs 8 | include::Catalogs.adoc[] 9 | 10 | :resourceName: Categories 11 | :itemType: category 12 | :resourcePath: categories 13 | include::Categories.adoc[] 14 | 15 | :resourceName: Products 16 | :itemType: product 17 | :resourcePath: products 18 | include::Products.adoc[] 19 | 20 | :resourceName: Stock Keeping Units 21 | :itemType: sku 22 | :resourcePath: skus 23 | include::SKUs.adoc[] 24 | 25 | :resourceName: Discounts 26 | :itemType: discount 27 | :resourcePath: discounts 28 | include::Discounts.adoc[] 29 | 30 | include::Medias.adoc[] -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/catalog.in.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "name": "Hyperbike catalog", 5 | "description": "Catalog of Hyperbike store", 6 | "disabled": false, 7 | "startDate":1403067172000, 8 | "endDate":1403067172000, 9 | "rootCategoriesIds":[1,2] 10 | } 11 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/catalog.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 1, 5 | "name": "Hyperbike catalog", 6 | "description": "Catalog of Hyperbike store", 7 | "disabled": false, 8 | "startDate": null, 9 | "endDate":" null, 10 | "visible": true, 11 | "localizedPresentation": null, 12 | "rootCategoriesIds": null 13 | } 14 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/catalog.list.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | [ 4 | { 5 | "id": 1, 6 | "name": "Hyperbike catalog", 7 | "description": "Catalog of Hyperbike store", 8 | "disabled": false, 9 | "startDate": null, 10 | "endDate": null, 11 | "visible": true, 12 | "localizedPresentation": null, 13 | "rootCategoriesIds": null 14 | } 15 | { 16 | "id": 2, 17 | "name": "Other catalog", 18 | "description": "Another catalog", 19 | "disabled": true, 20 | "startDate": null, 21 | "endDate": null, 22 | "visible": true, 23 | "localizedPresentation": null, 24 | "rootCategoriesIds": null 25 | } 26 | ] 27 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/catalog.presentation.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 9, 5 | "locale": "fr_FR", 6 | "displayName": "Catalogue des vélos", 7 | "promotion": null, 8 | "shortDescription": "Description courte ...", 9 | "mediumDescription": "Description moyenne ...", 10 | "longDescription": "Description longue ...", 11 | "thumbnail": null, 12 | "smallImage": { 13 | "id": 26, 14 | "uri": "remi.png" 15 | }, 16 | "largeImage": null, 17 | "video": null, 18 | "features": {} 19 | } 20 | ---- 21 | -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/category.in.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 7, 5 | "name": "VTT", 6 | "description": "VTT rubric", 7 | "disabled": false, 8 | "startDate": null, 9 | "endDate": null, 10 | "visible": true, 11 | "localizedPresentation": null, 12 | "childCategoriesIds": null, 13 | "childProductsIds": [1,2] 14 | } 15 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/category.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 7, 5 | "name": "VTT", 6 | "description": "VTT rubric", 7 | "disabled": false, 8 | "startDate": null, 9 | "endDate": null, 10 | "visible": true, 11 | "localizedPresentation": null, 12 | "childCategoriesIds": null, 13 | "childProductsIds": null 14 | } 15 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/category.list.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | [ 4 | { 5 | "id": 1, 6 | "name": "Bikes", 7 | "description": "Bikes main category", 8 | "disabled": false, 9 | "startDate": null, 10 | "endDate": null, 11 | "visible": true, 12 | "localizedPresentation": null, 13 | "childCategoriesIds": null, 14 | "childProductsIds": null 15 | }, 16 | { 17 | "id": 2, 18 | "name": "Accessories", 19 | "description": "Accessories main category", 20 | "disabled": false, 21 | "startDate": null, 22 | "endDate": null, 23 | "visible": true, 24 | "localizedPresentation": null, 25 | "childCategoriesIds": null, 26 | "childProductsIds": null 27 | } 28 | ] 29 | ---- 30 | -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/category.presentation.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 10, 5 | "locale": "fr_FR", 6 | "displayName": "VTT", 7 | "promotion": null, 8 | "shortDescription": "Retrouvez nos meilleurs VTT", 9 | "mediumDescription": null, 10 | "longDescription": null, 11 | "thumbnail": null, 12 | "smallImage": { 13 | "id": 56, 14 | "uri": "vtt_category_small.jpg" 15 | }, 16 | "largeImage": { 17 | "id": 56, 18 | "uri": "vtt_category_large.jpg" 19 | }, 20 | "video": null, 21 | "features": {} 22 | } 23 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/discount.in.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 4, 5 | "name": "First order - 10 percent", 6 | "description": "10 percent off for user first order", 7 | "disabled": false, 8 | "startDate": null, 9 | "endDate": null, 10 | "visible": true, 11 | "localizedPresentation": null, 12 | "voucherCode": null, 13 | "usesPerCustomer": 1, 14 | "type": "DISCOUNT_RATE", 15 | "triggerRule": "ORDER_NUMBER", 16 | "applicableTo": "ORDER", 17 | "triggerValue": 1.0, 18 | "discountValue": 20.0, 19 | "rateType": true, 20 | "uniqueUse": true 21 | } 22 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/discount.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 4, 5 | "name": "First order - 10 percent", 6 | "description": "10 percent off for user first order", 7 | "disabled": false, 8 | "startDate": null, 9 | "endDate": null, 10 | "visible": true, 11 | "localizedPresentation": null, 12 | "voucherCode": null, 13 | "usesPerCustomer": 1, 14 | "type": "DISCOUNT_RATE", 15 | "triggerRule": "ORDER_NUMBER", 16 | "applicableTo": "ORDER", 17 | "triggerValue": 1.0, 18 | "discountValue": 20.0, 19 | "rateType": true, 20 | "uniqueUse": true 21 | } 22 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/discount.list.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | [ 4 | { 5 | "id": 4, 6 | "name": "First order - 10 percent", 7 | "description": "10 percent off for user first order", 8 | "disabled": false, 9 | "startDate": null, 10 | "endDate": null, 11 | "visible": true, 12 | "localizedPresentation": null, 13 | "voucherCode": null, 14 | "usesPerCustomer": 1, 15 | "type": "DISCOUNT_RATE", 16 | "triggerRule": "ORDER_NUMBER", 17 | "applicableTo": "ORDER", 18 | "triggerValue": 1.0, 19 | "discountValue": 20.0, 20 | "rateType": true, 21 | "uniqueUse": true 22 | }, 23 | { 24 | "id": 5, 25 | "name": "Christmas 2015 - Free delivery fee", 26 | "description": "Free delivery fee for christmas", 27 | "disabled": false, 28 | "startDate": 1418598000000, 29 | "endDate": 1419980400000, 30 | "visible": false, 31 | "localizedPresentation": null, 32 | "voucherCode": null, 33 | "usesPerCustomer": 1, 34 | "type": "SHIPPING_FEE_DISCOUNT_AMOUNT", 35 | "triggerRule": null, 36 | "applicableTo": "ORDER", 37 | "triggerValue": null, 38 | "discountValue": 12.0, 39 | "rateType": false, 40 | "uniqueUse": false 41 | } 42 | ] 43 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/discount.presentation.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 33, 5 | "locale": "en_US", 6 | "displayName": "Free delivery fee for christmas !", 7 | "promotion": null, 8 | "shortDescription": "Delivery fee is free for all orders for Christmas.", 9 | "mediumDescription": "", 10 | "longDescription": "", 11 | "thumbnail": null, 12 | "smallImage": { 13 | "id": 26, 14 | "uri": "free_delivery_fee.jpg" 15 | }, 16 | "largeImage": null, 17 | "video": null, 18 | "features": {} 19 | } 20 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/product.in.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 2, 5 | "name": "Energy X2", 6 | "description": "VTT Energy X2", 7 | "disabled": false, 8 | "startDate": 1403067172000, 9 | "endDate": 1402980772000, 10 | "visible": false, 11 | "localizedPresentation": null, 12 | "childSKUsIds": [3], 13 | "discountsIds": null 14 | } 15 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/product.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 2, 5 | "name": "Energy X2", 6 | "description": "VTT Energy X2", 7 | "disabled": false, 8 | "startDate": 1403067172000, 9 | "endDate": 1402980772000, 10 | "visible": false, 11 | "localizedPresentation": null, 12 | "childSKUsIds": null, 13 | "discountsIds": null 14 | } 15 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/product.list.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | [ 4 | { 5 | "id": 1, 6 | "name": "Energy X1", 7 | "description": "VTT energy X1", 8 | "disabled": false, 9 | "startDate": null, 10 | "endDate": null, 11 | "visible": true, 12 | "localizedPresentation": null, 13 | "childSKUsIds": null, 14 | "discountsIds": null 15 | }, 16 | { 17 | "id": 2, 18 | "name": "Energy X2", 19 | "description": "VTT Energy X2", 20 | "disabled": false, 21 | "startDate": 1403067172000, 22 | "endDate": 1402980772000, 23 | "visible": false, 24 | "localizedPresentation": null, 25 | "childSKUsIds": null, 26 | "discountsIds": null 27 | } 28 | ] 29 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/product.presentation.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 7, 5 | "locale": "en_US", 6 | "displayName": "Energy 2 mountain bike", 7 | "promotion": null, 8 | "shortDescription": "The new Energy mountain bike produced by Bikester", 9 | "mediumDescription": null, 10 | "longDescription": "This new mountain bike gives you amazing sensations on city streets, or mountain trails.", 11 | "thumbnail": { 12 | "id": 24, 13 | "uri": "vtt_thumbnail.jpg" 14 | }, 15 | "smallImage": { 16 | "id": 23, 17 | "uri": "vtt_small.jpg" 18 | }, 19 | "largeImage": { 20 | "id": 22, 21 | "uri": "vtt_large.jpg" 22 | }, 23 | "video": null, 24 | "features": {} 25 | } 26 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/sku.in.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 1, 5 | "name": "Energy X1 batch of 10", 6 | "description": "Energy X1 batch of 10", 7 | "disabled": false, 8 | "startDate": 1403067172000, 9 | "endDate": 1412139172000, 10 | "visible": false, 11 | "localizedPresentation": null, 12 | "price": 10.0, 13 | "currency": "EUR", 14 | "reference": "X1213JJLB-1", 15 | "threshold": 3, 16 | "quantity": 100, 17 | "discountsIds": null, 18 | "available": true 19 | } 20 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/sku.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 1, 5 | "name": "Energy X1 batch of 10", 6 | "description": "Energy X1 batch of 10", 7 | "disabled": false, 8 | "startDate": 1403067172000, 9 | "endDate": 1412139172000, 10 | "visible": false, 11 | "localizedPresentation": null, 12 | "price": 10.0, 13 | "currency": "EUR", 14 | "reference": "X1213JJLB-1", 15 | "threshold": 3, 16 | "quantity": 100, 17 | "discountsIds": null, 18 | "available": true 19 | } 20 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/sku.list.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | [ 4 | { 5 | "id": 1, 6 | "name": "Energy X1 batch of 10", 7 | "description": "Energy X1 batch of 10", 8 | "disabled": false, 9 | "startDate": 1403067172000, 10 | "endDate": 1412139172000, 11 | "visible": false, 12 | "localizedPresentation": null, 13 | "price": 10.0, 14 | "currency": "EUR", 15 | "reference": "X1213JJLB-1", 16 | "threshold": 3, 17 | "quantity": 100, 18 | "discountsIds": null, 19 | "available": true 20 | }, 21 | { 22 | "id": 2, 23 | "name": "Energy X1 batch of 50", 24 | "description": "Energy X1 batch of 50", 25 | "disabled": true, 26 | "startDate": 1412225572000, 27 | "endDate": 1420091572000, 28 | "visible": false, 29 | "localizedPresentation": null, 30 | "price": 10.0, 31 | "currency": null, 32 | "reference": "X1213JJLB-2", 33 | "threshold": 3, 34 | "quantity": 100, 35 | "discountsIds": null, 36 | "available": true 37 | } 38 | ] 39 | ---- -------------------------------------------------------------------------------- /catalog/src/main/asciidoc/snippets/sku.presentation.json.adoc: -------------------------------------------------------------------------------- 1 | [source,javascript] 2 | ---- 3 | { 4 | "id": 9, 5 | "locale": "fr_FR", 6 | "displayName": "Unité de stock", 7 | "promotion": null, 8 | "shortDescription": "Description courte ...", 9 | "mediumDescription": "Description moyenne ...", 10 | "longDescription": "Description longue ...", 11 | "thumbnail": null, 12 | "smallImage": { 13 | "id": 26, 14 | "uri": "hello.png" 15 | }, 16 | "largeImage": null, 17 | "video": null, 18 | "features": {} 19 | } 20 | ---- -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/CatalogItemService.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog; 2 | 3 | import org.rembx.jeeshop.catalog.model.CatalogItem; 4 | import org.rembx.jeeshop.rest.WebApplicationException; 5 | 6 | import javax.validation.constraints.NotNull; 7 | import javax.ws.rs.core.Response; 8 | import javax.ws.rs.core.SecurityContext; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | import static org.rembx.jeeshop.role.JeeshopRoles.ADMIN; 13 | import static org.rembx.jeeshop.role.JeeshopRoles.STORE_ADMIN; 14 | 15 | public interface CatalogItemService { 16 | 17 | List findAll(String search, Integer start, Integer size, String orderBy, Boolean isDesc, String locale); 18 | 19 | T find(SecurityContext securityContext, @NotNull Long productId, String locale); 20 | 21 | T create(SecurityContext securityContext, T item); 22 | 23 | T modify(SecurityContext securityContext, T item); 24 | 25 | void delete(SecurityContext securityContext, Long itemId); 26 | 27 | Set findPresentationsLocales(SecurityContext securityContext, @NotNull Long catalogId); 28 | 29 | PresentationResource findPresentationByLocale(@NotNull Long productId, @NotNull String locale); 30 | 31 | default void attachOwner(SecurityContext securityContext, CatalogItem catalogItem) { 32 | if (securityContext.isUserInRole(ADMIN) && catalogItem.getOwner() == null) { 33 | throw new WebApplicationException(Response.Status.BAD_REQUEST); 34 | 35 | } else if (securityContext.isUserInRole(STORE_ADMIN) && catalogItem.getOwner() == null) { 36 | catalogItem.setOwner(securityContext.getUserPrincipal().getName()); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/DiscountFinder.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import io.quarkus.hibernate.orm.PersistenceUnit; 5 | import org.rembx.jeeshop.catalog.model.CatalogPersistenceUnit; 6 | import org.rembx.jeeshop.catalog.model.Discount; 7 | import org.rembx.jeeshop.catalog.model.Discount.ApplicableTo; 8 | 9 | import javax.enterprise.context.ApplicationScoped; 10 | import javax.persistence.EntityManager; 11 | import java.util.Date; 12 | import java.util.List; 13 | 14 | import static org.rembx.jeeshop.catalog.model.QDiscount.discount; 15 | 16 | @ApplicationScoped 17 | public class DiscountFinder { 18 | 19 | private final EntityManager entityManager; 20 | 21 | DiscountFinder(@PersistenceUnit(CatalogPersistenceUnit.NAME) EntityManager entityManager) { 22 | this.entityManager = entityManager; 23 | } 24 | 25 | /* 26 | * Returns all discounts visible to end user 27 | * @param applicableTo the applicable type of discount 28 | * @param locale the locale for results localization 29 | * @return the visible discounts: not disabled, with startDate and endDate respectively before and after now and without 30 | * voucher code 31 | */ 32 | public List findVisibleDiscounts(ApplicableTo applicableTo, String locale) { 33 | Date now = new Date(); 34 | List results = new JPAQueryFactory(entityManager) 35 | .selectFrom(discount).where( 36 | discount.disabled.isFalse(), 37 | discount.endDate.after(now).or(discount.endDate.isNull()), 38 | discount.startDate.before(now).or(discount.startDate.isNull()), 39 | discount.applicableTo.eq(applicableTo), 40 | discount.voucherCode.isNull() 41 | ).fetch(); 42 | 43 | results.forEach((discount) -> discount.setLocalizedPresentation(locale)); 44 | 45 | return results; 46 | 47 | } 48 | 49 | 50 | /* 51 | * Returns all discounts eligible for end-user 52 | * @param applicableTo the applicable type of discount 53 | * @param locale the locale for results localization 54 | * @return the visible discounts: not disabled, with startDate and endDate respectively before and after now and without 55 | * voucher code, applicable to given number of orders 56 | */ 57 | public List findEligibleOrderDiscounts(String locale, Long completedOrderNumbers) { 58 | Date now = new Date(); 59 | List results = new JPAQueryFactory(entityManager) 60 | .selectFrom(discount).where( 61 | discount.disabled.isFalse(), 62 | discount.endDate.after(now).or(discount.endDate.isNull()), 63 | discount.startDate.before(now).or(discount.startDate.isNull()), 64 | discount.applicableTo.eq(ApplicableTo.ORDER), 65 | discount.triggerRule.ne(Discount.Trigger.ORDER_NUMBER).or( 66 | discount.triggerValue.eq(completedOrderNumbers.doubleValue() + 1) 67 | ), 68 | discount.voucherCode.isNull() 69 | ) 70 | .fetch(); 71 | 72 | results.forEach((discount) -> discount.setLocalizedPresentation(locale)); 73 | 74 | return results; 75 | 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/OwnerUtils.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog; 2 | 3 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/Catalog.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.persistence.*; 4 | import javax.xml.bind.annotation.XmlAccessType; 5 | import javax.xml.bind.annotation.XmlAccessorType; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by remi on 20/05/14. 11 | */ 12 | @Entity 13 | @XmlRootElement 14 | @XmlAccessorType(XmlAccessType.FIELD) 15 | @Cacheable 16 | public class Catalog extends CatalogItem { 17 | 18 | @ManyToMany(cascade = {CascadeType.PERSIST}) 19 | @JoinTable(joinColumns = @JoinColumn(name = "catalogId"), 20 | inverseJoinColumns = @JoinColumn(name = "categoryId")) 21 | @OrderColumn(name="orderIdx") 22 | private List rootCategories; 23 | 24 | @Transient 25 | private List rootCategoriesIds; 26 | 27 | public Catalog() { 28 | } 29 | 30 | public Catalog(String name) { 31 | this.name = name; 32 | } 33 | 34 | public Catalog(Long id, String name) { 35 | this.id = id; 36 | this.name = name; 37 | } 38 | 39 | public List getRootCategories() { 40 | return rootCategories; 41 | } 42 | 43 | public void setRootCategories(List rootCategories) { 44 | this.rootCategories = rootCategories; 45 | } 46 | 47 | public List getRootCategoriesIds() { 48 | return rootCategoriesIds; 49 | } 50 | 51 | public void setRootCategoriesIds(List rootCategoriesIds) { 52 | this.rootCategoriesIds = rootCategoriesIds; 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) return true; 58 | if (o == null || getClass() != o.getClass()) return false; 59 | if (!super.equals(o)) return false; 60 | 61 | Catalog catalog = (Catalog) o; 62 | 63 | if (rootCategories != null ? !rootCategories.equals(catalog.rootCategories) : catalog.rootCategories != null) 64 | return false; 65 | 66 | return true; 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | int result = super.hashCode(); 72 | result = 31 * result + (rootCategories != null ? rootCategories.hashCode() : 0); 73 | return result; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/CatalogPersistenceUnit.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | /** 4 | * Created by remi on 25/05/14. 5 | */ 6 | public interface CatalogPersistenceUnit { 7 | public final static String NAME = "Catalog"; 8 | } 9 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/Category.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.json.bind.annotation.JsonbTransient; 4 | import javax.persistence.*; 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlType; 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by remi on 20/05/14. 13 | */ 14 | @Entity 15 | @XmlType 16 | @XmlAccessorType(XmlAccessType.FIELD) 17 | @Cacheable 18 | public class Category extends CatalogItem { 19 | 20 | @ManyToMany(cascade = {CascadeType.PERSIST}) 21 | @JoinTable(joinColumns = @JoinColumn(name = "parentCategoryId"), 22 | inverseJoinColumns = @JoinColumn(name = "childCategoryId")) 23 | @OrderColumn(name = "orderIdx") 24 | private List childCategories; 25 | 26 | @Transient 27 | private List childCategoriesIds; 28 | 29 | @ManyToMany(cascade = {CascadeType.PERSIST}) 30 | @JoinTable(joinColumns = @JoinColumn(name = "categoryId"), 31 | inverseJoinColumns = @JoinColumn(name = "productId")) 32 | @OrderColumn(name = "orderIdx") 33 | @JsonbTransient 34 | private List childProducts; 35 | 36 | @Transient 37 | private List childProductsIds; 38 | 39 | public Category() { 40 | } 41 | 42 | public Category(Long id, String name) { 43 | this.id = id; 44 | this.name = name; 45 | } 46 | 47 | public Category(String name, String description) { 48 | this.name = name; 49 | this.description = description; 50 | } 51 | 52 | public Category(Long id, String name, String description, Date startDate, Date endDate, Boolean disabled) { 53 | this.id = id; 54 | this.name = name; 55 | this.description = description; 56 | this.startDate = startDate; 57 | this.endDate = endDate; 58 | this.disabled = disabled; 59 | } 60 | 61 | public Category(String name, String description, Date startDate, Date endDate, Boolean disabled, String owner) { 62 | this.name = name; 63 | this.description = description; 64 | this.startDate = startDate; 65 | this.endDate = endDate; 66 | this.disabled = disabled; 67 | this.owner = owner; 68 | } 69 | 70 | public List getChildCategories() { 71 | return childCategories; 72 | } 73 | 74 | public void setChildCategories(List childCategories) { 75 | this.childCategories = childCategories; 76 | } 77 | 78 | public List getChildProducts() { 79 | return childProducts; 80 | } 81 | 82 | public void setChildProducts(List childProducts) { 83 | this.childProducts = childProducts; 84 | } 85 | 86 | public List getChildCategoriesIds() { 87 | return childCategoriesIds; 88 | } 89 | 90 | public void setChildCategoriesIds(List childCategoriesIds) { 91 | this.childCategoriesIds = childCategoriesIds; 92 | } 93 | 94 | public List getChildProductsIds() { 95 | return childProductsIds; 96 | } 97 | 98 | public void setChildProductsIds(List childProductsIds) { 99 | this.childProductsIds = childProductsIds; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/Premises.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.persistence.*; 4 | import javax.xml.bind.annotation.XmlAccessType; 5 | import javax.xml.bind.annotation.XmlAccessorType; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | import java.util.List; 8 | 9 | @Entity 10 | @XmlRootElement 11 | @XmlAccessorType(XmlAccessType.FIELD) 12 | @Cacheable 13 | public class Premises { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | Long id; 18 | 19 | @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 20 | PremisesAddress address; 21 | 22 | @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 23 | List schedules; 24 | 25 | public Premises() { 26 | } 27 | 28 | public Premises(Long id) { 29 | this.id = id; 30 | } 31 | 32 | public Premises(Long id, PremisesAddress address, List schedules) { 33 | this.id = id; 34 | this.address = address; 35 | this.schedules = schedules; 36 | } 37 | 38 | public Long getId() { 39 | return id; 40 | } 41 | 42 | public void setId(Long id) { 43 | this.id = id; 44 | } 45 | 46 | public PremisesAddress getAddress() { 47 | return address; 48 | } 49 | 50 | public void setAddress(PremisesAddress address) { 51 | this.address = address; 52 | } 53 | 54 | public List getSchedules() { 55 | return schedules; 56 | } 57 | 58 | public void setSchedules(List schedules) { 59 | this.schedules = schedules; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/PremisesAddress.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.persistence.*; 4 | import javax.validation.constraints.NotNull; 5 | import javax.validation.constraints.Size; 6 | import javax.xml.bind.annotation.XmlAccessType; 7 | import javax.xml.bind.annotation.XmlAccessorType; 8 | import javax.xml.bind.annotation.XmlType; 9 | import java.util.Objects; 10 | 11 | @Entity 12 | @XmlType 13 | @Table(name = "premises_address") 14 | @XmlAccessorType(XmlAccessType.FIELD) 15 | public class PremisesAddress { 16 | 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Long id; 20 | 21 | @Size(max = 255) 22 | @NotNull 23 | @Column(nullable = false, length = 255) 24 | private String street; 25 | @Column(nullable = false, length = 255) 26 | @Size(max = 255) 27 | @NotNull 28 | private String city; 29 | @Column(nullable = false, length = 10) 30 | @Size(min = 1, max = 10) 31 | @NotNull 32 | private String zipCode; 33 | 34 | @NotNull 35 | @Size(min = 3, max = 3) 36 | @Column(nullable = false, length = 3) 37 | private String countryIso3Code; 38 | 39 | public PremisesAddress() { 40 | } 41 | 42 | public PremisesAddress(String street, String city, String zipCode, String countryIso3Code) { 43 | this.street = street; 44 | this.city = city; 45 | this.zipCode = zipCode; 46 | this.countryIso3Code = countryIso3Code; 47 | } 48 | 49 | public Long getId() { 50 | return id; 51 | } 52 | 53 | 54 | public String getStreet() { 55 | return street; 56 | } 57 | 58 | public void setStreet(String street) { 59 | this.street = street; 60 | } 61 | 62 | public String getCity() { 63 | return city; 64 | } 65 | 66 | public void setCity(String city) { 67 | this.city = city; 68 | } 69 | 70 | public String getZipCode() { 71 | return zipCode; 72 | } 73 | 74 | public void setZipCode(String zipCode) { 75 | this.zipCode = zipCode; 76 | } 77 | 78 | public String getCountryIso3Code() { 79 | return countryIso3Code; 80 | } 81 | 82 | public void setCountryIso3Code(String countryIso3Code) { 83 | this.countryIso3Code = countryIso3Code; 84 | } 85 | 86 | public void setId(Long id) { 87 | this.id = id; 88 | } 89 | 90 | @Override 91 | public boolean equals(Object o) { 92 | if (this == o) return true; 93 | if (o == null || getClass() != o.getClass()) return false; 94 | PremisesAddress that = (PremisesAddress) o; 95 | return Objects.equals(id, that.id) && Objects.equals(street, that.street) && Objects.equals(city, that.city) && Objects.equals(zipCode, that.zipCode) && Objects.equals(countryIso3Code, that.countryIso3Code); 96 | } 97 | 98 | @Override 99 | public int hashCode() { 100 | return Objects.hash(id, street, city, zipCode, countryIso3Code); 101 | } 102 | 103 | @Override 104 | public String toString() { 105 | return "PremisesAddress{" + 106 | "id=" + id + 107 | ", street='" + street + '\'' + 108 | ", city='" + city + '\'' + 109 | ", zipCode='" + zipCode + '\'' + 110 | ", countryIso3Code='" + countryIso3Code + '\'' + 111 | '}'; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/PremisesOpeningSchedules.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.persistence.*; 4 | import javax.validation.constraints.NotNull; 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlType; 8 | import java.time.DayOfWeek; 9 | import java.time.LocalTime; 10 | 11 | @Entity 12 | @XmlType 13 | @XmlAccessorType(XmlAccessType.FIELD) 14 | @Cacheable 15 | public class PremisesOpeningSchedules { 16 | 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | protected Long id; 20 | 21 | @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY) 22 | private Store store; 23 | 24 | @Enumerated(EnumType.ORDINAL) 25 | @NotNull 26 | @Column(nullable = false) 27 | DayOfWeek dayOfWeek; 28 | 29 | @Column 30 | LocalTime timeOpen; 31 | 32 | @Column 33 | LocalTime timeClose; 34 | 35 | public PremisesOpeningSchedules() { 36 | } 37 | 38 | public PremisesOpeningSchedules(Long id) { 39 | this.id = id; 40 | } 41 | 42 | public PremisesOpeningSchedules(Store store, DayOfWeek dayOfWeek, LocalTime timeOpen, LocalTime timeClose) { 43 | this.store = store; 44 | this.dayOfWeek = dayOfWeek; 45 | this.timeOpen = timeOpen; 46 | this.timeClose = timeClose; 47 | } 48 | 49 | public Store getStore() { 50 | return store; 51 | } 52 | 53 | public void setStore(Store store) { 54 | this.store = store; 55 | } 56 | 57 | public DayOfWeek getDayOfWeek() { 58 | return dayOfWeek; 59 | } 60 | 61 | public void setDayOfWeek(DayOfWeek dayOfWeek) { 62 | this.dayOfWeek = dayOfWeek; 63 | } 64 | 65 | public LocalTime getTimeOpen() { 66 | return timeOpen; 67 | } 68 | 69 | public void setTimeOpen(LocalTime timeOpen) { 70 | this.timeOpen = timeOpen; 71 | } 72 | 73 | public LocalTime getTimeClose() { 74 | return timeClose; 75 | } 76 | 77 | public void setTimeClose(LocalTime timeClose) { 78 | this.timeClose = timeClose; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/Product.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.persistence.*; 4 | import javax.xml.bind.annotation.XmlAccessType; 5 | import javax.xml.bind.annotation.XmlAccessorType; 6 | import javax.xml.bind.annotation.XmlType; 7 | import java.util.Date; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by remi on 20/05/14. 12 | */ 13 | @Entity 14 | @XmlType 15 | @XmlAccessorType(XmlAccessType.FIELD) 16 | @Cacheable 17 | public class Product extends CatalogItem { 18 | @ManyToMany(cascade = {CascadeType.PERSIST}) 19 | @JoinTable(joinColumns = @JoinColumn(name = "productId"), 20 | inverseJoinColumns = @JoinColumn(name = "skuId")) 21 | @OrderColumn(name = "orderIdx") 22 | private List childSKUs; 23 | 24 | @Transient 25 | private List childSKUsIds; 26 | 27 | @ManyToMany(cascade = {CascadeType.PERSIST}) 28 | @JoinTable(joinColumns = @JoinColumn(name = "productId"), 29 | inverseJoinColumns = @JoinColumn(name = "discountId")) 30 | @OrderColumn(name = "orderIdx") 31 | private List discounts; 32 | 33 | @Transient 34 | private List discountsIds; 35 | 36 | public Product() { 37 | } 38 | 39 | public Product(Long id, String name) { 40 | this.id = id; 41 | this.name = name; 42 | } 43 | 44 | 45 | public Product(String name) { 46 | this.name = name; 47 | } 48 | 49 | public Product(String name, String description, Date startDate, Date endDate, Boolean disabled, String owner) { 50 | this.name = name; 51 | this.description = description; 52 | this.startDate = startDate; 53 | this.endDate = endDate; 54 | this.disabled = disabled; 55 | this.owner = owner; 56 | } 57 | 58 | 59 | public Product(Long id, String name, String description, Date startDate, Date endDate, Boolean disabled) { 60 | this.id = id; 61 | this.name = name; 62 | this.description = description; 63 | this.startDate = startDate; 64 | this.endDate = endDate; 65 | this.disabled = disabled; 66 | } 67 | 68 | public List getChildSKUs() { 69 | return childSKUs; 70 | } 71 | 72 | public void setChildSKUs(List childSKUs) { 73 | this.childSKUs = childSKUs; 74 | } 75 | 76 | public List getDiscounts() { 77 | return discounts; 78 | } 79 | 80 | public void setDiscounts(List discounts) { 81 | this.discounts = discounts; 82 | } 83 | 84 | 85 | public List getChildSKUsIds() { 86 | return childSKUsIds; 87 | } 88 | 89 | public void setChildSKUsIds(List childSKUsIds) { 90 | this.childSKUsIds = childSKUsIds; 91 | } 92 | 93 | public List getDiscountsIds() { 94 | return discountsIds; 95 | } 96 | 97 | public void setDiscountsIds(List discountsIds) { 98 | this.discountsIds = discountsIds; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /catalog/src/main/java/org/rembx/jeeshop/catalog/model/Store.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import javax.persistence.*; 4 | import javax.xml.bind.annotation.XmlAccessType; 5 | import javax.xml.bind.annotation.XmlAccessorType; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | import java.util.List; 8 | import java.util.Objects; 9 | 10 | @Entity 11 | @XmlRootElement 12 | @XmlAccessorType(XmlAccessType.FIELD) 13 | @Cacheable 14 | public class Store extends CatalogItem { 15 | 16 | @ManyToMany(cascade = {CascadeType.PERSIST}) 17 | @JoinTable(joinColumns = @JoinColumn(name = "storeId"), 18 | inverseJoinColumns = @JoinColumn(name = "catalogId")) 19 | @OrderColumn(name="orderIdx") 20 | List catalogs; 21 | 22 | @Transient 23 | List catalogsIds; 24 | 25 | @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 26 | List premisses; 27 | 28 | public Store() { 29 | } 30 | 31 | public Store(String name) { 32 | this.name = name; 33 | } 34 | 35 | public Store(Long id, String name) { 36 | this.id = id; 37 | this.name = name; 38 | } 39 | 40 | public List getCatalogs() { 41 | return catalogs; 42 | } 43 | 44 | public void setCatalogs(List catalogs) { 45 | this.catalogs = catalogs; 46 | } 47 | 48 | public List getPremisses() { 49 | return premisses; 50 | } 51 | 52 | public void setPremisses(List premisses) { 53 | this.premisses = premisses; 54 | } 55 | 56 | public List getCatalogsIds() { 57 | return catalogsIds; 58 | } 59 | 60 | public void setCatalogsIds(List catalogsIds) { 61 | this.catalogsIds = catalogsIds; 62 | } 63 | 64 | @Override 65 | public boolean equals(Object o) { 66 | if (this == o) return true; 67 | if (o == null || getClass() != o.getClass()) return false; 68 | if (!super.equals(o)) return false; 69 | Store store = (Store) o; 70 | return Objects.equals(premisses, store.premisses); 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return Objects.hash(super.hashCode(), premisses); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /catalog/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /catalog/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /catalog/src/test/java/org/rembx/jeeshop/catalog/CatalogItemFinderTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import org.rembx.jeeshop.catalog.model.Catalog; 6 | import org.rembx.jeeshop.catalog.model.CatalogItem; 7 | import org.rembx.jeeshop.rest.WebApplicationException; 8 | 9 | import javax.ws.rs.core.Response; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static org.assertj.core.api.Assertions.fail; 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | 15 | public class CatalogItemFinderTest { 16 | 17 | private CatalogItemFinder instance; 18 | 19 | CatalogItem visibleCatalogItem = new CatalogItem() { 20 | @Override 21 | public boolean isVisible() { 22 | return true; 23 | } 24 | }; 25 | 26 | 27 | @BeforeEach 28 | public void setup() { 29 | instance = new CatalogItemFinder(null); 30 | } 31 | 32 | 33 | @Test 34 | public void find_VisibleCatalogItem_ShouldReturnExpectedProduct() { 35 | assertThat(instance.filterVisible(visibleCatalogItem, null)).isEqualTo(visibleCatalogItem); 36 | } 37 | 38 | @Test 39 | public void find_NotVisibleCatalogItem_ShouldThrowForbiddenException() { 40 | try { 41 | instance.filterVisible(new Catalog(), null); 42 | fail("should have thrown ex"); 43 | } catch (WebApplicationException e) { 44 | assertEquals(Response.Status.FORBIDDEN, e.getResponse().getStatusInfo()); 45 | } 46 | } 47 | 48 | @Test 49 | public void find_NullCatalogItem_ShouldThrowNotFoundException() { 50 | try { 51 | instance.filterVisible(null, null); 52 | fail("should have thrown ex"); 53 | } catch (WebApplicationException e) { 54 | assertEquals(Response.Status.NOT_FOUND, e.getResponse().getStatusInfo()); 55 | } 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /catalog/src/test/java/org/rembx/jeeshop/catalog/model/DiscountTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.model; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | import static org.rembx.jeeshop.catalog.model.Discount.ApplicableTo.ORDER; 7 | import static org.rembx.jeeshop.catalog.model.Discount.Trigger.AMOUNT; 8 | import static org.rembx.jeeshop.catalog.model.Discount.Type.DISCOUNT_RATE; 9 | import static org.rembx.jeeshop.catalog.model.Discount.Type.ORDER_DISCOUNT_AMOUNT; 10 | import static org.rembx.jeeshop.catalog.model.Discount.Type.SHIPPING_FEE_DISCOUNT_AMOUNT; 11 | 12 | public class DiscountTest { 13 | 14 | @Test 15 | public void processAmountDiscountWithRate() throws Exception { 16 | Discount discount = new Discount("discount1", "a discount", ORDER, DISCOUNT_RATE, AMOUNT, null,10.0, 2.0, 1, true,null,null, false, "test@test.com"); 17 | assertThat(discount.processDiscount(10.0,10.0)).isEqualTo(9); 18 | } 19 | 20 | @Test 21 | public void processAmountDiscountWithRate_andCurrentPriceDifferentFromOriginalPrice() throws Exception { 22 | Discount discount = new Discount("discount1", "a discount", ORDER, DISCOUNT_RATE, AMOUNT, null,10.0, 2.0, 1, true,null,null, false, "test@test.com"); 23 | assertThat(discount.processDiscount(10.0,20.0)).isEqualTo(8); 24 | } 25 | 26 | @Test 27 | public void processAmountDiscountWithDiscountValue() throws Exception { 28 | Discount discount = new Discount("discount1", "a discount", ORDER, ORDER_DISCOUNT_AMOUNT, AMOUNT, null,5.0, 2.0, 1, true,null,null, false, "test@test.com"); 29 | assertThat(discount.processDiscount(10.0,10.0)).isEqualTo(5); 30 | } 31 | 32 | @Test 33 | public void processShippingDiscount() throws Exception { 34 | Discount discount = new Discount("discount1", "a discount", ORDER, SHIPPING_FEE_DISCOUNT_AMOUNT, AMOUNT, null,5.0, 2.0, 1, true,null,null, false, "test@test.com"); 35 | assertThat(discount.processDiscount(10.0,10.0)).isEqualTo(5); 36 | } 37 | 38 | @Test 39 | public void isEligible_givenItemsPriceLowerThanTriggerValueAndAmountTrigger_shouldReturnFalse_() throws Exception{ 40 | Discount discount = new Discount("discount1", "a discount", ORDER, DISCOUNT_RATE, AMOUNT, null, 0.1, 2.0, 1, true,null,null, false, "test@test.com"); 41 | assertThat(discount.isEligible(1.9)).isFalse(); 42 | } 43 | 44 | @Test 45 | public void isEligible_givenItemsPriceGreaterOrEqualThanTriggerValueAndAmountTrigger_shouldReturnTrue_() throws Exception{ 46 | Discount discount = new Discount("discount1", "a discount", ORDER, DISCOUNT_RATE, AMOUNT, null, 0.1, 2.0, 1, true,null,null, false, "test@test.com"); 47 | assertThat(discount.isEligible(2.0)).isTrue(); 48 | } 49 | 50 | @Test 51 | public void isEligible_WhenDiscountHasNullTriggerValue_shouldReturnTrue_() throws Exception{ 52 | Discount discount = new Discount("discount1", "a discount", ORDER, DISCOUNT_RATE, AMOUNT, null, 0.1, null, 1, true,null,null, false, "test@test.com"); 53 | assertThat(discount.isEligible(2.0)).isTrue(); 54 | } 55 | } -------------------------------------------------------------------------------- /catalog/src/test/java/org/rembx/jeeshop/catalog/test/Assertions.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.test; 2 | 3 | import org.rembx.jeeshop.catalog.model.*; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by remi on 25/05/14. 9 | */ 10 | public class Assertions extends org.assertj.core.api.Assertions{ 11 | 12 | public static TestCatalog.CatalogItemAssert assertThat(CatalogItem catalogItem) { 13 | return new TestCatalog.CatalogItemAssert(catalogItem); 14 | } 15 | 16 | public static TestCatalog.CategoriesAssert assertThatCategoriesOf(List categories) { 17 | return new TestCatalog.CategoriesAssert(categories); 18 | } 19 | 20 | public static TestCatalog.ProductsAssert assertThatProductsOf(List products) { 21 | return new TestCatalog.ProductsAssert(products); 22 | } 23 | 24 | public static TestCatalog.SKUsAssert assertThatSKUsOf(List skus) { 25 | return new TestCatalog.SKUsAssert(skus); 26 | } 27 | 28 | 29 | public static TestCatalog.SKUDiscountsAssert assertThatDiscountsOf(List discounts) { 30 | return new TestCatalog.SKUDiscountsAssert(discounts); 31 | } 32 | 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /catalog/src/test/java/org/rembx/jeeshop/catalog/test/PresentationTexts.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.catalog.test; 2 | 3 | /** 4 | * Created by remi on 28/05/14. 5 | */ 6 | public class PresentationTexts { 7 | public final static String TEXT_1000 = "orem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies convallis lacinia. Nunc fringilla, odio ac volutpat lobortis, ligula nisi suscipit eros, quis porttitor neque mi id purus. Proin vitae nibh semper, fermentum sapien et, interdum urna. Morbi dictum dignissim est, vitae hendrerit dolor adipiscing sed. Phasellus ac est mi. Aenean adipiscing turpis rutrum elit ultricies, eget scelerisque nisl scelerisque. Cras quis urna vulputate est interdum congue. Pellentesque vel sollicitudin mi, sed fringilla odio. Duis quis volutpat orci. Curabitur nec vestibulum nunc. Nunc imperdiet lacus orci, ac vestibulum diam bibendum quis. Praesent convallis tempus ante, in suscipit urna facilisis at. Sed congue pretium feugiat. Nunc faucibus consectetur accumsan.Phasellus malesuada augue eget magna condimentum, ut rhoncus nisl ullamcorper. Pellentesque vitae erat facilisis, ullamcorper urna ac, eleifend massa. Phasellus elit eros, volutpat nec pellentesque et, ultrices nec erat. Cras iacu"; 8 | public final static String TEXT_2000 = "orem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies convallis lacinia. Nunc fringilla, odio ac volutpat lobortis, ligula nisi suscipit eros, quis porttitor neque mi id purus. Proin vitae nibh semper, fermentum sapien et, interdum urna. Morbi dictum dignissim est, vitae hendrerit dolor adipiscing sed. Phasellus ac est mi. Aenean adipiscing turpis rutrum elit ultricies, eget scelerisque nisl scelerisque. Cras quis urna vulputate est interdum congue. Pellentesque vel sollicitudin mi, sed fringilla odio. Duis quis volutpat orci. Curabitur nec vestibulum nunc. Nunc imperdiet lacus orci, ac vestibulum diam bibendum quis. Praesent convallis tempus ante, in suscipit urna facilisis at. Sed congue pretium feugiat. Nunc faucibus consectetur accumsan.Phasellus malesuada augue eget magna condimentum, ut rhoncus nisl ullamcorper. Pellentesque vitae erat facilisis, ullamcorper urna ac, eleifend massa. Phasellus elit eros, volutpat nec pellentesque et, ultrices nec erat. Cras iaculis tincidunt nulla auctor luctus. Pellentesque turpis leo, auctor sed sem eget, luctus malesuada erat. Donec sit amet posuere magna. Duis iaculis, arcu sit amet pharetra condimentum, quam dolor condimentum massa, convallis venenatis diam lorem eu sem.Nullam ornare dolor id neque pretium, quis dignissim lorem posuere. Quisque iaculis augue libero, in sagittis velit dignissim in. Nullam adipiscing, odio ut facilisis malesuada, nibh justo tincidunt ipsum, eget eleifend diam lacus ut nibh. Sed feugiat est eu elit sagittis, id sollicitudin sem faucibus. Sed sit amet libero et massa luctus ullamcorper. Sed non purus adipiscing, malesuada leo vel, tempus felis. Nulla ut ipsum laoreet diam eleifend gravida at eget nulla. Nullam ultrices convallis nisi at cursus. Nullam lacinia tincidunt eleifend. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas vel tincidunt metus. Nullam nibh orci, tristique sed mollis vitae, euismod ultricies augue. Aliquam tincidunt elit a massa ...."; 9 | } 10 | -------------------------------------------------------------------------------- /catalog/src/test/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | org.hibernate.jpa.HibernatePersistenceProvider 10 | org.rembx.jeeshop.catalog.model.Store 11 | org.rembx.jeeshop.catalog.model.Premises 12 | org.rembx.jeeshop.catalog.model.PremisesAddress 13 | org.rembx.jeeshop.catalog.model.PremisesOpeningSchedules 14 | org.rembx.jeeshop.catalog.model.Catalog 15 | org.rembx.jeeshop.catalog.model.Category 16 | org.rembx.jeeshop.catalog.model.Product 17 | org.rembx.jeeshop.catalog.model.SKU 18 | org.rembx.jeeshop.media.model.Media 19 | org.rembx.jeeshop.catalog.model.Presentation 20 | org.rembx.jeeshop.catalog.model.Discount 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /catalog/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /common/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | target 5 | 6 | src/main/resources/META-INF/resources 7 | src/main/webapp/node 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | *.iml -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.rembx.jeeshop 7 | jeeshop 8 | 0.9-SNAPSHOT 9 | 10 | common 11 | 12 | 13 | commons-lang 14 | commons-lang 15 | 16 | 17 | com.querydsl 18 | querydsl-apt 19 | 20 | 21 | com.querydsl 22 | querydsl-jpa 23 | 24 | 25 | org.jboss.weld.se 26 | weld-se 27 | test 28 | 29 | 30 | com.icegreen 31 | greenmail 32 | 1.4.1 33 | test 34 | 35 | 36 | io.quarkus 37 | quarkus-resteasy-multipart 38 | 39 | 40 | 41 | 42 | 43 | org.jboss.jandex 44 | jandex-maven-plugin 45 | 1.0.7 46 | 47 | 48 | make-index 49 | 50 | jandex 51 | 52 | 53 | 54 | 55 | 56 | com.mysema.maven 57 | apt-maven-plugin 58 | 1.1.3 59 | 60 | 61 | 62 | process 63 | 64 | 65 | target/generated-sources/java 66 | com.querydsl.apt.jpa.JPAAnnotationProcessor 67 | 68 | 69 | 70 | 71 | 72 | io.quarkus 73 | quarkus-maven-plugin 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /common/src/main/asciidoc/rest-api-general.adoc: -------------------------------------------------------------------------------- 1 | === General Jeeshop REST principles 2 | 3 | ==== Methods 4 | 5 | [options="header"] 6 | |=============== 7 | |Method|Operations 8 | |+GET+|Get a single resource or get a collection of resources. 9 | |+POST+|Create a new resource. 10 | |+PUT+|Update properties of an existing resource. 11 | |+DELETE+|Delete an existing resource. 12 | |+HEAD+|Check authentication credentials. (Only available on User resource) 13 | 14 | |=============== 15 | 16 | The media-type of HTTP requests should be set to application/json. + 17 | The media-type of HTTP responses is always application/json unless binary content is requested (eg. deployment resource data), the media-type of the content is used. 18 | 19 | Items relationships are always lazy loaded and must be explicitly requested to get them. (they are not eagerly fetched) 20 | 21 | ==== Authentication and authorization 22 | Jeeshop REST API operations are protected by role based access. Therefore, most of REST operations require authentication. + 23 | Jeeshop authentication and authorization are managed using https://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/JAASRefGuide.html[JaaS]. See https://github.com/remibantos/jeeshop#security-domain-configuration[this documentation] for details about Jeeshop JaaS configuration on Wildfly application server. + 24 | Currently, only Basic HTTP access authentication is documented, so you should include a +Authorization: Basic ...==+ HTTP-header when performing requests to API methods which are not public. 25 | 26 | NOTE: For security purpose we only allow Basic Authentication in combination with HTTPS. See https://github.com/remibantos/jeeshop#configure-ssl-to-secure-channels[this documentation] for details about Jeeshop SSL configuration on Wildfly application server. 27 | 28 | Each REST operation documentation declares one or many roles which are required for method use : 29 | 30 | * _admin_ - Role dedicated to admin / back office operations. (Typically, it has to be set on Jeeshop administrators accounts for Jeeshop-Admin application use) 31 | * _user_ - Default role bound to Jeeshop users. (Every online store registered users have this role) 32 | * _ALL_ - Public. Methods which declare this role are public. Authentication is not required for their use. 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/configuration/ConfigurationProducer.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.configuration; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.enterprise.inject.Produces; 8 | import javax.enterprise.inject.spi.InjectionPoint; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.Properties; 14 | 15 | 16 | /** 17 | * Configuration Producer 18 | *

19 | * Produces a value for a given @NamedConfiguration annotated property. 20 | * This value is retrieved from a property file named with the lower case class name where this property is declared 21 | *

22 | * User: remi 23 | */ 24 | public class ConfigurationProducer { 25 | 26 | private final static Logger logger = LoggerFactory.getLogger(ConfigurationProducer.class); 27 | 28 | private final static String CONFIGURATION_FILE_SUFFIX = ".properties"; 29 | 30 | /** 31 | * Stores every property files associated to classes using NamedConfiguration annotation 32 | */ 33 | private static final Map configurations = new HashMap<>(); 34 | 35 | @Produces 36 | @NamedConfiguration 37 | String retrieveNamedConfiguration(InjectionPoint injectionPoint) { 38 | 39 | String configurationFilePath; 40 | 41 | NamedConfiguration namedConfiguration = injectionPoint.getAnnotated().getAnnotation(NamedConfiguration.class); 42 | if (namedConfiguration.value() == null || StringUtils.isEmpty(namedConfiguration.value())) { 43 | return null; 44 | } 45 | 46 | if (namedConfiguration.configurationFile() == null || StringUtils.isEmpty(namedConfiguration.configurationFile())) { 47 | configurationFilePath = "/" + injectionPoint.getMember().getDeclaringClass().getSimpleName().toLowerCase() 48 | + CONFIGURATION_FILE_SUFFIX; 49 | } else { 50 | configurationFilePath = namedConfiguration.configurationFile(); 51 | } 52 | 53 | Properties properties = loadConfigurationFile(configurationFilePath); 54 | 55 | return properties.getProperty(namedConfiguration.value()); 56 | 57 | } 58 | 59 | private Properties loadConfigurationFile(String configurationFilePath) { 60 | 61 | 62 | if (configurations.get(configurationFilePath) != null) { 63 | return configurations.get(configurationFilePath); 64 | } 65 | 66 | logger.debug("Loading property file : {}", configurationFilePath); 67 | 68 | Properties properties = new Properties(); 69 | 70 | try (InputStream configurationFile = getClass().getResourceAsStream(configurationFilePath)) { 71 | if (configurationFile == null) 72 | throw new IllegalStateException("File :" + configurationFilePath + " not found"); 73 | properties.load(configurationFile); 74 | configurations.put(configurationFilePath,properties); 75 | 76 | } catch (IOException e) { 77 | throw new RuntimeException("Failed to load configuration file: " + configurationFilePath, e); 78 | } 79 | 80 | logger.debug("Property file load successful"); 81 | return properties; 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/configuration/NamedConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.configuration; 2 | 3 | 4 | import javax.enterprise.util.Nonbinding; 5 | import javax.inject.Qualifier; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | 9 | @Qualifier 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface NamedConfiguration { 12 | @Nonbinding String value() default ""; 13 | 14 | @Nonbinding String configurationFile() default ""; 15 | } -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/mail/Mailer.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.mail; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.rembx.jeeshop.configuration.NamedConfiguration; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | import javax.inject.Inject; 8 | import javax.mail.*; 9 | import javax.mail.internet.InternetAddress; 10 | import javax.mail.internet.MimeBodyPart; 11 | import javax.mail.internet.MimeMessage; 12 | import javax.mail.internet.MimeMultipart; 13 | import java.util.Date; 14 | import java.util.Properties; 15 | 16 | /** 17 | */ 18 | @ApplicationScoped 19 | public class Mailer { 20 | 21 | @Inject 22 | @NamedConfiguration("mail.smtp.host") 23 | private String host; 24 | 25 | @Inject 26 | @NamedConfiguration("mail.smtp.port") 27 | private String port; 28 | 29 | @Inject 30 | @NamedConfiguration("mail.auth.user") 31 | private String user; 32 | 33 | @Inject 34 | @NamedConfiguration("mail.auth.password") 35 | private String password; 36 | 37 | @Inject 38 | @NamedConfiguration("mail.from") 39 | private String sender; 40 | 41 | @Inject 42 | @NamedConfiguration("mail.smtp.timeout") 43 | private String readTimeout; 44 | 45 | @Inject 46 | @NamedConfiguration("mail.smtp.connectiontimeout") 47 | private String connectTimeout; 48 | 49 | @Inject 50 | @NamedConfiguration("debug") 51 | private String debug; 52 | 53 | public void sendMail(String subject, String to, String content) throws MessagingException { 54 | Properties props = new Properties(); 55 | props.put("mail.smtp.host", host); 56 | props.put("mail.smtp.port", port); 57 | props.put("mail.smtp.socketFactory.port", port); 58 | props.put("mail.smtp.socketFactory.class", 59 | "javax.net.ssl.SSLSocketFactory"); 60 | props.put("mail.smtp.connectiontimeout",connectTimeout); 61 | props.put("mail.smtp.timeout",readTimeout); 62 | 63 | Authenticator authenticator = null; 64 | if (StringUtils.isNotEmpty(user)) { 65 | props.put("mail.smtp.auth", "true"); 66 | authenticator = new Authenticator() { 67 | private PasswordAuthentication pa = new PasswordAuthentication(user, password); 68 | 69 | @Override 70 | public PasswordAuthentication getPasswordAuthentication() { 71 | return pa; 72 | } 73 | }; 74 | } 75 | 76 | Session session = Session.getInstance(props, authenticator); 77 | session.setDebug(Boolean.parseBoolean(debug)); 78 | 79 | MimeMessage message = new MimeMessage(session); 80 | 81 | message.setFrom(new InternetAddress(sender)); 82 | InternetAddress[] address = {new InternetAddress(to)}; 83 | message.setRecipients(Message.RecipientType.TO, address); 84 | message.setSubject(subject,"UTF-8"); 85 | message.setSentDate(new Date()); 86 | 87 | Multipart multipart = new MimeMultipart("alternative"); 88 | MimeBodyPart htmlPart = new MimeBodyPart(); 89 | htmlPart.setContent(content, "text/html; charset=utf-8"); 90 | multipart.addBodyPart(htmlPart); 91 | 92 | message.setContent(multipart); 93 | 94 | Transport.send(message); 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/rest/WebApplicationException.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.rest; 2 | 3 | 4 | import javax.ws.rs.core.Response; 5 | 6 | // FIXME ? @ApplicationException 7 | public class WebApplicationException extends javax.ws.rs.WebApplicationException{ 8 | public WebApplicationException(Response.Status status) { 9 | super(status); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/rest/WebApplicationExceptionMapper.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.rest; 2 | 3 | 4 | import javax.ws.rs.core.Response; 5 | 6 | /** 7 | * Avoid logging of stack trace for WebApplicationException instances thrown by application 8 | */ 9 | public class WebApplicationExceptionMapper implements javax.ws.rs.ext.ExceptionMapper { 10 | @Override 11 | public Response toResponse(WebApplicationException e) { 12 | return e.getResponse(); 13 | } 14 | } -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/role/AuthorizationUtils.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.role; 2 | 3 | import javax.ws.rs.core.SecurityContext; 4 | 5 | 6 | /** 7 | * Created by remi on 24/06/14. 8 | */ 9 | public class AuthorizationUtils { 10 | 11 | public static boolean isAdminUser(SecurityContext sessionContext) { 12 | return sessionContext != null && sessionContext.getUserPrincipal() != null 13 | && sessionContext.isUserInRole(JeeshopRoles.ADMIN); 14 | } 15 | 16 | public static boolean isOwner(SecurityContext securityContext, String owner) { 17 | return securityContext != null && securityContext.getUserPrincipal() != null 18 | && owner != null && securityContext.isUserInRole(JeeshopRoles.STORE_ADMIN) 19 | && owner.equals(securityContext.getUserPrincipal().getName()); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/role/JeeshopRoles.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.role; 2 | 3 | /** 4 | * Jeeshop roles 5 | */ 6 | public interface JeeshopRoles { 7 | 8 | String USER = "user"; 9 | String ADMIN = "admin"; 10 | String ADMIN_READONLY = "adminRO"; 11 | String STORE_ADMIN = "store_admin"; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.util; 2 | 3 | import java.time.Instant; 4 | import java.time.LocalDateTime; 5 | import java.time.ZoneOffset; 6 | import java.time.ZonedDateTime; 7 | import java.util.Date; 8 | 9 | /** 10 | * Created by remi on 25/05/14. 11 | */ 12 | public class DateUtil { 13 | 14 | public static ZonedDateTime dateToLocalDateTime(Date date){ 15 | Instant endDateInstant = Instant.ofEpochMilli(date.getTime()); 16 | return ZonedDateTime.ofInstant(endDateInstant, ZoneOffset.UTC); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/org/rembx/jeeshop/util/LocaleUtil.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.util; 2 | 3 | import org.apache.commons.lang.LocaleUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Locale; 8 | 9 | public class LocaleUtil { 10 | 11 | private static Logger logger = LoggerFactory.getLogger(LocaleUtil.class); 12 | 13 | public static final Locale FALLBACK = Locale.ENGLISH; 14 | 15 | public static String getLocaleCode(String localeStr) { 16 | Locale locale = FALLBACK; 17 | try { 18 | locale = (localeStr != null)? LocaleUtils.toLocale(localeStr):FALLBACK; 19 | } catch (IllegalArgumentException e) { 20 | logger.warn("cannot get locale from {}. Returning fallback locale: "+FALLBACK,localeStr); 21 | } 22 | return locale.toString(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /common/src/test/java/org/rembx/jeeshop/configuration/ConfigurationProducerCT.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.configuration; 2 | 3 | import org.jboss.weld.environment.se.Weld; 4 | import org.jboss.weld.environment.se.WeldContainer; 5 | import org.junit.AfterClass; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | 9 | import javax.inject.Inject; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Injection test using weld container 15 | */ 16 | public class ConfigurationProducerCT { 17 | 18 | protected static Weld weld; 19 | protected static WeldContainer container; 20 | 21 | @BeforeClass 22 | public static void init() { 23 | weld = new Weld(); 24 | container = weld.initialize(); 25 | } 26 | 27 | @AfterClass 28 | public static void close() { 29 | weld.shutdown(); 30 | } 31 | 32 | @Test 33 | public void withConfiguredFileProperty_shouldBeInjectedAsConfiguredValue() throws Exception { 34 | NamedConfigurationUse injected = container.instance().select(NamedConfigurationUse.class).get(); 35 | assertNotNull(injected); 36 | assertEquals("dummyHost", injected.getHostName()); 37 | assertEquals("dummyTimeout", injected.getTimeout()); 38 | } 39 | 40 | @Test 41 | public void withNotConfiguredFileProperty_shouldBeInjectedAsNull() throws Exception { 42 | NamedConfigurationUse injected = container.instance().select(NamedConfigurationUse.class).get(); 43 | assertNotNull(injected); 44 | assertNull(injected.getPort()); 45 | } 46 | 47 | @Test 48 | public void withUnknownFile_shouldThrowException() throws Exception { 49 | 50 | try{ 51 | NamedConfigurationWithoutConfigurationFile injected = container.instance().select(NamedConfigurationWithoutConfigurationFile.class).get(); 52 | fail(); 53 | }catch (IllegalStateException e){ 54 | 55 | } 56 | } 57 | 58 | } 59 | 60 | class NamedConfigurationUse { 61 | 62 | @Inject 63 | @NamedConfiguration("host.name") 64 | private String hostName; 65 | 66 | @Inject 67 | @NamedConfiguration("toto.toto") 68 | private String port; 69 | 70 | @Inject 71 | @NamedConfiguration(value = "timeout", configurationFile = "/namedconfigurationcustom.properties") 72 | private String timeout; 73 | 74 | String getTimeout() { 75 | return timeout; 76 | } 77 | 78 | String getPort() { 79 | return port; 80 | } 81 | 82 | public String getHostName() { 83 | return hostName; 84 | } 85 | 86 | } 87 | 88 | class NamedConfigurationWithoutConfigurationFile { 89 | 90 | @Inject 91 | @NamedConfiguration("toto.unknown") 92 | private String hostName; 93 | 94 | public String getHostName() { 95 | return hostName; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /common/src/test/java/org/rembx/jeeshop/configuration/TestProducer.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.configuration; 2 | 3 | import javax.enterprise.inject.Produces; 4 | import java.util.Calendar; 5 | import java.util.GregorianCalendar; 6 | 7 | /** 8 | * Created with IntelliJ IDEA. 9 | * User: bantos 10 | * Date: 29/11/13 11 | * Time: 21:04 12 | */ 13 | public class TestProducer { 14 | 15 | public final static Calendar calendar = new GregorianCalendar(2013, 0, 9, 18, 1, 0); 16 | 17 | @Produces 18 | private Calendar calendar(){ 19 | return calendar; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /common/src/test/java/org/rembx/jeeshop/mail/MailerIT.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.mail; 2 | 3 | import com.icegreen.greenmail.util.GreenMail; 4 | import com.icegreen.greenmail.util.ServerSetupTest; 5 | import org.jboss.weld.environment.se.Weld; 6 | import org.jboss.weld.environment.se.WeldContainer; 7 | import org.junit.*; 8 | 9 | import javax.mail.MessagingException; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static org.junit.Assert.fail; 13 | 14 | public class MailerIT { 15 | 16 | protected static Weld weld; 17 | protected static WeldContainer container; 18 | 19 | private GreenMail server; 20 | 21 | @BeforeClass 22 | public static void init() { 23 | weld = new Weld(); 24 | container = weld.initialize(); 25 | } 26 | 27 | @AfterClass 28 | public static void close() { 29 | weld.shutdown(); 30 | } 31 | 32 | @Before 33 | public void setUp() { 34 | server = new GreenMail(ServerSetupTest.SMTP); 35 | server.start(); 36 | } 37 | 38 | @After 39 | public void tearDown() { 40 | server.stop(); 41 | } 42 | 43 | @Test 44 | public void sendMail() throws Exception{ 45 | Mailer mailer = container.instance().select(Mailer.class).get(); 46 | try { 47 | mailer.sendMail("Test Subject", "test@test.com", "

Hello

"); 48 | } catch (MessagingException e) { 49 | e.printStackTrace(); 50 | fail(); 51 | } 52 | 53 | assertThat(server.getReceivedMessages().length).isEqualTo(1); 54 | assertThat(server.getReceivedMessages()[0].getSubject()).isEqualTo("Test Subject"); 55 | } 56 | 57 | @Test 58 | public void sendMail_shouldThrowConnectTimeoutEx_WhenNoSmtpServerAvailable(){ 59 | server.stop(); 60 | Mailer mailer = container.instance().select(Mailer.class).get(); 61 | try { 62 | mailer.sendMail("Test Subject", "test@test.com", "

Hello

"); 63 | fail("should have thrown ex"); 64 | }catch (MessagingException e){ 65 | assertThat(e.getMessage()).startsWith("Couldn't connect to host"); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /common/src/test/java/org/rembx/jeeshop/util/DateUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.util; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.text.SimpleDateFormat; 7 | import java.time.LocalDateTime; 8 | import java.time.Month; 9 | import java.time.ZoneId; 10 | import java.time.ZonedDateTime; 11 | import java.util.Date; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | public class DateUtilTest { 16 | 17 | @Test 18 | public void testDateToLocalDateTime() throws Exception { 19 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z"); 20 | Date date = sdf.parse("2001.07.04 12:08:56 UTC"); 21 | ZonedDateTime localDateTime = DateUtil.dateToLocalDateTime(date); 22 | assertThat(ZonedDateTime.of(LocalDateTime.of(2001, Month.JULY, 4, 12, 8, 56), ZoneId.of("Z"))).isEqualTo(localDateTime); 23 | } 24 | } -------------------------------------------------------------------------------- /common/src/test/java/org/rembx/jeeshop/util/LocaleUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.util; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | public class LocaleUtilTest { 8 | 9 | @Test 10 | public void getLocaleCode_shouldReturnLocaleCode() throws Exception { 11 | assertThat(LocaleUtil.getLocaleCode("en_GB")).isEqualTo("en_GB"); 12 | } 13 | 14 | @Test 15 | public void getLocaleCode_shouldFallbackForInvalidLocale() throws Exception { 16 | assertThat(LocaleUtil.getLocaleCode("qsdpjsd")).isEqualTo(LocaleUtil.FALLBACK.toString()); 17 | } 18 | 19 | @Test 20 | public void getLocaleCode_shouldFallbackWhenNullLocaleProvided() throws Exception { 21 | assertThat(LocaleUtil.getLocaleCode(null)).isEqualTo(LocaleUtil.FALLBACK.toString()); 22 | } 23 | } -------------------------------------------------------------------------------- /common/src/test/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /common/src/test/resources/mailer.properties: -------------------------------------------------------------------------------- 1 | mail.smtp.host=127.0.0.1 2 | mail.smtp.port=3025 3 | mail.smtp.timeout=10000 4 | mail.smtp.connectiontimeout=10000 5 | mail.auth.user=test@test.com 6 | mail.auth.password=toto 7 | mail.from=test@test.com 8 | debug=true 9 | -------------------------------------------------------------------------------- /common/src/test/resources/namedconfigurationcustom.properties: -------------------------------------------------------------------------------- 1 | timeout=dummyTimeout -------------------------------------------------------------------------------- /common/src/test/resources/namedconfigurationuse.properties: -------------------------------------------------------------------------------- 1 | host.name=dummyHost -------------------------------------------------------------------------------- /deployments/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/deployments/.gitkeep -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | postgres-jeeshop-admin: 5 | image: postgres 6 | container_name: postgres-jeeshop-admin 7 | environment: 8 | POSTGRES_DB: jeeshop 9 | POSTGRES_USER: jeeshop 10 | POSTGRES_PASSWORD: test 11 | volumes: 12 | - ./database-data:/var/lib/postgresql/data/ 13 | ports: 14 | - 5432:5432 15 | 16 | jeeshop: 17 | image: jeeshop/admin 18 | container_name: jeeshop 19 | environment: 20 | JEESHOP_DATABASENAME: jeeshop 21 | JEESHOP_DATABASE_HOSTNAME: postgres-jeeshop-admin:5432 22 | JEESHOP_DATABASE_USERNAME: jeeshop 23 | JEESHOP_DATABASE_PASSWORD: test 24 | JEESHOP_JDBC_DRIVER: postgresql 25 | JEESHOP_CATALOG_DATABASENAME: jeeshop 26 | JEESHOP_CATALOG_DATABASE_HOSTNAME: postgres-jeeshop-admin:5432 27 | JEESHOP_CATALOG_DATABASE_USERNAME: jeeshop 28 | JEESHOP_CATALOG_DATABASE_PASSWORD: test 29 | JEESHOP_CATALOG_JDBC_DRIVER: postgresql 30 | JEESHOP_DATA_DIR: /jeeshop 31 | PROXY_ADDRESS_FORWARDING: "true" 32 | ports: 33 | - 8080:8080 34 | volumes: 35 | - ./images:/jeeshop 36 | depends_on: 37 | - postgres-jeeshop-admin 38 | 39 | volumes: 40 | database-data: 41 | images: 42 | 43 | # Uncomment to use external network 44 | #networks: 45 | # default: 46 | # external: 47 | # name: nginx-proxy 48 | -------------------------------------------------------------------------------- /install/src/main/resources/db/mysql/V1.0__jeeshop-drop.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- DB: jeeshop - DROP - MySql5 3 | -- 4 | 5 | -- 6 | -- Tables 7 | -- 8 | SET foreign_key_checks = 0; 9 | drop table if exists address; 10 | drop table if exists catalog; 11 | drop table if exists catalog_category; 12 | drop table if exists catalog_presentation; 13 | drop table if exists category; 14 | drop table if exists category_category; 15 | drop table if exists category_presentation; 16 | drop table if exists category_product; 17 | drop table if exists country; 18 | drop table if exists discount; 19 | drop table if exists discount_presentation; 20 | drop table if exists mailtemplate_media; 21 | drop table if exists mailtemplate; 22 | drop table if exists media; 23 | drop table if exists presentation; 24 | drop table if exists presentation_media; 25 | drop table if exists presentation_feature; 26 | drop table if exists product; 27 | drop table if exists product_discount; 28 | drop table if exists product_presentation; 29 | drop table if exists product_sku; 30 | drop table if exists role; 31 | drop table if exists sku; 32 | drop table if exists sku_discount; 33 | drop table if exists sku_presentation; 34 | drop table if exists orderitem; 35 | drop table if exists orderdiscount; 36 | drop table if exists orders; 37 | drop table if exists user; 38 | drop table if exists user_role; 39 | drop table if exists newsletter; 40 | SET foreign_key_checks = 1; 41 | -------------------------------------------------------------------------------- /install/src/main/resources/db/postgresql/V1.0_2__create_store.sql: -------------------------------------------------------------------------------- 1 | 2 | alter table if exists catalog add column owner varchar(100); 3 | alter table if exists category add column owner varchar(100); 4 | alter table if exists product add column owner varchar(100); 5 | alter table if exists sku add column owner varchar(100); 6 | alter table if exists discount add column owner varchar(100); 7 | 8 | update catalog set owner = 'admin@jeeshop.org'; 9 | update category set owner = 'admin@jeeshop.org'; 10 | update product set owner = 'admin@jeeshop.org'; 11 | update sku set owner = 'admin@jeeshop.org'; 12 | update discount set owner = 'admin@jeeshop.org'; 13 | 14 | alter table if exists catalog alter column owner set not null; 15 | alter table if exists category alter column owner set not null; 16 | alter table if exists product alter column owner set not null; 17 | alter table if exists sku alter column owner set not null; 18 | alter table if exists discount alter column owner set not null; 19 | 20 | create table if not exists store ( 21 | id serial not null primary key, 22 | description varchar(255) null, 23 | disabled boolean null, 24 | enddate date null, 25 | name varchar(50) not null, 26 | startdate date null, 27 | owner varchar(100) not null); 28 | 29 | create table if not exists premises_address ( 30 | id serial not null primary key, 31 | city varchar(255) not null, 32 | street varchar(255)not null, 33 | zipcode varchar (10) not null, 34 | countryiso3code varchar (3) not null); 35 | 36 | create table if not exists premises ( 37 | id serial not null primary key, 38 | store_id bigint not null, 39 | address_id bigint not null 40 | ); 41 | 42 | create table if not exists schedules ( 43 | id serial not null primary key, 44 | premises_id bigint not null, 45 | dayoftheweek integer not null, 46 | time_open time not null, 47 | time_close time not null); 48 | 49 | create table if not exists store_presentation ( 50 | catalogitemid bigint not null, 51 | presentationid bigint not null, 52 | primary key (catalogitemid,presentationid)); 53 | 54 | alter table premises 55 | add constraint fk_premises_address foreign key (address_id) references premises_address (id), 56 | add constraint fk_premises_store foreign key (store_id) references store (id); 57 | 58 | alter table schedules 59 | add constraint fk_schedules_premises foreign key (premises_id) references premises (id); 60 | 61 | insert into "role" (id, name) values (4, 'store_admin'); -------------------------------------------------------------------------------- /install/src/main/resources/db/postgresql/V1.0__jeeshop-drop.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- DB: jeeshop - DROP - Postgresql 3 | -- 4 | 5 | -- 6 | -- Tables 7 | -- 8 | 9 | DROP TABLE IF EXISTS Catalog_Category; 10 | DROP TABLE IF EXISTS Catalog_Presentation; 11 | DROP TABLE IF EXISTS Category_Category; 12 | DROP TABLE IF EXISTS Category_Presentation; 13 | DROP TABLE IF EXISTS Category_Product; 14 | DROP TABLE IF EXISTS Discount_Presentation; 15 | DROP TABLE IF EXISTS MailTemplate_Media; 16 | DROP TABLE IF EXISTS Presentation_Media; 17 | DROP TABLE IF EXISTS Presentation_Feature; 18 | DROP TABLE IF EXISTS Product_Discount; 19 | DROP TABLE IF EXISTS Product_Presentation; 20 | DROP TABLE IF EXISTS Product_SKU; 21 | DROP TABLE IF EXISTS SKU_Discount; 22 | DROP TABLE IF EXISTS SKU_Presentation; 23 | DROP TABLE IF EXISTS User_Role; 24 | DROP TABLE IF EXISTS "catalog"; 25 | DROP TABLE IF EXISTS Category; 26 | DROP TABLE IF EXISTS Country; 27 | DROP TABLE IF EXISTS Discount; 28 | DROP TABLE IF EXISTS MailTemplate; 29 | DROP TABLE IF EXISTS Presentation; 30 | DROP TABLE IF EXISTS Product; 31 | DROP TABLE IF EXISTS Role; 32 | DROP TABLE IF EXISTS SKU; 33 | DROP TABLE IF EXISTS OrderItem; 34 | DROP TABLE IF EXISTS OrderDiscount; 35 | DROP TABLE IF EXISTS Orders; 36 | DROP TABLE IF EXISTS Media; 37 | DROP TABLE IF EXISTS "user"; 38 | DROP TABLE IF EXISTS Newsletter; 39 | DROP TABLE IF EXISTS store_address; 40 | DROP TABLE IF EXISTS store_presentation; 41 | DROP TABLE IF EXISTS schedules; 42 | DROP TABLE IF EXISTS premises; 43 | DROP TABLE IF EXISTS "store"; 44 | DROP TABLE IF EXISTS Address; 45 | -------------------------------------------------------------------------------- /install/src/main/resources/demo/db/postgresql/demo-order-data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO address (city, street, zipcode, countryiso3code, gender, firstname, lastname, company) 2 | VALUES ('Paris', '11, Rue des lilas', '75001', 'FRA', 'M.', 'John', 'Smith', null); 3 | 4 | 5 | INSERT INTO orders(id, user_id, transactionid, deliveryaddress_id, billingaddress_id, 6 | status, creationdate, updatedate, paymentdate, deliverydate, parceltrackingkey, price) VALUES 7 | (1, 1, 1, (SELECT MAX(id) FROM address), (SELECT MAX(id) FROM address), 'PAYMENT_VALIDATED', '2020-11-26 00:52:52', '2020-11-26 00:52:52', null, null, null, 234.5), 8 | (2, 1, 2, (SELECT MAX(id) FROM address), (SELECT MAX(id) FROM address), 'DELIVERED', '2020-11-26 00:52:52', '2020-11-26 00:52:52', '2020-11-26 01:52:52', '2020-11-28 08:52:52', 'EKJKJKKH7676', 99.9); 9 | 10 | SELECT setval('orders_id_seq', (SELECT MAX(id) FROM orders)); 11 | 12 | 13 | INSERT INTO orderitem(order_id, sku_id, product_id, quantity, price) VALUES 14 | (1, 1, 1, 1, 200.0), 15 | (1, 3, 2, 1, 34.5), 16 | (2, 5, 3, 1, 99.0); 17 | 18 | INSERT INTO orderdiscount(order_id, discount_id, discountvalue) 19 | VALUES (1, 1, 10.0); 20 | -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/1/en/bikes_root_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/1/en/bikes_root_cat.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/1/fr/bikes_root_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/1/fr/bikes_root_cat.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/12/en/racing-bikes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/12/en/racing-bikes.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/12/fr/racing-bikes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/12/fr/racing-bikes.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/2/en/accessories_root_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/2/en/accessories_root_cat.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/2/fr/accessories_root_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/2/fr/accessories_root_cat.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/7/en/bikes_root_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/7/en/bikes_root_cat.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/categories/7/fr/bikes_root_cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/categories/7/fr/bikes_root_cat.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/discounts/2/en/pastille-livraison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/discounts/2/en/pastille-livraison.png -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/discounts/2/fr/pastille-livraison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/discounts/2/fr/pastille-livraison.png -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/discounts/5/en/pastille-10-pourcent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/discounts/5/en/pastille-10-pourcent.png -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/discounts/5/fr/pastille-10-pourcent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/discounts/5/fr/pastille-10-pourcent.png -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/products/1/en/energy_x1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/products/1/en/energy_x1.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/products/1/fr/energy_x1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/products/1/fr/energy_x1.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/products/2/en/energy_x2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/products/2/en/energy_x2.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/jeeshop-media/products/2/fr/energy_x2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealJeeshop/jeeshop/c50b333f1c3be3d936cb67d1cfa5b36aaef01c19/install/src/main/resources/demo/jeeshop-media/products/2/fr/energy_x2.jpg -------------------------------------------------------------------------------- /install/src/main/resources/demo/mailTemplates/userRegistration_en.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | Jeeshop store demo 4 | 5 |
6 | 7 |

Welcome ${gender} ${firstname} ${lastname},

8 | 9 |

You have subscribed to Jeeshop store demo.

10 | 11 |

Please activate your account by clicking on link below : (1)

12 |
 
13 |
https://apps-jeeshop.rhcloud.com/jeeshop-store/#!/activation/${login}/${actionToken}
14 |
 
15 |

Best regards

-------------------------------------------------------------------------------- /install/src/main/resources/demo/mailTemplates/userRegistration_fr.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | Jeeshop store demo 4 | 5 |
6 | 7 |

Bienvenue ${gender} ${firstname} ${lastname},

8 | 9 |

Vous venez de créer un compte Jeeshop store demo.

10 | 11 |

Nous vous invitons à copier le lien ci-dessous dans la barre d'adresse de votre navigateur internet afin d'activer votre compte : (1)

12 |
 
13 |
https://apps-jeeshop.rhcloud.com/jeeshop-store/#!/activation/${login}/${actionToken}
14 |
 
15 |

A très bientôt

-------------------------------------------------------------------------------- /install/src/main/resources/demo/mailTemplates/userResetPassword_en.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | Jeeshop store demo 4 | 5 |
6 | 7 |

Hello ${gender} ${firstname} ${lastname},

8 | 9 |

You have have submitted the reset password from Jeeshop store demo.

10 | 11 |

Please click on link below to reset your password : (1)

12 |
 
13 |
https://apps-jeeshop.rhcloud.com/jeeshop-store/#!/resetpassword/${login}/${actionToken}
14 |
 
15 |

Best regards

-------------------------------------------------------------------------------- /install/src/main/resources/demo/mailTemplates/userResetPassword_fr.ftl: -------------------------------------------------------------------------------- 1 |
2 | 3 | Jeeshop store demo 4 | 5 |
6 | 7 |

Bonjour ${gender} ${firstname} ${lastname},

8 | 9 |

Vous venez d'effectuer une demande de réinitialisation de votre mot de passe sur Jeeshop store demo.

10 | 11 |

Nous vous invitons à copier le lien ci-dessous dans la barre d'adresse de votre navigateur internet afin de réinitialiser votre mot de passe : (1)

12 |
 
13 |
https://apps-jeeshop.rhcloud.com/jeeshop-store/#!/resetpassword/${login}/${actionToken}
14 |
 
15 |

A très bientôt,

-------------------------------------------------------------------------------- /media/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.rembx.jeeshop 7 | jeeshop 8 | 0.9-SNAPSHOT 9 | 10 | media 11 | media 12 | 13 | 14 | org.rembx.jeeshop 15 | common 16 | ${project.version} 17 | 18 | 19 | commons-fileupload 20 | commons-fileupload 21 | 22 | 23 | io.quarkus 24 | quarkus-resteasy-multipart 25 | 26 | 27 | 28 | 29 | 30 | org.jboss.jandex 31 | jandex-maven-plugin 32 | 1.0.7 33 | 34 | 35 | make-index 36 | 37 | jandex 38 | 39 | 40 | 41 | 42 | 43 | com.mysema.maven 44 | apt-maven-plugin 45 | 1.1.3 46 | 47 | 48 | 49 | process 50 | 51 | 52 | target/generated-sources/java 53 | com.querydsl.apt.jpa.JPAAnnotationProcessor 54 | 55 | 56 | 57 | 58 | 59 | io.quarkus 60 | quarkus-maven-plugin 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /media/src/main/java/org/rembx/jeeshop/media/model/Media.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.media.model; 2 | 3 | import javax.persistence.*; 4 | import javax.validation.constraints.Size; 5 | 6 | /** 7 | * Created by remi on 20/05/14. 8 | */ 9 | @Entity 10 | public class Media { 11 | 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | private Long id; 15 | 16 | @Size(max = 255) 17 | @Column(nullable = false, length = 255) 18 | private String uri; 19 | 20 | public Long getId() { 21 | return id; 22 | } 23 | 24 | public void setId(Long id) { 25 | this.id = id; 26 | } 27 | 28 | public String getUri() { 29 | return uri; 30 | } 31 | 32 | public void setUri(String uri) { 33 | this.uri = uri; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) return true; 39 | if (o == null || getClass() != o.getClass()) return false; 40 | 41 | Media media = (Media) o; 42 | 43 | if (id != null ? !id.equals(media.id) : media.id != null) return false; 44 | if (uri != null ? !uri.equals(media.uri) : media.uri != null) return false; 45 | 46 | return true; 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | int result = id != null ? id.hashCode() : 0; 52 | result = 31 * result + (uri != null ? uri.hashCode() : 0); 53 | return result; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /media/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /media/src/test/java/org/rembx/jeeshop/media/MediasTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.media; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import org.rembx.jeeshop.rest.WebApplicationException; 6 | 7 | import javax.ws.rs.core.Response; 8 | import java.io.File; 9 | import java.nio.file.Files; 10 | 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | import static org.assertj.core.api.Assertions.fail; 13 | 14 | public class MediasTest { 15 | 16 | Medias medias; 17 | 18 | @BeforeEach 19 | public void setup() { 20 | medias = new Medias(); 21 | } 22 | 23 | @Test 24 | public void get_shouldReturnFile_whenThereIsAFileWithPathMatchingGivenParams() throws Exception { 25 | 26 | java.nio.file.Path basePath = medias.getBasePath(); 27 | 28 | java.nio.file.Path testFilePath = basePath.resolve("categories").resolve("999").resolve("en_GB"); 29 | 30 | if (!Files.exists(testFilePath)) { 31 | Files.createDirectories(testFilePath); 32 | } 33 | 34 | File testFile = new File(testFilePath.toFile(), "testMedias.test"); 35 | testFile.createNewFile(); 36 | 37 | assertThat(medias.get("categories", 999L, "en_GB", "testMedias.test")).isNotNull(); 38 | 39 | } 40 | 41 | @Test 42 | public void get_shouldThrowNotFound_whenThereAreNoFileMatchingGivenParams() throws Exception { 43 | try { 44 | medias.get("categories", 999L, "en_GB", "unknown.test"); 45 | fail("Should have thrown ex"); 46 | } catch (WebApplicationException e) { 47 | assertThat(e.getResponse().getStatus()).isEqualTo(Response.Status.NOT_FOUND.getStatusCode()); 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /order/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.rembx.jeeshop 7 | jeeshop 8 | 0.9-SNAPSHOT 9 | 10 | order 11 | order 12 | order domain 13 | 14 | 15 | org.rembx.jeeshop 16 | user 17 | ${project.version} 18 | 19 | 20 | org.rembx.jeeshop 21 | user 22 | ${project.version} 23 | test-jar 24 | test 25 | 26 | 27 | org.rembx.jeeshop 28 | catalog 29 | ${project.version} 30 | 31 | 32 | org.rembx.jeeshop 33 | catalog 34 | ${project.version} 35 | test-jar 36 | test 37 | 38 | 39 | io.rest-assured 40 | rest-assured 41 | test 42 | 43 | 44 | org.hsqldb 45 | hsqldb 46 | test 47 | 48 | 49 | org.hibernate 50 | hibernate-entitymanager 51 | ${version.hibernate} 52 | test 53 | 54 | 55 | org.hibernate 56 | hibernate-core 57 | ${version.hibernate} 58 | test 59 | 60 | 61 | io.quarkus 62 | quarkus-resteasy-multipart 63 | 64 | 65 | 66 | 67 | 68 | org.jboss.jandex 69 | jandex-maven-plugin 70 | 1.0.7 71 | 72 | 73 | make-index 74 | 75 | jandex 76 | 77 | 78 | 79 | 80 | 81 | io.quarkus 82 | quarkus-maven-plugin 83 | 84 | 85 | org.asciidoctor 86 | asciidoctor-maven-plugin 87 | 88 | 89 | output-html 90 | generate-resources 91 | 92 | process-asciidoc 93 | 94 | 95 | 96 | 97 | coderay 98 | html5 99 | 100 | ./images 101 | left 102 | 3 103 | 104 | font 105 | true 106 | 107 | - 108 | true 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /order/src/main/asciidoc/EligibleDiscounts.adoc: -------------------------------------------------------------------------------- 1 | === Eligible order discounts resource 2 | 3 | Manages user orders. 4 | 5 | ==== Get eligible order discounts 6 | 7 | [cols="h,5a"] 8 | |==== 9 | | URL 10 | | /rs/discounts/eligible 11 | 12 | | Method 13 | | GET 14 | 15 | | Description 16 | | Returns all discounts eligible for current authenticated user's next order. 17 | 18 | | Roles allowed 19 | | _user_ 20 | 21 | | Parameters 22 | | 23 | !==== 24 | ! Name ! Mandatory ! Description 25 | 26 | ! locale 27 | ! No 28 | ! For sample _en_GB_. Can be provided get localized related presentation item (localized content) in response 29 | 30 | | Response HTTP statuses 31 | | 32 | !==== 33 | ! Code ! Meaning 34 | ! 200 35 | ! Success 36 | 37 | !==== 38 | 39 | | Response Body 40 | | include::snippets/Discount.list.json.adoc[] 41 | |==== 42 | -------------------------------------------------------------------------------- /order/src/main/asciidoc/rest-api.adoc: -------------------------------------------------------------------------------- 1 | == Order REST API 2 | 3 | include::../../../../common/src/main/asciidoc/rest-api-general.adoc[] 4 | 5 | include::Orders.adoc[] 6 | 7 | include::EligibleDiscounts.adoc[] -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/EligibleDiscounts.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import io.quarkus.undertow.runtime.HttpSessionContext; 4 | import org.rembx.jeeshop.catalog.DiscountFinder; 5 | import org.rembx.jeeshop.catalog.model.Discount; 6 | import org.rembx.jeeshop.role.JeeshopRoles; 7 | import org.rembx.jeeshop.user.UserFinder; 8 | import org.rembx.jeeshop.user.model.User; 9 | 10 | import javax.annotation.Resource; 11 | import javax.annotation.security.RolesAllowed; 12 | import javax.enterprise.context.ApplicationScoped; 13 | import javax.enterprise.context.RequestScoped; 14 | import javax.inject.Inject; 15 | import javax.transaction.Transactional; 16 | import javax.ws.rs.GET; 17 | import javax.ws.rs.Path; 18 | import javax.ws.rs.Produces; 19 | import javax.ws.rs.QueryParam; 20 | import javax.ws.rs.core.Context; 21 | import javax.ws.rs.core.MediaType; 22 | import javax.ws.rs.core.SecurityContext; 23 | import java.util.List; 24 | 25 | /** 26 | * Orders resource. 27 | */ 28 | @Path("discounts/eligible") 29 | @ApplicationScoped 30 | public class EligibleDiscounts { 31 | 32 | private DiscountFinder discountFinder; 33 | private UserFinder userFinder; 34 | private OrderFinder orderFinder; 35 | 36 | private OrderConfiguration orderConfiguration; 37 | 38 | EligibleDiscounts(UserFinder userFinder, DiscountFinder discountFinder, OrderFinder orderFinder) { 39 | this.userFinder = userFinder; 40 | this.discountFinder = discountFinder; 41 | this.orderFinder = orderFinder; 42 | } 43 | 44 | @GET 45 | @Produces(MediaType.APPLICATION_JSON) 46 | @RolesAllowed(JeeshopRoles.USER) 47 | public List findEligible(@Context SecurityContext securityContext, @QueryParam("locale") String locale) { 48 | 49 | User currentUser = userFinder.findByLogin(securityContext.getUserPrincipal().getName()); 50 | 51 | Long completedOrders = orderFinder.countUserCompletedOrders(currentUser); 52 | 53 | return discountFinder.findEligibleOrderDiscounts(locale, completedOrders ); 54 | 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/Fees.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import javax.annotation.security.PermitAll; 4 | import javax.enterprise.context.ApplicationScoped; 5 | import javax.enterprise.context.RequestScoped; 6 | import javax.inject.Inject; 7 | import javax.transaction.Transactional; 8 | import javax.ws.rs.GET; 9 | import javax.ws.rs.Path; 10 | import javax.ws.rs.Produces; 11 | import javax.ws.rs.core.MediaType; 12 | 13 | @Path("/rs/fees") 14 | @ApplicationScoped 15 | public class Fees { 16 | 17 | private OrderConfiguration orderConfiguration; 18 | 19 | Fees(OrderConfiguration orderConfiguration) { 20 | this.orderConfiguration = orderConfiguration; 21 | } 22 | 23 | @GET 24 | @Produces(MediaType.APPLICATION_JSON) 25 | @Path("/shipping") 26 | @PermitAll 27 | public Double getShippingFee() { 28 | if (orderConfiguration!=null){ 29 | return orderConfiguration.getFixedDeliveryFee(); 30 | } 31 | return null; 32 | } 33 | 34 | 35 | @GET 36 | @Path("/vat") 37 | @Produces(MediaType.APPLICATION_JSON) 38 | @PermitAll 39 | public Double getVAT() { 40 | if (orderConfiguration!=null){ 41 | return orderConfiguration.getVAT(); 42 | } 43 | return null; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/OrderConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import org.rembx.jeeshop.configuration.NamedConfiguration; 4 | 5 | import javax.enterprise.context.ApplicationScoped; 6 | import javax.inject.Inject; 7 | 8 | @ApplicationScoped 9 | public class OrderConfiguration { 10 | 11 | @Inject 12 | @NamedConfiguration("fixed.delivery.fee") 13 | private String fixedDeliveryFee; 14 | 15 | @Inject 16 | @NamedConfiguration("vat") 17 | private String vat; 18 | 19 | public OrderConfiguration() { 20 | } 21 | 22 | public OrderConfiguration(String fixedDeliveryFee, String vat) { 23 | this.fixedDeliveryFee = fixedDeliveryFee; 24 | this.vat = vat; 25 | } 26 | 27 | public Double getFixedDeliveryFee() { 28 | return Double.parseDouble(fixedDeliveryFee); 29 | } 30 | 31 | public Double getVAT() { 32 | return Double.parseDouble(vat); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/PaymentTransactionEngine.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import org.rembx.jeeshop.order.model.Order; 4 | import org.rembx.jeeshop.order.model.PaymentInfo; 5 | 6 | /** 7 | * Created by remi on 07/12/14. 8 | */ 9 | public interface PaymentTransactionEngine { 10 | public void processPayment(Order order); 11 | } 12 | -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/PriceEngine.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import org.rembx.jeeshop.order.model.Order; 4 | import org.rembx.jeeshop.order.model.PaymentInfo; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | import javax.enterprise.context.RequestScoped; 8 | 9 | /** 10 | * Created by remi on 07/12/14. 11 | */ 12 | @ApplicationScoped 13 | public interface PriceEngine { 14 | public void computePrice(Order order); 15 | } 16 | -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/PriceEngineImpl.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import io.quarkus.arc.DefaultBean; 4 | import io.quarkus.hibernate.orm.PersistenceUnit; 5 | import org.apache.commons.collections.CollectionUtils; 6 | import org.rembx.jeeshop.catalog.DiscountFinder; 7 | import org.rembx.jeeshop.catalog.model.CatalogPersistenceUnit; 8 | import org.rembx.jeeshop.catalog.model.Discount; 9 | import org.rembx.jeeshop.catalog.model.SKU; 10 | import org.rembx.jeeshop.order.model.Order; 11 | import org.rembx.jeeshop.order.model.OrderDiscount; 12 | import org.rembx.jeeshop.order.model.OrderItem; 13 | 14 | import javax.enterprise.context.ApplicationScoped; 15 | import javax.enterprise.context.RequestScoped; 16 | import javax.enterprise.inject.Default; 17 | import javax.inject.Inject; 18 | import javax.persistence.EntityManager; 19 | import javax.persistence.PersistenceContext; 20 | import java.util.HashSet; 21 | import java.util.List; 22 | 23 | /** 24 | * Order price engine 25 | * Computes order's price and updates Order's properties 26 | */ 27 | @ApplicationScoped 28 | @Default 29 | public class PriceEngineImpl implements PriceEngine { 30 | 31 | private EntityManager entityManager; 32 | private OrderConfiguration orderConfiguration; 33 | private DiscountFinder discountFinder; 34 | private OrderFinder orderFinder; 35 | 36 | PriceEngineImpl(@PersistenceUnit(CatalogPersistenceUnit.NAME) EntityManager entityManager, OrderConfiguration orderConfiguration, 37 | OrderFinder orderFinder, DiscountFinder discountFinder) { 38 | this.entityManager = entityManager; 39 | this.orderConfiguration = orderConfiguration; 40 | this.orderFinder = orderFinder; 41 | this.discountFinder = discountFinder; 42 | } 43 | 44 | @Override 45 | public void computePrice(Order order) { 46 | 47 | if (CollectionUtils.isEmpty(order.getItems())){ 48 | throw new IllegalStateException("Order items list is empty "+order); 49 | } 50 | 51 | Double price = 0.0; 52 | 53 | for (OrderItem orderItem : order.getItems()){ 54 | 55 | SKU sku = entityManager.find(SKU.class,(orderItem).getSkuId()); 56 | price += (sku.getPrice()*(orderItem).getQuantity()); 57 | orderItem.setPrice(sku.getPrice()); 58 | } 59 | 60 | final Double fixedDeliveryFee = orderConfiguration.getFixedDeliveryFee(); 61 | 62 | price = applyEligibleDiscounts(order, price); 63 | 64 | if (fixedDeliveryFee != null){ 65 | price += fixedDeliveryFee; 66 | order.setDeliveryFee(fixedDeliveryFee); 67 | } 68 | 69 | order.setPrice(price); 70 | 71 | } 72 | 73 | private Double applyEligibleDiscounts(Order order, Double price) { 74 | 75 | double originalPrice = price; 76 | 77 | Long userCompletedOrders = orderFinder.countUserCompletedOrders(order.getUser()); 78 | 79 | List userEligibleOrderDiscounts = discountFinder.findEligibleOrderDiscounts(null,userCompletedOrders); 80 | 81 | if (userEligibleOrderDiscounts == null) { 82 | return price; 83 | } 84 | 85 | if (order.getOrderDiscounts() == null){ 86 | order.setOrderDiscounts(new HashSet<>()); 87 | } 88 | 89 | for (Discount discount : userEligibleOrderDiscounts){ 90 | if (discount.isEligible(originalPrice)){ 91 | price = discount.processDiscount(price, originalPrice); 92 | order.getOrderDiscounts().add(new OrderDiscount(discount.getId(),discount.getDiscountValue())); 93 | } 94 | } 95 | 96 | return price; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /order/src/main/java/org/rembx/jeeshop/order/mail/Mails.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.mail; 2 | 3 | /** 4 | * Created by remi on 14/12/14. 5 | */ 6 | public enum Mails { 7 | orderAccepted, 8 | orderValidated, 9 | orderShipped 10 | } 11 | -------------------------------------------------------------------------------- /order/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /order/src/test/java/org/rembx/jeeshop/order/EligibleDiscountsCT.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | // TODO! 7 | public class EligibleDiscountsCT { 8 | 9 | @Test 10 | public void testFindEligible() throws Exception { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /order/src/test/java/org/rembx/jeeshop/order/FeesTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | 8 | public class FeesTest { 9 | 10 | @Test 11 | public void getShippingFeesShouldReturnConfiguredShippingFeeAsDouble() throws Exception { 12 | OrderConfiguration orderConfiguration = orderConfiguration(); 13 | 14 | Fees fees = new Fees(orderConfiguration); 15 | assertThat(fees.getShippingFee()).isEqualTo(11.0); 16 | } 17 | 18 | @Test 19 | public void getVATShouldReturnConfiguredVATAsDouble() throws Exception { 20 | 21 | OrderConfiguration orderConfiguration = orderConfiguration(); 22 | 23 | Fees fees = new Fees(orderConfiguration); 24 | 25 | assertThat(fees.getShippingFee()).isEqualTo(11); 26 | 27 | } 28 | 29 | 30 | @Test 31 | public void getVATOrShippingFeeShouldReturnNullWhenNoMatchingOrderConfiguration() throws Exception { 32 | 33 | Fees fees = new Fees(null); 34 | 35 | assertThat(fees.getShippingFee()).isEqualTo(null); 36 | assertThat(fees.getVAT()).isEqualTo(null); 37 | } 38 | 39 | private OrderConfiguration orderConfiguration() { 40 | return new OrderConfiguration("11.0", "19.6"); 41 | } 42 | } -------------------------------------------------------------------------------- /order/src/test/java/org/rembx/jeeshop/order/test/TestMailTemplate.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.test; 2 | 3 | import org.rembx.jeeshop.order.mail.Mails; 4 | import org.rembx.jeeshop.user.model.MailTemplate; 5 | import org.rembx.jeeshop.user.model.UserPersistenceUnit; 6 | 7 | import javax.persistence.EntityManager; 8 | import javax.persistence.Persistence; 9 | 10 | /** 11 | * MailTemplate test utility 12 | */ 13 | public class TestMailTemplate { 14 | 15 | private static TestMailTemplate instance; 16 | 17 | private static MailTemplate orderConfirmationTpl; 18 | 19 | 20 | public static TestMailTemplate getInstance() { 21 | if (instance != null) 22 | return instance; 23 | 24 | EntityManager entityManager = Persistence.createEntityManagerFactory(UserPersistenceUnit.NAME).createEntityManager(); 25 | 26 | entityManager.getTransaction().begin(); 27 | 28 | orderConfirmationTpl = new MailTemplate(Mails.orderValidated.name(), "fr_FR", "Hello ${gender} ${firstname} ${lastname}. Your order has been registered...", "Order Confirmation"); 29 | 30 | entityManager.persist(orderConfirmationTpl); 31 | 32 | entityManager.getTransaction().commit(); 33 | 34 | instance = new TestMailTemplate(); 35 | entityManager.close(); 36 | return instance; 37 | } 38 | 39 | public MailTemplate orderConfirmationMailTemplate(){ 40 | return orderConfirmationTpl; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /order/src/test/java/org/rembx/jeeshop/order/test/TestOrder.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.test; 2 | 3 | import com.google.common.collect.Sets; 4 | import org.rembx.jeeshop.order.model.Order; 5 | import org.rembx.jeeshop.order.model.OrderItem; 6 | import org.rembx.jeeshop.order.model.OrderStatus; 7 | import org.rembx.jeeshop.user.model.Address; 8 | import org.rembx.jeeshop.user.model.User; 9 | import org.rembx.jeeshop.user.model.UserPersistenceUnit; 10 | import org.rembx.jeeshop.user.test.TestUser; 11 | 12 | import javax.persistence.EntityManager; 13 | import javax.persistence.Persistence; 14 | 15 | /** 16 | * Created by remi on 30/11/14. 17 | */ 18 | public class TestOrder { 19 | 20 | private static TestOrder instance; 21 | 22 | private static Order order1; 23 | private static Order order2; 24 | 25 | private static OrderItem orderItem1; 26 | private static TestUser testUser; 27 | 28 | public static TestOrder getInstance() { 29 | if (instance != null) 30 | return instance; 31 | 32 | testUser = TestUser.getInstance(); 33 | 34 | EntityManager entityManager = Persistence.createEntityManagerFactory(UserPersistenceUnit.NAME).createEntityManager(); 35 | 36 | entityManager.getTransaction().begin(); 37 | 38 | Address deliveryAddress = new Address("21 Blue street", "Chicago", "78801", "John", "Doe", "M.", null, "FRA"); 39 | Address billingAddress = new Address("53 Green street", "Chicago", "78801", "John", "Doe", "M.", null, "FRA"); 40 | 41 | entityManager.persist(deliveryAddress); 42 | entityManager.persist(billingAddress); 43 | 44 | order1 = new Order(testUser.firstUser(), null, deliveryAddress, billingAddress, OrderStatus.PAYMENT_VALIDATED); 45 | orderItem1 = new OrderItem(1L, 1L, 2); 46 | orderItem1.setOrder(order1); 47 | 48 | order1.setItems(Sets.newHashSet(orderItem1)); 49 | entityManager.persist(order1); 50 | 51 | order2 = new Order(testUser.firstUser(), null, null, null, OrderStatus.CREATED); 52 | entityManager.persist(order2); 53 | 54 | entityManager.getTransaction().commit(); 55 | 56 | instance = new TestOrder(); 57 | entityManager.close(); 58 | return instance; 59 | } 60 | 61 | 62 | public Order firstOrder() { 63 | return order1; 64 | } 65 | 66 | public Order secondOrder() { 67 | return order2; 68 | } 69 | 70 | public User firstOrdersUser() { 71 | return order1.getUser(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /order/src/test/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | org.hibernate.jpa.HibernatePersistenceProvider 10 | org.rembx.jeeshop.user.model.Role 11 | org.rembx.jeeshop.user.model.User 12 | org.rembx.jeeshop.user.model.Address 13 | org.rembx.jeeshop.user.model.RoleName 14 | org.rembx.jeeshop.user.model.MailTemplate 15 | org.rembx.jeeshop.media.model.Media 16 | org.rembx.jeeshop.order.model.Order 17 | org.rembx.jeeshop.order.model.OrderItem 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | org.hibernate.jpa.HibernatePersistenceProvider 32 | org.rembx.jeeshop.catalog.model.Store 33 | org.rembx.jeeshop.catalog.model.Premises 34 | org.rembx.jeeshop.catalog.model.PremisesAddress 35 | org.rembx.jeeshop.catalog.model.PremisesOpeningSchedules 36 | org.rembx.jeeshop.user.model.Address 37 | org.rembx.jeeshop.catalog.model.Catalog 38 | org.rembx.jeeshop.catalog.model.Category 39 | org.rembx.jeeshop.catalog.model.Product 40 | org.rembx.jeeshop.catalog.model.SKU 41 | org.rembx.jeeshop.media.model.Media 42 | org.rembx.jeeshop.catalog.model.Presentation 43 | org.rembx.jeeshop.catalog.model.Discount 44 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /order/src/test/resources/global.properties: -------------------------------------------------------------------------------- 1 | # Available Countries 2 | countries.available=FRA,BEL,GBR,CHE 3 | -------------------------------------------------------------------------------- /order/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /user/src/main/asciidoc/rest-api.adoc: -------------------------------------------------------------------------------- 1 | == User REST API 2 | 3 | include::../../../../common/src/main/asciidoc/rest-api-general.adoc[] 4 | 5 | include::Users.adoc[] 6 | 7 | include::MailTemplates.adoc[] 8 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/order/model/OrderDiscount.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.model; 2 | 3 | import javax.persistence.*; 4 | import javax.validation.constraints.NotNull; 5 | 6 | /** 7 | * OrderDiscount entity 8 | */ 9 | 10 | @Embeddable 11 | public class OrderDiscount { 12 | 13 | public OrderDiscount() { 14 | } 15 | 16 | public OrderDiscount(Long discountId, Double discountValue) { 17 | this.discountId = discountId; 18 | this.discountValue = discountValue; 19 | } 20 | 21 | @NotNull 22 | @Column(name = "discount_id") 23 | private Long discountId; 24 | 25 | private Double discountValue; 26 | 27 | @Transient 28 | private String displayName; 29 | @Transient 30 | private String presentationImageURI; 31 | @Transient 32 | private Boolean rateType; 33 | 34 | public Long getDiscountId() { 35 | return discountId; 36 | } 37 | 38 | public void setDiscountId(Long discountId) { 39 | this.discountId = discountId; 40 | } 41 | 42 | public String getDisplayName() { 43 | return displayName; 44 | } 45 | 46 | public void setDisplayName(String displayName) { 47 | this.displayName = displayName; 48 | } 49 | 50 | public String getPresentationImageURI() { 51 | return presentationImageURI; 52 | } 53 | 54 | public void setPresentationImageURI(String presentationImageURI) { 55 | this.presentationImageURI = presentationImageURI; 56 | } 57 | 58 | public Double getDiscountValue() { 59 | return discountValue; 60 | } 61 | 62 | public void setDiscountValue(Double discountValue) { 63 | this.discountValue = discountValue; 64 | } 65 | 66 | public Boolean getRateType() { 67 | return rateType; 68 | } 69 | 70 | public void setRateType(Boolean rateType) { 71 | this.rateType = rateType; 72 | } 73 | 74 | @Override 75 | public boolean equals(Object o) { 76 | if (this == o) return true; 77 | if (o == null || getClass() != o.getClass()) return false; 78 | 79 | OrderDiscount that = (OrderDiscount) o; 80 | 81 | if (discountId != null ? !discountId.equals(that.discountId) : that.discountId != null) return false; 82 | if (discountValue != null ? !discountValue.equals(that.discountValue) : that.discountValue != null) 83 | return false; 84 | if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) return false; 85 | if (presentationImageURI != null ? !presentationImageURI.equals(that.presentationImageURI) : that.presentationImageURI != null) 86 | return false; 87 | 88 | return true; 89 | } 90 | 91 | @Override 92 | public int hashCode() { 93 | int result = discountId != null ? discountId.hashCode() : 0; 94 | result = 31 * result + (discountValue != null ? discountValue.hashCode() : 0); 95 | result = 31 * result + (displayName != null ? displayName.hashCode() : 0); 96 | result = 31 * result + (presentationImageURI != null ? presentationImageURI.hashCode() : 0); 97 | return result; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/order/model/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.model; 2 | 3 | /** 4 | * Statuses for Order lifecycle 5 | */ 6 | public enum OrderStatus { 7 | CREATED, VALIDATED, PAYMENT_VALIDATED, CANCELLED,READY_FOR_SHIPMENT, SHIPPED, DELIVERED, RETURNED 8 | } 9 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/order/model/PaymentInfo.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.model; 2 | 3 | import javax.xml.bind.annotation.XmlAccessType; 4 | import javax.xml.bind.annotation.XmlAccessorType; 5 | import javax.xml.bind.annotation.XmlType; 6 | 7 | @XmlType 8 | @XmlAccessorType(XmlAccessType.FIELD) 9 | public class PaymentInfo { 10 | 11 | /** 12 | * Used to store payment form response for Payment solutions such as SIPS. 13 | */ 14 | private String paymentFormResponse; 15 | 16 | public PaymentInfo() { 17 | } 18 | 19 | public PaymentInfo(String paymentFormResponse) { 20 | this.paymentFormResponse = paymentFormResponse; 21 | } 22 | 23 | public String getPaymentFormResponse() { 24 | return paymentFormResponse; 25 | } 26 | 27 | public void setPaymentFormResponse(String paymentFormResponse) { 28 | this.paymentFormResponse = paymentFormResponse; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | if (this == o) return true; 34 | if (o == null || getClass() != o.getClass()) return false; 35 | 36 | PaymentInfo that = (PaymentInfo) o; 37 | 38 | if (paymentFormResponse != null ? !paymentFormResponse.equals(that.paymentFormResponse) : that.paymentFormResponse != null) 39 | return false; 40 | 41 | return true; 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return paymentFormResponse != null ? paymentFormResponse.hashCode() : 0; 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/CountryChecker.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user; 2 | 3 | import org.rembx.jeeshop.configuration.NamedConfiguration; 4 | 5 | import javax.enterprise.context.ApplicationScoped; 6 | import javax.inject.Inject; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * User finder utility 11 | */ 12 | 13 | @ApplicationScoped 14 | public class CountryChecker { 15 | @Inject 16 | @NamedConfiguration(value = "countries.available",configurationFile = "/global.properties") 17 | private String availableCountriesStr; 18 | 19 | private String[] availableCountries; 20 | 21 | public CountryChecker() { 22 | } 23 | 24 | public CountryChecker(String availableCountries) { 25 | this.availableCountriesStr = availableCountries; 26 | } 27 | 28 | public boolean isAvailable(String country){ 29 | 30 | if (availableCountries == null){ 31 | availableCountries = availableCountriesStr.split(","); 32 | } 33 | return Arrays.asList(availableCountries).contains(country); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/MailTemplateFinder.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user; 2 | 3 | import com.querydsl.core.types.dsl.ComparableExpressionBase; 4 | import com.querydsl.jpa.impl.JPAQuery; 5 | import com.querydsl.jpa.impl.JPAQueryFactory; 6 | import io.quarkus.hibernate.orm.PersistenceUnit; 7 | import org.rembx.jeeshop.user.model.MailTemplate; 8 | import org.rembx.jeeshop.user.model.UserPersistenceUnit; 9 | 10 | import javax.annotation.Resource; 11 | import javax.enterprise.context.ApplicationScoped; 12 | import javax.enterprise.context.RequestScoped; 13 | import javax.inject.Inject; 14 | import javax.persistence.EntityManager; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | import static org.rembx.jeeshop.user.model.QMailTemplate.mailTemplate; 20 | 21 | /** 22 | * Newsletter finder utility 23 | */ 24 | @ApplicationScoped 25 | public class MailTemplateFinder { 26 | 27 | public final static String DEFAULT_LOCALE = "en_GB"; 28 | 29 | private EntityManager entityManager; 30 | 31 | private static final Map> sortProperties = new HashMap>() {{ 32 | put("id", mailTemplate.id); 33 | put("name", mailTemplate.name); 34 | put("locale", mailTemplate.locale); 35 | put("creationDate", mailTemplate.creationDate); 36 | put("updateDate", mailTemplate.updateDate); 37 | }}; 38 | 39 | public static MailTemplateFinder getInstance(EntityManager entityManager) { 40 | return new MailTemplateFinder(entityManager); 41 | } 42 | 43 | MailTemplateFinder( @PersistenceUnit(UserPersistenceUnit.NAME) EntityManager entityManager) { 44 | this.entityManager = entityManager; 45 | } 46 | 47 | public MailTemplate findByNameAndLocale(String name, String locale) { 48 | 49 | if (locale == null) { 50 | locale = DEFAULT_LOCALE; 51 | } 52 | 53 | return new JPAQueryFactory(entityManager) 54 | .selectFrom(mailTemplate).where( 55 | mailTemplate.name.eq(name) 56 | .and(mailTemplate.locale.eq(locale).or(mailTemplate.locale.startsWith(locale)))) 57 | .fetchOne(); 58 | } 59 | 60 | public List findByName(String name) { 61 | 62 | return new JPAQueryFactory(entityManager) 63 | .selectFrom(mailTemplate).where( 64 | mailTemplate.name.startsWith(name)) 65 | .fetch(); 66 | } 67 | 68 | public List findAll(Integer offset, Integer limit, String orderBy, Boolean isDesc) { 69 | JPAQuery query = new JPAQueryFactory(entityManager).selectFrom(mailTemplate); 70 | 71 | if (offset != null) 72 | query.offset(offset); 73 | if (limit != null) 74 | query.limit(limit); 75 | 76 | sortBy(orderBy, isDesc, query); 77 | 78 | return query.fetch(); 79 | 80 | } 81 | 82 | public Long countAll() { 83 | JPAQuery query = new JPAQueryFactory(entityManager).selectFrom(mailTemplate); 84 | return query.fetchCount(); 85 | } 86 | 87 | private void sortBy(String orderby, Boolean isDesc, JPAQuery query) { 88 | if (orderby != null && sortProperties.containsKey(orderby)) { 89 | if (isDesc) { 90 | query.orderBy(sortProperties.get(orderby).desc()); 91 | } else { 92 | query.orderBy(sortProperties.get(orderby).asc()); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/RoleFinder.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import io.quarkus.hibernate.orm.PersistenceUnit; 5 | import org.rembx.jeeshop.user.model.Role; 6 | import org.rembx.jeeshop.user.model.RoleName; 7 | import org.rembx.jeeshop.user.model.UserPersistenceUnit; 8 | 9 | import javax.enterprise.context.ApplicationScoped; 10 | import javax.enterprise.context.RequestScoped; 11 | import javax.persistence.EntityManager; 12 | 13 | import static org.rembx.jeeshop.user.model.QRole.role; 14 | 15 | /** 16 | * User finder utility 17 | */ 18 | @ApplicationScoped 19 | public class RoleFinder { 20 | 21 | private EntityManager entityManager; 22 | 23 | RoleFinder(@PersistenceUnit(UserPersistenceUnit.NAME) EntityManager entityManager) { 24 | this.entityManager = entityManager; 25 | } 26 | 27 | public Role findByName(RoleName name) { 28 | return new JPAQueryFactory(entityManager) 29 | .selectFrom(role).where( 30 | role.name.eq(name)) 31 | .fetchOne(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/mail/Mails.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.mail; 2 | 3 | public enum Mails { 4 | userRegistration, 5 | userActivation, 6 | userResetPassword, 7 | userChangePassword 8 | } 9 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/model/Email.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.model; 2 | 3 | import javax.validation.Constraint; 4 | import javax.validation.Payload; 5 | import javax.validation.ReportAsSingleViolation; 6 | import javax.validation.constraints.Pattern; 7 | import javax.validation.constraints.Size; 8 | import java.lang.annotation.Documented; 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.Target; 11 | 12 | import static java.lang.annotation.ElementType.*; 13 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 14 | 15 | @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) 16 | @Retention(RUNTIME) 17 | @Documented 18 | @Size(min = 5) 19 | @Pattern(regexp = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\." 20 | + "[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*" 21 | + "@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") 22 | @ReportAsSingleViolation 23 | @Constraint(validatedBy = {}) 24 | public @interface Email { 25 | 26 | String message() default "email"; 27 | 28 | Class[] groups() default {}; 29 | 30 | Class[] payload() default {}; 31 | 32 | @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) 33 | @Retention(RUNTIME) 34 | @interface List { 35 | Email[] value(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/model/Phone.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.model; 2 | 3 | import javax.validation.Constraint; 4 | import javax.validation.Payload; 5 | import javax.validation.ReportAsSingleViolation; 6 | import javax.validation.constraints.NotNull; 7 | import javax.validation.constraints.Pattern; 8 | import javax.validation.constraints.Size; 9 | import java.lang.annotation.Documented; 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | 13 | import static java.lang.annotation.ElementType.FIELD; 14 | import static java.lang.annotation.ElementType.METHOD; 15 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 16 | 17 | @Size(max = 15) 18 | @Pattern(regexp = "\\+?[0-9\\s]+") 19 | @ReportAsSingleViolation 20 | @Target({METHOD, FIELD}) 21 | @Retention(RUNTIME) 22 | @Documented 23 | public @interface Phone { 24 | 25 | // ====================================== 26 | // = Attributes = 27 | // ====================================== 28 | 29 | String message() default "phone"; 30 | 31 | Class[] groups() default {}; 32 | 33 | Class[] payload() default {}; 34 | } 35 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/model/Role.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.model; 2 | 3 | import javax.persistence.*; 4 | import javax.validation.constraints.NotNull; 5 | import javax.validation.constraints.Size; 6 | 7 | /** 8 | * Created by remi on 03/06/14. 9 | */ 10 | @Entity 11 | @Table(name = "`role`") 12 | public class Role { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Long id; 17 | 18 | @NotNull 19 | @Column(unique = true, nullable = false) 20 | @Enumerated(EnumType.STRING) 21 | private RoleName name; 22 | 23 | public Role() { 24 | } 25 | 26 | public Role(RoleName name) { 27 | this.name = name; 28 | } 29 | 30 | public Long getId() { 31 | return id; 32 | } 33 | 34 | 35 | public RoleName getName() { 36 | return name; 37 | } 38 | 39 | public void setName(RoleName role) { 40 | this.name = role; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (o == null || getClass() != o.getClass()) return false; 47 | 48 | Role role1 = (Role) o; 49 | 50 | if (id != null ? !id.equals(role1.id) : role1.id != null) return false; 51 | if (name != null ? !name.equals(role1.name) : role1.name != null) return false; 52 | 53 | return true; 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | int result = id != null ? id.hashCode() : 0; 59 | result = 31 * result + (name != null ? name.hashCode() : 0); 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/model/RoleName.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.model; 2 | 3 | 4 | public enum RoleName { 5 | user, 6 | admin, 7 | store_admin 8 | } 9 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/model/UserPersistenceUnit.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.model; 2 | 3 | /** 4 | * Created by remi on 25/05/14. 5 | */ 6 | public interface UserPersistenceUnit { 7 | public final static String NAME = "User"; 8 | } 9 | -------------------------------------------------------------------------------- /user/src/main/java/org/rembx/jeeshop/user/tools/CryptTools.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.tools; 2 | 3 | import com.google.common.hash.Hashing; 4 | import org.apache.commons.codec.binary.Base64; 5 | 6 | public class CryptTools { 7 | 8 | public static String hashSha256Base64(String strToHash) { 9 | byte[] digest = Hashing.sha256().hashBytes(strToHash.getBytes()).asBytes(); 10 | return Base64.encodeBase64String(digest); 11 | } 12 | } -------------------------------------------------------------------------------- /user/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /user/src/main/resources/ValidationMessages.properties: -------------------------------------------------------------------------------- 1 | login=Format incorrect 2 | phone=Format incorrect 3 | email=Format incorrect -------------------------------------------------------------------------------- /user/src/test/java/org/rembx/jeeshop/order/model/OrderTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.order.model; 2 | 3 | 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.text.SimpleDateFormat; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | 11 | public class OrderTest { 12 | 13 | Order order; 14 | 15 | @Test 16 | public void testPrePersist() throws Exception { 17 | Order order = new Order(); 18 | 19 | assertThat(order.getUpdateDate()).isNull(); 20 | order.prePersist(); 21 | assertThat(order.getUpdateDate()).isNotNull(); 22 | } 23 | 24 | @Test 25 | public void testPreUpdate() throws Exception { 26 | Order order = new Order(); 27 | 28 | assertThat(order.getCreationDate()).isNull(); 29 | assertThat(order.getUpdateDate()).isNull(); 30 | order.prePersist(); 31 | assertThat(order.getCreationDate()).isNotNull(); 32 | assertThat(order.getUpdateDate()).isNotNull(); 33 | } 34 | 35 | @Test 36 | public void computeOrderReference_orderWithoutTransactionId() throws Exception { 37 | order = new Order(); 38 | order.setId(1L); 39 | order.setCreationDate(new SimpleDateFormat("MMddyyyy").parse("11222222")); 40 | 41 | assertThat(order.getReference()).isNull(); 42 | order.computeOrderReference(); 43 | assertThat(order.getReference()).isEqualTo("11222222-1"); 44 | } 45 | 46 | @Test 47 | public void computeOrderReference_orderWithTransactionId() throws Exception { 48 | order = new Order(); 49 | order.setId(1L); 50 | order.setCreationDate(new SimpleDateFormat("MMddyyyy").parse("11222222")); 51 | order.setTransactionId("1234"); 52 | order.computeOrderReference(); 53 | 54 | assertThat(order.getReference()).isEqualTo("11222222-1-1234"); 55 | } 56 | } -------------------------------------------------------------------------------- /user/src/test/java/org/rembx/jeeshop/user/test/TestMailTemplate.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.test; 2 | 3 | import org.rembx.jeeshop.user.mail.Mails; 4 | import org.rembx.jeeshop.user.model.MailTemplate; 5 | import org.rembx.jeeshop.user.model.UserPersistenceUnit; 6 | 7 | import javax.persistence.EntityManager; 8 | import javax.persistence.Persistence; 9 | 10 | /** 11 | * MailTemplate test utility 12 | */ 13 | public class TestMailTemplate { 14 | 15 | private static TestMailTemplate instance; 16 | 17 | private static MailTemplate mailTemplate1; 18 | private static MailTemplate userRegistrationMailTpl; 19 | private static MailTemplate ressetPasswordMailTpl; 20 | private static MailTemplate changePasswordMailTpl; 21 | 22 | public static TestMailTemplate getInstance() { 23 | if (instance != null) 24 | return instance; 25 | 26 | EntityManager entityManager = Persistence.createEntityManagerFactory(UserPersistenceUnit.NAME).createEntityManager(); 27 | 28 | entityManager.getTransaction().begin(); 29 | 30 | mailTemplate1 = new MailTemplate("Newsletter1", "fr_FR", "bla bla...", "Hello Subject"); 31 | userRegistrationMailTpl = new MailTemplate(Mails.userRegistration.name(), "fr_FR", "Welcome ${gender} ${firstname} ${lastname}", "New Registration Subject"); 32 | ressetPasswordMailTpl = new MailTemplate(Mails.userResetPassword.name(), "fr_FR", "Here is the link to reset your password", "Reset Password Subject"); 33 | changePasswordMailTpl = new MailTemplate(Mails.userChangePassword.name(), "fr_FR", "Hello there, your password has changed!", "Change Password Subject"); 34 | 35 | entityManager.persist(mailTemplate1); 36 | entityManager.persist(userRegistrationMailTpl); 37 | entityManager.persist(ressetPasswordMailTpl); 38 | entityManager.persist(changePasswordMailTpl); 39 | 40 | entityManager.getTransaction().commit(); 41 | 42 | instance = new TestMailTemplate(); 43 | entityManager.close(); 44 | return instance; 45 | } 46 | 47 | 48 | public MailTemplate firstMailTemplate() { 49 | return mailTemplate1; 50 | } 51 | 52 | public MailTemplate userRegistrationMailTemplate(){ 53 | return userRegistrationMailTpl; 54 | } 55 | 56 | public MailTemplate resetPasswordMailTemplate(){ 57 | return ressetPasswordMailTpl; 58 | } 59 | 60 | public MailTemplate changePasswordMailTpl(){ 61 | return changePasswordMailTpl; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /user/src/test/java/org/rembx/jeeshop/user/test/TestUser.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.test; 2 | 3 | import org.rembx.jeeshop.user.model.*; 4 | 5 | import javax.persistence.EntityManager; 6 | import javax.persistence.Persistence; 7 | import java.sql.Timestamp; 8 | import java.time.ZonedDateTime; 9 | import java.util.Date; 10 | 11 | /** 12 | * User test utility 13 | */ 14 | public class TestUser { 15 | 16 | private static TestUser instance; 17 | 18 | private static User user1; 19 | 20 | // Date are initialized with java.sql.Timestamp as JPA get a Timestamp instance 21 | private final static Date now = Timestamp.from(ZonedDateTime.now().toInstant()); 22 | private final static Date yesterday = Timestamp.from(ZonedDateTime.now().minusDays(1).toInstant()); 23 | 24 | public static TestUser getInstance() { 25 | if (instance != null) 26 | return instance; 27 | 28 | EntityManager entityManager = Persistence.createEntityManagerFactory(UserPersistenceUnit.NAME).createEntityManager(); 29 | 30 | entityManager.getTransaction().begin(); 31 | 32 | Address address = new Address("21 Blue street", "Chicago", "78801", "John", "Doe","M.",null, "FRA"); 33 | user1 = new User("test@test.com", "test", "John", "Doe", "+33616161616",null,yesterday,"fr_FR",null); 34 | user1.setGender("M."); 35 | 36 | entityManager.persist(address); 37 | entityManager.persist(user1); 38 | 39 | Role adminRole = new Role(RoleName.admin); 40 | Role userRole = new Role(RoleName.user); 41 | entityManager.persist(adminRole); 42 | entityManager.persist(userRole); 43 | 44 | entityManager.getTransaction().commit(); 45 | 46 | instance = new TestUser(); 47 | entityManager.close(); 48 | return instance; 49 | } 50 | 51 | 52 | public User firstUser() { 53 | return user1; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /user/src/test/java/org/rembx/jeeshop/user/tools/CryptToolsTest.java: -------------------------------------------------------------------------------- 1 | package org.rembx.jeeshop.user.tools; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | public class CryptToolsTest { 8 | 9 | @Test 10 | public void testHashSha256Base64() throws Exception { 11 | assertThat(CryptTools.hashSha256Base64("jeeshop")).isEqualTo("DjYu7nlNFk6BdxO+LwxZJ3mBAfxgwytTS2cVRbmnIO8="); 12 | } 13 | } -------------------------------------------------------------------------------- /user/src/test/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | org.hibernate.jpa.HibernatePersistenceProvider 10 | org.rembx.jeeshop.user.model.Role 11 | org.rembx.jeeshop.user.model.User 12 | org.rembx.jeeshop.user.model.Address 13 | org.rembx.jeeshop.user.model.RoleName 14 | org.rembx.jeeshop.user.model.MailTemplate 15 | org.rembx.jeeshop.media.model.Media 16 | org.rembx.jeeshop.order.model.Order 17 | org.rembx.jeeshop.order.model.OrderItem 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /user/src/test/resources/global.properties: -------------------------------------------------------------------------------- 1 | # Available Countries 2 | countries.available=FRA,BEL,GBR,CHE 3 | -------------------------------------------------------------------------------- /user/src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | --------------------------------------------------------------------------------