From 5bcc6820bb0fd31e28d20da3b97d3761fc03404c Mon Sep 17 00:00:00 2001 From: Cezary Olejarczyk Date: Thu, 16 Nov 2017 15:12:35 +0100 Subject: [PATCH] Updated vendors for 2.0.0 --- .gitlab-ci.yml | 29 + .travis.yml | 4 +- CHANGELOG.md | 18 + README.md | 38 +- backend/.gitignore | 4 +- backend/Dockerfile | 48 - backend/app/config/config.yml | 1 + backend/app/config/parameters.yml.dist | 1 + backend/bin/symfony_requirements | 2 +- backend/build.xml | 10 +- backend/composer.json | 6 +- backend/composer.lock | 207 +- backend/docker/mpm-prefork-module.conf | 3 - backend/docker/rancher/entrypoint.sh | 12 - backend/docker/rancher/prod_entrypoint.sh | 12 - backend/docker/rancher/test_entrypoint.sh | 13 - backend/docker/vhost.conf | 26 - backend/web/config.php | 2 +- docker-compose.dev.yml | 8 - docker-compose.test.yml | 3 - docker-compose.yml | 33 - docker-compose_prod.yml | 37 - docker/.env | 11 + docker/base/build_dev.sh | 6 + docker/base/nginx-dockerfile | 4 + docker/base/nodejs-dockerfile | 6 + docker/base/php-fpm-dockerfile | 10 + {backend/docker => docker/base}/php.ini | 2 +- docker/base/scripts/php-configure.sh | 11 + docker/ci/php/fpm-dockerfile | 16 + docker/dev/php/fpm-dockerfile | 24 + {backend/docker => docker/dev/php}/xdebug.ini | 2 +- docker/dev/web/backend-dockerfile | 6 + docker/dev/web/backend.conf | 37 + docker/dev/web/config.js | 16 + docker/dev/web/front-dockerfile | 13 + docker/dev/web/parameters.json | 8 + docker/docker-compose.dev.yml | 33 + docker/docker-compose.test.yml | 8 + docker/docker-compose.yml | 41 + docker/prod/php/bin/init.sh | 30 + docker/prod/php/conf/crontab.txt | 3 + .../php/conf/supervisord/conf.d/cron.conf | 4 + .../php/conf/supervisord/conf.d/php-fpm.conf | 12 + .../php/conf/supervisord/supervisord.conf | 27 + docker/prod/php/fpm-dockerfile | 26 + docker/prod/web/app-dockerfile | 17 + docker/prod/web/backend.conf | 36 + docker/prod/web/bin/init.sh | 5 + docker/prod/web/frontend.conf | 23 + docker/prod/web/parameters.json | 8 + frontend/.eslintrc | 26 + frontend/.gitignore | 6 + frontend/.sass-lint.yml | 49 + frontend/Dockerfile | 11 - frontend/config.js.dist | 2 - frontend/dev/accessibility-validation.js | 14 + frontend/dev/html-validator.js | 31 + frontend/dev/sassdoc.js | 6 + frontend/docs/index.html | 16 + frontend/docs/main.js | 0 frontend/karma.conf.js | 93 +- frontend/package.json | 99 +- frontend/postcss.config.js | 8 + frontend/rancher/entrypoint.sh | 4 + frontend/src/appAdmin.js | 148 +- frontend/src/appClient.js | 274 + frontend/src/appPos.js | 258 + .../global/boxLoader/BoxLoaderDirective.js | 4 +- .../global/checkbox/CheckboxDirective.js | 4 +- .../global/csv/CsvUploadDirective.js | 4 +- .../global/filereader/FileModelDirective.js | 4 +- .../src/component/global/filters/Filters.js | 7 +- .../src/component/global/map/EditableMap.js | 4 +- .../component/global/modal/ModalDirective.js | 4 +- .../global/pages/StaticPagesDirective.js | 5 +- .../global/pages/templates/static-pages.html | 4 +- .../global/security/SecurityController.js | 2 +- .../spinnerLoader/SpinnerLoaderDirective.js | 4 +- .../validation/FormValidationDirective.js | 4 +- frontend/src/img/ol_ban_1.jpg | Bin 0 -> 85657 bytes frontend/src/img/ol_ban_10.jpg | Bin 0 -> 79582 bytes frontend/src/img/ol_ban_2.jpg | Bin 0 -> 51484 bytes frontend/src/img/ol_ban_3.jpg | Bin 0 -> 42310 bytes frontend/src/img/ol_ban_4.jpg | Bin 0 -> 60844 bytes frontend/src/img/ol_ban_5.jpg | Bin 0 -> 28755 bytes frontend/src/img/ol_ban_6.jpg | Bin 0 -> 72255 bytes frontend/src/img/ol_ban_7.jpg | Bin 0 -> 66206 bytes frontend/src/img/ol_ban_8.jpg | Bin 0 -> 89754 bytes frontend/src/img/ol_ban_9.jpg | Bin 0 -> 74366 bytes .../admin.campaign/CampaignController.js | 2 +- frontend/src/modules/admin.campaign/module.js | 68 +- .../admin.customers/CustomerController.js | 2 +- .../src/modules/admin.customers/module.js | 124 +- .../templates/single-customer.html | 2 +- .../admin.dashboard/DashboardController.js | 2 +- .../src/modules/admin.dashboard/module.js | 16 +- .../modules/admin.data/AdminDataController.js | 2 +- frontend/src/modules/admin.data/module.js | 16 +- .../src/modules/admin.earning-rules/module.js | 44 +- frontend/src/modules/admin.emails/module.js | 30 +- frontend/src/modules/admin.levels/module.js | 58 +- frontend/src/modules/admin.login/module.js | 2 +- frontend/src/modules/admin.logs/module.js | 16 +- frontend/src/modules/admin.partials/module.js | 45 +- frontend/src/modules/admin.pos/module.js | 44 +- .../admin.segment/SegmentPartDirective.js | 7 +- frontend/src/modules/admin.segment/module.js | 164 +- frontend/src/modules/admin.seller/module.js | 44 +- .../admin.settings/SettingsController.js | 2 +- frontend/src/modules/admin.settings/module.js | 16 +- .../templates/admin-settings.html | 2 +- .../src/modules/admin.transactions/module.js | 16 +- .../src/modules/admin.transfers/module.js | 16 +- .../src/modules/admin.translations/module.js | 44 +- frontend/src/modules/admin.users/module.js | 44 +- .../src/modules/client.campaign/module.js | 28 +- .../src/modules/client.dashboard/module.js | 16 +- .../templates/customer-dashboard.html | 43 +- .../modules/client.earning-rules/module.js | 16 +- frontend/src/modules/client.login/module.js | 16 +- .../src/modules/client.partials/module.js | 6 +- .../templates/client-footer.html | 15 + .../templates/client-top-nav.html | 66 + frontend/src/modules/client.profile/module.js | 31 +- .../src/modules/client.registration/module.js | 78 +- .../src/modules/client.transactions/module.js | 16 +- .../src/modules/client.transfers/module.js | 16 +- frontend/src/modules/pos.campaigns/module.js | 30 +- .../pos.customers/SellerCustomerService.js | 2 +- frontend/src/modules/pos.customers/module.js | 115 +- frontend/src/modules/pos.dashboard/module.js | 16 +- .../src/modules/pos.earning-rules/module.js | 16 +- frontend/src/modules/pos.login/module.js | 44 +- .../templates/seller-password-request.html | 43 + .../templates/seller-password-reset.html | 43 + frontend/src/modules/pos.partials/module.js | 5 +- .../pos.partials/templates/pos-top-nav.html | 29 + .../src/modules/pos.transactions/module.js | 30 +- frontend/src/scripts/main.js | 2 +- frontend/src/style/_icon_set_1.scss | 2 +- frontend/src/style/_icon_set_2.scss | 2 +- frontend/src/style/main.scss | 6 +- frontend/src/style/static-pages.scss | 6 +- frontend/src/templates/admin.html | 98 + frontend/src/templates/client.html | 87 + frontend/src/templates/pos.html | 86 + frontend/test/HelloWorldTest.js | 11 + frontend/test/loadtests.js | 5 + frontend/webpack.config.js | 111 + frontend/webpack.docs.config.js | 9 + frontend/yarn.lock | 7936 +++++++++-------- kubernetes/README.rst | 74 + kubernetes/claims.yml | 76 + kubernetes/config.yml | 23 + kubernetes/deployment.yml | 343 + kubernetes/development.rst | 87 + kubernetes/storage.yml | 75 + 158 files changed, 7715 insertions(+), 4929 deletions(-) delete mode 100644 backend/Dockerfile delete mode 100644 backend/docker/mpm-prefork-module.conf delete mode 100644 backend/docker/rancher/entrypoint.sh delete mode 100644 backend/docker/rancher/prod_entrypoint.sh delete mode 100644 backend/docker/rancher/test_entrypoint.sh delete mode 100644 backend/docker/vhost.conf delete mode 100644 docker-compose.dev.yml delete mode 100644 docker-compose.test.yml delete mode 100644 docker-compose.yml delete mode 100644 docker-compose_prod.yml create mode 100644 docker/.env create mode 100755 docker/base/build_dev.sh create mode 100644 docker/base/nginx-dockerfile create mode 100644 docker/base/nodejs-dockerfile create mode 100644 docker/base/php-fpm-dockerfile rename {backend/docker => docker/base}/php.ini (71%) create mode 100644 docker/base/scripts/php-configure.sh create mode 100644 docker/ci/php/fpm-dockerfile create mode 100644 docker/dev/php/fpm-dockerfile rename {backend/docker => docker/dev/php}/xdebug.ini (84%) create mode 100644 docker/dev/web/backend-dockerfile create mode 100644 docker/dev/web/backend.conf create mode 100644 docker/dev/web/config.js create mode 100644 docker/dev/web/front-dockerfile create mode 100644 docker/dev/web/parameters.json create mode 100644 docker/docker-compose.dev.yml create mode 100644 docker/docker-compose.test.yml create mode 100644 docker/docker-compose.yml create mode 100644 docker/prod/php/bin/init.sh create mode 100644 docker/prod/php/conf/crontab.txt create mode 100644 docker/prod/php/conf/supervisord/conf.d/cron.conf create mode 100644 docker/prod/php/conf/supervisord/conf.d/php-fpm.conf create mode 100644 docker/prod/php/conf/supervisord/supervisord.conf create mode 100644 docker/prod/php/fpm-dockerfile create mode 100644 docker/prod/web/app-dockerfile create mode 100644 docker/prod/web/backend.conf create mode 100755 docker/prod/web/bin/init.sh create mode 100644 docker/prod/web/frontend.conf create mode 100644 docker/prod/web/parameters.json create mode 100644 frontend/.eslintrc create mode 100644 frontend/.gitignore create mode 100644 frontend/.sass-lint.yml delete mode 100644 frontend/Dockerfile delete mode 100644 frontend/config.js.dist create mode 100644 frontend/dev/accessibility-validation.js create mode 100644 frontend/dev/html-validator.js create mode 100644 frontend/dev/sassdoc.js create mode 100644 frontend/docs/index.html create mode 100644 frontend/docs/main.js create mode 100644 frontend/postcss.config.js create mode 100644 frontend/rancher/entrypoint.sh create mode 100644 frontend/src/appClient.js create mode 100644 frontend/src/appPos.js create mode 100644 frontend/src/img/ol_ban_1.jpg create mode 100644 frontend/src/img/ol_ban_10.jpg create mode 100644 frontend/src/img/ol_ban_2.jpg create mode 100644 frontend/src/img/ol_ban_3.jpg create mode 100644 frontend/src/img/ol_ban_4.jpg create mode 100644 frontend/src/img/ol_ban_5.jpg create mode 100644 frontend/src/img/ol_ban_6.jpg create mode 100644 frontend/src/img/ol_ban_7.jpg create mode 100644 frontend/src/img/ol_ban_8.jpg create mode 100644 frontend/src/img/ol_ban_9.jpg create mode 100644 frontend/src/modules/client.partials/templates/client-footer.html create mode 100644 frontend/src/modules/client.partials/templates/client-top-nav.html create mode 100644 frontend/src/modules/pos.login/templates/seller-password-request.html create mode 100644 frontend/src/modules/pos.login/templates/seller-password-reset.html create mode 100644 frontend/src/modules/pos.partials/templates/pos-top-nav.html create mode 100644 frontend/src/templates/admin.html create mode 100644 frontend/src/templates/client.html create mode 100644 frontend/src/templates/pos.html create mode 100644 frontend/test/HelloWorldTest.js create mode 100644 frontend/test/loadtests.js create mode 100644 frontend/webpack.config.js create mode 100644 frontend/webpack.docs.config.js create mode 100644 kubernetes/README.rst create mode 100644 kubernetes/claims.yml create mode 100644 kubernetes/config.yml create mode 100644 kubernetes/deployment.yml create mode 100644 kubernetes/development.rst create mode 100644 kubernetes/storage.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4a2417ba..672f3b21 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,3 +34,32 @@ php-7.0: - bin/console doctrine:schema:validate --env=test --skip-sync - vendor/phpunit/phpunit/phpunit - bin/php-cs-fixer fix --dry-run --diff src + +php-7.1: + image: tetraweb/php:7.1 + stage: test + services: + - elasticsearch:2.2 + - postgres:9 + script: + - echo "memory_limit = 512M" > /usr/local/etc/php/conf.d/memory.ini + - cd backend + - mkdir app/var + - mkdir app/var/jwt + - openssl genrsa -out app/var/jwt/private.pem 4096 + - openssl rsa -pubout -in app/var/jwt/private.pem -out app/var/jwt/public.pem + - docker-php-ext-enable zip pdo pgsql pdo_pgsql mbstring intl bcmath + - "sed -i 's/database_host: .*/database_host: postgres/g' app/config/parameters.yml.dist" + - "sed -i 's/elastica_host: .*/elastica_host: elasticsearch/g' app/config/parameters.yml.dist" + - composer self-update + - composer install + - bin/console oloy:user:projections:index:create --drop-old + - bin/console doctrine:schema:update --env=test -n --force + - bin/console broadway:event-store:schema:drop + - bin/console broadway:event-store:schema:init + - bin/console doctrine:fixtures:load --env=test -n + - bin/console assets:install --env=test + - bin/console security:check + - bin/console doctrine:schema:validate --env=test --skip-sync + - vendor/phpunit/phpunit/phpunit + - bin/php-cs-fixer fix --dry-run --diff src diff --git a/.travis.yml b/.travis.yml index 79a3f66f..1c5584f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,12 @@ services: - docker before_install: + - sudo apt-get update + - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce - sudo rm /usr/local/bin/docker-compose - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose - chmod +x docker-compose - sudo mv docker-compose /usr/local/bin script: - - docker-compose -f docker-compose.yml -f docker-compose.test.yml run backend \ No newline at end of file + - cd docker && docker-compose -f docker-compose.yml -f docker-compose.test.yml run php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4721ed08..996f9104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [2.0.0] - 2017-11-016 +### Added +- Kubernetes support +### Changed +- Docker files +- Frontend migration from Gulp to the Webpack +- Migration from Nodejs server to the Nginx + +## [1.4.0] - 2017-11-07 +### Added +- CLI command to restore read model using event store +### Fixed +- AC/POSC fixed transaction id +- AC/POSC show points for each transaction +- AC clear fields after changing event type +- POSC fixed missing days from last order +- CC fixed cancel button + ## [1.3.1] - 2017-10-23 ### Added - Added change log file diff --git a/README.md b/README.md index 4437242e..0669a48c 100644 --- a/README.md +++ b/README.md @@ -23,22 +23,22 @@ There is variety of applications for Open Loyalty. Based on it you can build loy This project has full support for running in [Docker](https://www.docker.com/>). -Execute bellow command to run application: +Go to the docker directory: ``` -docker-compose up +cd docker ``` -or, if you are developer and want to attach source code then: +Execute bellow command to run application: ``` -docker-compose -f docker-compose.yml -f docker-compose.dev.yml up +docker-compose up ``` Then use another command to setup database, Elasticsearch and load some demo data: ``` -docker-compose exec backend phing setup +docker-compose exec php phing setup ``` If you find any problems using docker (for example on Windows environments) please try our Vagrant recipe. @@ -52,23 +52,17 @@ Then, please execute following commands: ``` vagrant up vagrant ssh -cd ol +cd ol/docker docker-compose up -d -docker-compose exec backend phing demo +docker-compose exec open_loyalty_backend phing demo ``` That's all. Now you can go to admin panel [127.0.0.1:8182](http://127.0.0.1:8182). Default login is **admin** and password **open**. You can also go to customer panel [127.0.0.1:8183](http://127.0.0.1:8183). -If you are developer and want to attach source code then: - -``` -docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -``` - ## Url access -After starting Open Loyalty it's exposes services under followig URLs: +After starting Open Loyalty it's exposes services under following URLs: * http://localhost:8182 - the administration panel, * http://localhost:8183 - the customer panel, @@ -76,7 +70,23 @@ After starting Open Loyalty it's exposes services under followig URLs: * http://localhost:8181 - RESTful API port * http://localhost:8181/doc - swagger-like API doc +If you are developer and want to attach source code then: +``` +cd docker/base +./build_dev.sh +cd .. +docker-compose -f docker-compose.yml -f docker-compose.dev.yml up +``` + +## Url access for developer +After starting Open Loyalty in developer mode it's exposes services under slightly different URLs: + + * http://localhost:8081/admin - the administration panel, + * http://localhost:8081/client - the customer panel, + * http://localhost:8081/pos - the merchant panel, + * http://localhost:8181 - RESTful API port + * http://localhost:8181/app_dev.php/doc - swagger-like API doc ## Generate JWT keys diff --git a/backend/.gitignore b/backend/.gitignore index ea6a5a4c..5218deaf 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -14,4 +14,6 @@ !var/SymfonyRequirements.php /vendor/ /web/bundles/ -app/var/jwt/ \ No newline at end of file +app/var/jwt/ +bin/symfony_requirements +web/config.php diff --git a/backend/Dockerfile b/backend/Dockerfile deleted file mode 100644 index bd20b819..00000000 --- a/backend/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM php:7.0-apache - -RUN apt-get update \ - && apt-get install -y locales libicu-dev zlib1g-dev libghc-postgresql-libpq-dev git phpunit libcurl4-openssl-dev \ - && locale-gen C.UTF-8 \ - && /usr/sbin/update-locale LANG=C.UTF-8 \ - && apt-get autoremove -y \ - && apt-get clean all - -RUN docker-php-ext-configure pgsql -with-pgsql=/usr/include/postgresql/ \ - && docker-php-ext-install pdo pgsql pdo_pgsql pdo_mysql mysqli intl opcache bcmath zip curl -RUN docker-php-ext-enable curl -RUN usermod --non-unique --uid 1000 www-data - -RUN pecl install xdebug && docker-php-ext-enable xdebug - -ADD https://www.phing.info/get/phing-latest.phar /usr/local/bin/phing -COPY docker/mpm-prefork-module.conf /etc/apache2/conf-available/mpm-prefork-module.conf -COPY docker/vhost.conf /etc/apache2/sites-enabled/000-default.conf -COPY docker/php.ini /usr/local/etc/php/php.ini - -RUN a2enmod rewrite headers -RUN a2enconf mpm-prefork-module - -RUN chmod +x /usr/local/bin/phing - -RUN mkdir -p /var/www/ol/backend -COPY . /var/www/ol/backend -ADD docker/rancher/entrypoint.sh /rancher_entrypoint.sh -RUN chmod +x /rancher_entrypoint.sh -ADD docker/rancher/prod_entrypoint.sh /rancher_prod_entrypoint.sh -RUN chmod +x /rancher_prod_entrypoint.sh -ADD docker/rancher/test_entrypoint.sh /rancher_test_entrypoint.sh -RUN chmod +x /rancher_test_entrypoint.sh -WORKDIR /var/www/ol/backend -RUN chmod -R 777 /var/www/ol/backend/var && \ - chown -R www-data:www-data /var/www/ol/backend/app/uploads && \ - chmod -R 777 /var/www/ol/backend/app/uploads && \ - chown -R www-data:www-data /var/www/ol/backend/app/Resources/frontend_translations && \ - chmod -R 777 /var/www/ol/backend/app/Resources/frontend_translations - -RUN cp /var/www/ol/backend/app/config/parameters.yml.dist /var/www/ol/backend/app/config/parameters.yml -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && php composer-setup.php \ - && php -r "unlink('composer-setup.php');" \ - && mv composer.phar /usr/local/bin/composer - -CMD composer install -o --prefer-dist && bin/console assets:install --symlink && chown -R www-data:www-data /var/www/ol/backend/var && chown -R www-data:www-data /var/www/ol/backend/app/uploads && apache2-foreground diff --git a/backend/app/config/config.yml b/backend/app/config/config.yml index 84e0a7e8..25cd078b 100644 --- a/backend/app/config/config.yml +++ b/backend/app/config/config.yml @@ -53,6 +53,7 @@ doctrine: default_connection: default connections: default: + server_version: "%database_version%" driver: "%database_driver%" host: "%database_host%" port: "%database_port%" diff --git a/backend/app/config/parameters.yml.dist b/backend/app/config/parameters.yml.dist index db63061c..5d9a3588 100644 --- a/backend/app/config/parameters.yml.dist +++ b/backend/app/config/parameters.yml.dist @@ -8,6 +8,7 @@ parameters: database_user: openloyalty database_password: openloyalty database_driver: pdo_pgsql + database_version: 9 elastica_host: elk elastica_port: 9200 # You should uncomment this if you want use pdo_sqlite diff --git a/backend/bin/symfony_requirements b/backend/bin/symfony_requirements index eeead326..a7bf65a1 100755 --- a/backend/bin/symfony_requirements +++ b/backend/bin/symfony_requirements @@ -1,7 +1,7 @@ #!/usr/bin/env php - + - + @@ -31,17 +31,17 @@ - + - + - + diff --git a/backend/composer.json b/backend/composer.json index b6189cc5..5ee3f362 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -17,7 +17,7 @@ } }, "require": { - "php": ">=5.5.9", + "php": ">=7.0", "symfony/symfony": "3.2.*", "doctrine/orm": "^2.5", "doctrine/doctrine-bundle": "^1.6", @@ -43,7 +43,7 @@ "knplabs/knp-gaufrette-bundle": "^0.3.0", "beberlei/DoctrineExtensions": "^1.0", "sensio/generator-bundle": "^3.0", - "divante-ltd/open-loyalty-framework": "1.4.*" + "divante-ltd/open-loyalty-framework": "^2.0" }, "require-dev": { "symfony/phpunit-bridge": "^3.0", @@ -69,7 +69,7 @@ }, "config": { "platform": { - "php": "5.6" + "php": "7.0" }, "bin-dir": "var/bin" }, diff --git a/backend/composer.lock b/backend/composer.lock index 33b16b1d..11aa8e7c 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -4,7 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "fb04bf5a6404206276e45d081b69ad63", + "hash": "d2567ad74215db498345537c133fab6a", + "content-hash": "98b847690629cd0ea4f60fe68f7ca6b0", "packages": [ { "name": "beberlei/DoctrineExtensions", @@ -66,7 +67,7 @@ "doctrine", "orm" ], - "time": "2017-01-11T07:22:12+00:00" + "time": "2017-01-11 07:22:12" }, { "name": "beberlei/assert", @@ -121,7 +122,7 @@ "assertion", "validation" ], - "time": "2017-01-09T09:19:50+00:00" + "time": "2017-01-09 09:19:50" }, { "name": "broadway/broadway", @@ -208,7 +209,7 @@ "domain-driven design", "event sourcing" ], - "time": "2016-04-19T13:31:15+00:00" + "time": "2016-04-19 13:31:15" }, { "name": "broadway/uuid-generator", @@ -241,20 +242,20 @@ "MIT" ], "description": "UUID generator for broadway/broadway.", - "time": "2014-09-12T14:14:07+00:00" + "time": "2014-09-12 14:14:07" }, { "name": "divante-ltd/open-loyalty-framework", - "version": "1.4.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/DivanteLtd/open-loyalty-framework.git", - "reference": "c12ea18c53ad9de0afa93afd6b1592e367fcbd8d" + "reference": "579e46cb7dea1756cb4f2fd9e6c2311230b2e94e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DivanteLtd/open-loyalty-framework/zipball/c12ea18c53ad9de0afa93afd6b1592e367fcbd8d", - "reference": "c12ea18c53ad9de0afa93afd6b1592e367fcbd8d", + "url": "https://api.github.com/repos/DivanteLtd/open-loyalty-framework/zipball/579e46cb7dea1756cb4f2fd9e6c2311230b2e94e", + "reference": "579e46cb7dea1756cb4f2fd9e6c2311230b2e94e", "shasum": "" }, "require": { @@ -275,7 +276,7 @@ "nelmio/api-doc-bundle": "^2.13", "nelmio/cors-bundle": "^1.4", "ocramius/proxy-manager": "^1.0", - "php": ">=5.6", + "php": ">=7.0", "pixers/salesmanago-api": "1.1.1", "sensio/distribution-bundle": "^5.0", "sensio/framework-extra-bundle": "^3.0.2", @@ -349,7 +350,7 @@ "license": [ "proprietary" ], - "time": "2017-11-07T13:21:16+00:00" + "time": "2017-11-16 08:52:21" }, { "name": "doctrine/annotations", @@ -417,7 +418,7 @@ "docblock", "parser" ], - "time": "2016-12-30T15:59:45+00:00" + "time": "2016-12-30 15:59:45" }, { "name": "doctrine/cache", @@ -487,7 +488,7 @@ "cache", "caching" ], - "time": "2016-10-29T11:16:17+00:00" + "time": "2016-10-29 11:16:17" }, { "name": "doctrine/collections", @@ -553,7 +554,7 @@ "collections", "iterator" ], - "time": "2015-04-14T22:21:58+00:00" + "time": "2015-04-14 22:21:58" }, { "name": "doctrine/common", @@ -626,7 +627,7 @@ "persistence", "spl" ], - "time": "2017-01-13T14:02:13+00:00" + "time": "2017-01-13 14:02:13" }, { "name": "doctrine/data-fixtures", @@ -685,7 +686,7 @@ "keywords": [ "database" ], - "time": "2016-09-20T10:07:57+00:00" + "time": "2016-09-20 10:07:57" }, { "name": "doctrine/dbal", @@ -756,7 +757,7 @@ "persistence", "queryobject" ], - "time": "2017-01-14T21:05:28+00:00" + "time": "2017-01-14 21:05:28" }, { "name": "doctrine/doctrine-bundle", @@ -837,7 +838,7 @@ "orm", "persistence" ], - "time": "2017-01-07T21:47:22+00:00" + "time": "2017-01-07 21:47:22" }, { "name": "doctrine/doctrine-cache-bundle", @@ -925,7 +926,7 @@ "cache", "caching" ], - "time": "2016-01-26T17:28:51+00:00" + "time": "2016-01-26 17:28:51" }, { "name": "doctrine/doctrine-fixtures-bundle", @@ -982,7 +983,7 @@ "Fixture", "persistence" ], - "time": "2015-11-04T21:23:23+00:00" + "time": "2015-11-04 21:23:23" }, { "name": "doctrine/inflector", @@ -1049,7 +1050,7 @@ "singularize", "string" ], - "time": "2015-11-06T14:35:42+00:00" + "time": "2015-11-06 14:35:42" }, { "name": "doctrine/instantiator", @@ -1103,7 +1104,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "doctrine/lexer", @@ -1157,7 +1158,7 @@ "lexer", "parser" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2014-09-09 13:34:57" }, { "name": "doctrine/orm", @@ -1233,7 +1234,7 @@ "database", "orm" ], - "time": "2016-12-18T15:42:34+00:00" + "time": "2016-12-18 15:42:34" }, { "name": "elasticsearch/elasticsearch", @@ -1287,7 +1288,7 @@ "elasticsearch", "search" ], - "time": "2016-11-30T17:15:05+00:00" + "time": "2016-11-30 17:15:05" }, { "name": "friendsofsymfony/rest-bundle", @@ -1384,7 +1385,7 @@ "keywords": [ "rest" ], - "time": "2016-11-23T12:09:05+00:00" + "time": "2016-11-23 12:09:05" }, { "name": "fzaninotto/faker", @@ -1432,7 +1433,7 @@ "faker", "fixtures" ], - "time": "2016-04-29T12:21:54+00:00" + "time": "2016-04-29 12:21:54" }, { "name": "gesdinet/jwt-refresh-token-bundle", @@ -1484,7 +1485,7 @@ "keywords": [ "jwt refresh token bundle symfony json web" ], - "time": "2016-07-24T08:16:07+00:00" + "time": "2016-07-24 08:16:07" }, { "name": "guzzlehttp/guzzle", @@ -1546,7 +1547,7 @@ "rest", "web service" ], - "time": "2016-10-08T15:01:37+00:00" + "time": "2016-10-08 15:01:37" }, { "name": "guzzlehttp/promises", @@ -1597,7 +1598,7 @@ "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "time": "2016-12-20 10:07:11" }, { "name": "guzzlehttp/psr7", @@ -1655,7 +1656,7 @@ "stream", "uri" ], - "time": "2016-06-24T23:00:38+00:00" + "time": "2016-06-24 23:00:38" }, { "name": "guzzlehttp/ringphp", @@ -1706,7 +1707,7 @@ } ], "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", - "time": "2015-05-20T03:37:09+00:00" + "time": "2015-05-20 03:37:09" }, { "name": "guzzlehttp/streams", @@ -1756,7 +1757,7 @@ "Guzzle", "stream" ], - "time": "2014-10-12T19:18:40+00:00" + "time": "2014-10-12 19:18:40" }, { "name": "incenteev/composer-parameter-handler", @@ -1807,7 +1808,7 @@ "keywords": [ "parameters management" ], - "time": "2015-11-10T17:04:01+00:00" + "time": "2015-11-10 17:04:01" }, { "name": "jdorn/sql-formatter", @@ -1857,7 +1858,7 @@ "highlight", "sql" ], - "time": "2014-01-12T16:20:24+00:00" + "time": "2014-01-12 16:20:24" }, { "name": "jms-serializer/serializer-bundle", @@ -1930,7 +1931,7 @@ "serialization", "xml" ], - "time": "2016-04-25T14:54:23+00:00" + "time": "2016-04-25 14:54:23" }, { "name": "jms/metadata", @@ -1981,7 +1982,7 @@ "xml", "yaml" ], - "time": "2016-12-05T10:18:33+00:00" + "time": "2016-12-05 10:18:33" }, { "name": "jms/parser-lib", @@ -2016,7 +2017,7 @@ "Apache2" ], "description": "A library for easily creating recursive-descent parsers.", - "time": "2012-11-18T18:08:43+00:00" + "time": "2012-11-18 18:08:43" }, { "name": "jms/serializer", @@ -2091,7 +2092,7 @@ "serialization", "xml" ], - "time": "2016-11-13T10:20:11+00:00" + "time": "2016-11-13 10:20:11" }, { "name": "knplabs/gaufrette", @@ -2175,7 +2176,7 @@ "filesystem", "media" ], - "time": "2016-03-03T09:36:22+00:00" + "time": "2016-03-03 09:36:22" }, { "name": "knplabs/knp-gaufrette-bundle", @@ -2233,7 +2234,7 @@ "filesystem", "media" ], - "time": "2016-01-16T00:12:11+00:00" + "time": "2016-01-16 00:12:11" }, { "name": "lexik/jwt-authentication-bundle", @@ -2308,7 +2309,7 @@ "rest", "symfony" ], - "time": "2016-10-11T17:25:28+00:00" + "time": "2016-10-11 17:25:28" }, { "name": "michelf/php-markdown", @@ -2359,7 +2360,7 @@ "keywords": [ "markdown" ], - "time": "2016-10-29T18:58:20+00:00" + "time": "2016-10-29 18:58:20" }, { "name": "monolog/monolog", @@ -2437,7 +2438,7 @@ "logging", "psr-3" ], - "time": "2016-11-26T00:15:39+00:00" + "time": "2016-11-26 00:15:39" }, { "name": "namshi/jose", @@ -2497,7 +2498,7 @@ "jwt", "token" ], - "time": "2016-01-24T11:10:26+00:00" + "time": "2016-01-24 11:10:26" }, { "name": "nelmio/api-doc-bundle", @@ -2582,7 +2583,7 @@ "documentation", "rest" ], - "time": "2016-06-13T09:12:09+00:00" + "time": "2016-06-13 09:12:09" }, { "name": "nelmio/cors-bundle", @@ -2639,7 +2640,7 @@ "cors", "crossdomain" ], - "time": "2016-12-30T18:10:59+00:00" + "time": "2016-12-30 18:10:59" }, { "name": "ocramius/proxy-manager", @@ -2702,7 +2703,7 @@ "proxy pattern", "service proxies" ], - "time": "2015-08-09T04:28:19+00:00" + "time": "2015-08-09 04:28:19" }, { "name": "paragonie/random_compat", @@ -2750,7 +2751,7 @@ "pseudorandom", "random" ], - "time": "2016-11-07T23:38:38+00:00" + "time": "2016-11-07 23:38:38" }, { "name": "phpcollection/phpcollection", @@ -2798,7 +2799,7 @@ "sequence", "set" ], - "time": "2015-05-17T12:39:23+00:00" + "time": "2015-05-17 12:39:23" }, { "name": "phpoption/phpoption", @@ -2848,7 +2849,7 @@ "php", "type" ], - "time": "2015-07-25T16:39:46+00:00" + "time": "2015-07-25 16:39:46" }, { "name": "phpseclib/phpseclib", @@ -2940,7 +2941,7 @@ "x.509", "x509" ], - "time": "2016-10-04T00:57:04+00:00" + "time": "2016-10-04 00:57:04" }, { "name": "pixers/salesmanago-api", @@ -2984,7 +2985,7 @@ } ], "description": "SalesManago API", - "time": "2016-08-02T10:10:44+00:00" + "time": "2016-08-02 10:10:44" }, { "name": "psr/cache", @@ -3030,7 +3031,7 @@ "psr", "psr-6" ], - "time": "2016-08-06T20:24:11+00:00" + "time": "2016-08-06 20:24:11" }, { "name": "psr/http-message", @@ -3080,7 +3081,7 @@ "request", "response" ], - "time": "2016-08-06T14:39:51+00:00" + "time": "2016-08-06 14:39:51" }, { "name": "psr/log", @@ -3127,7 +3128,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2016-10-10 12:19:37" }, { "name": "ramsey/uuid", @@ -3194,7 +3195,7 @@ "identifier", "uuid" ], - "time": "2016-03-22T18:20:19+00:00" + "time": "2016-03-22 18:20:19" }, { "name": "react/promise", @@ -3237,7 +3238,7 @@ "promise", "promises" ], - "time": "2016-12-22T14:09:01+00:00" + "time": "2016-12-22 14:09:01" }, { "name": "sensio/distribution-bundle", @@ -3289,7 +3290,7 @@ "configuration", "distribution" ], - "time": "2017-01-10T14:58:45+00:00" + "time": "2017-01-10 14:58:45" }, { "name": "sensio/framework-extra-bundle", @@ -3357,7 +3358,7 @@ "annotations", "controllers" ], - "time": "2017-01-10T19:42:56+00:00" + "time": "2017-01-10 19:42:56" }, { "name": "sensio/generator-bundle", @@ -3411,7 +3412,7 @@ } ], "description": "This bundle generates code for you", - "time": "2017-07-18T07:57:44+00:00" + "time": "2017-07-18 07:57:44" }, { "name": "sensiolabs/security-checker", @@ -3455,7 +3456,7 @@ } ], "description": "A security checker for your composer.lock", - "time": "2016-09-23T18:09:57+00:00" + "time": "2016-09-23 18:09:57" }, { "name": "swiftmailer/swiftmailer", @@ -3509,7 +3510,7 @@ "mail", "mailer" ], - "time": "2016-12-29T10:02:40+00:00" + "time": "2016-12-29 10:02:40" }, { "name": "symfony/monolog-bundle", @@ -3569,7 +3570,7 @@ "log", "logging" ], - "time": "2017-01-02T19:04:26+00:00" + "time": "2017-01-02 19:04:26" }, { "name": "symfony/polyfill-apcu", @@ -3622,7 +3623,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-intl-icu", @@ -3680,7 +3681,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-mbstring", @@ -3739,7 +3740,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php56", @@ -3795,7 +3796,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php70", @@ -3854,7 +3855,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-util", @@ -3906,7 +3907,7 @@ "polyfill", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/swiftmailer-bundle", @@ -3965,7 +3966,7 @@ ], "description": "Symfony SwiftmailerBundle", "homepage": "http://symfony.com", - "time": "2016-12-20T04:44:33+00:00" + "time": "2016-12-20 04:44:33" }, { "name": "symfony/symfony", @@ -4107,7 +4108,7 @@ "keywords": [ "framework" ], - "time": "2017-01-12T21:36:55+00:00" + "time": "2017-01-12 21:36:55" }, { "name": "twig/twig", @@ -4168,7 +4169,7 @@ "keywords": [ "templating" ], - "time": "2017-01-11T19:36:15+00:00" + "time": "2017-01-11 19:36:15" }, { "name": "willdurand/jsonp-callback-validator", @@ -4208,7 +4209,7 @@ } ], "description": "JSONP callback validator.", - "time": "2014-01-20T22:35:06+00:00" + "time": "2014-01-20 22:35:06" }, { "name": "willdurand/negotiation", @@ -4260,7 +4261,7 @@ "header", "negotiation" ], - "time": "2016-10-14T09:17:47+00:00" + "time": "2016-10-14 09:17:47" }, { "name": "zendframework/zend-code", @@ -4312,7 +4313,7 @@ "code", "zf2" ], - "time": "2016-04-20T17:26:42+00:00" + "time": "2016-04-20 17:26:42" }, { "name": "zendframework/zend-eventmanager", @@ -4366,7 +4367,7 @@ "events", "zf2" ], - "time": "2016-12-19T21:47:12+00:00" + "time": "2016-12-19 21:47:12" } ], "packages-dev": [ @@ -4410,7 +4411,7 @@ "object", "object graph" ], - "time": "2017-01-26T22:05:40+00:00" + "time": "2017-01-26 22:05:40" }, { "name": "phpdocumentor/reflection-common", @@ -4464,7 +4465,7 @@ "reflection", "static analysis" ], - "time": "2015-12-27T11:43:31+00:00" + "time": "2015-12-27 11:43:31" }, { "name": "phpdocumentor/reflection-docblock", @@ -4509,7 +4510,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30T07:12:33+00:00" + "time": "2016-09-30 07:12:33" }, { "name": "phpdocumentor/type-resolver", @@ -4556,7 +4557,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2016-11-25T06:54:22+00:00" + "time": "2016-11-25 06:54:22" }, { "name": "phpspec/prophecy", @@ -4619,7 +4620,7 @@ "spy", "stub" ], - "time": "2016-11-21T14:58:47+00:00" + "time": "2016-11-21 14:58:47" }, { "name": "phpunit/php-code-coverage", @@ -4682,7 +4683,7 @@ "testing", "xunit" ], - "time": "2017-02-23T07:38:02+00:00" + "time": "2017-02-23 07:38:02" }, { "name": "phpunit/php-file-iterator", @@ -4729,7 +4730,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -4770,7 +4771,7 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2015-06-21 13:50:34" }, { "name": "phpunit/php-timer", @@ -4814,7 +4815,7 @@ "keywords": [ "timer" ], - "time": "2016-05-12T18:03:57+00:00" + "time": "2016-05-12 18:03:57" }, { "name": "phpunit/php-token-stream", @@ -4863,7 +4864,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-02-23T06:14:45+00:00" + "time": "2017-02-23 06:14:45" }, { "name": "phpunit/phpunit", @@ -4945,7 +4946,7 @@ "testing", "xunit" ], - "time": "2017-02-19T07:22:16+00:00" + "time": "2017-02-19 07:22:16" }, { "name": "phpunit/phpunit-mock-objects", @@ -5004,7 +5005,7 @@ "mock", "xunit" ], - "time": "2016-12-08T20:27:08+00:00" + "time": "2016-12-08 20:27:08" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -5049,7 +5050,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2016-02-13T06:45:14+00:00" + "time": "2016-02-13 06:45:14" }, { "name": "sebastian/comparator", @@ -5113,7 +5114,7 @@ "compare", "equality" ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2017-01-29 09:50:25" }, { "name": "sebastian/diff", @@ -5165,7 +5166,7 @@ "keywords": [ "diff" ], - "time": "2015-12-08T07:14:41+00:00" + "time": "2015-12-08 07:14:41" }, { "name": "sebastian/environment", @@ -5215,7 +5216,7 @@ "environment", "hhvm" ], - "time": "2016-11-26T07:53:53+00:00" + "time": "2016-11-26 07:53:53" }, { "name": "sebastian/exporter", @@ -5282,7 +5283,7 @@ "export", "exporter" ], - "time": "2016-11-19T08:54:04+00:00" + "time": "2016-11-19 08:54:04" }, { "name": "sebastian/global-state", @@ -5333,7 +5334,7 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2015-10-12 03:26:01" }, { "name": "sebastian/object-enumerator", @@ -5379,7 +5380,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" + "time": "2017-02-18 15:18:39" }, { "name": "sebastian/recursion-context", @@ -5432,7 +5433,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" + "time": "2016-11-19 07:33:16" }, { "name": "sebastian/resource-operations", @@ -5474,7 +5475,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2015-07-28 20:34:47" }, { "name": "sebastian/version", @@ -5517,7 +5518,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2016-10-03 07:35:21" }, { "name": "symfony/phpunit-bridge", @@ -5575,7 +5576,7 @@ ], "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", - "time": "2017-01-06T17:19:17+00:00" + "time": "2017-01-06 17:19:17" }, { "name": "webmozart/assert", @@ -5625,7 +5626,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2016-11-23 20:04:58" } ], "aliases": [], @@ -5634,10 +5635,10 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.5.9" + "php": ">=7.0" }, "platform-dev": [], "platform-overrides": { - "php": "5.6" + "php": "7.0" } } diff --git a/backend/docker/mpm-prefork-module.conf b/backend/docker/mpm-prefork-module.conf deleted file mode 100644 index 697d036b..00000000 --- a/backend/docker/mpm-prefork-module.conf +++ /dev/null @@ -1,3 +0,0 @@ - - StartServers 4 - diff --git a/backend/docker/rancher/entrypoint.sh b/backend/docker/rancher/entrypoint.sh deleted file mode 100644 index d628e953..00000000 --- a/backend/docker/rancher/entrypoint.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -cd /var/www/ol/backend -rm -r vendor -composer install -o -bin/console cache:clear --env=prod -bin/console cache:warmup --env=prod -bin/console assets:install --symlink -chown -R www-data:www-data /var/www/ol/backend/var -chown -R www-data:www-data /var/www/ol/backend/app/uploads -phing setup -apache2-foreground diff --git a/backend/docker/rancher/prod_entrypoint.sh b/backend/docker/rancher/prod_entrypoint.sh deleted file mode 100644 index bef5711a..00000000 --- a/backend/docker/rancher/prod_entrypoint.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -cd /var/www/ol/backend -rm -r vendor -composer install -o --prefer-dist --no-dev -bin/console cache:clear --env=prod -bin/console cache:warmup --env=prod -bin/console assets:install --symlink -chown -R www-data:www-data /var/www/ol/backend/var -chown -R www-data:www-data /var/www/ol/backend/app/uploads -phing generate-jwt-keys -apache2-foreground diff --git a/backend/docker/rancher/test_entrypoint.sh b/backend/docker/rancher/test_entrypoint.sh deleted file mode 100644 index c14dfe86..00000000 --- a/backend/docker/rancher/test_entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -cd /var/www/ol/backend -rm -r vendor -composer install -o --prefer-dist -bin/console cache:clear --env=prod -bin/console cache:warmup --env=prod -bin/console assets:install --symlink -bin/console doctrine:schema:update -f -chown -R www-data:www-data /var/www/ol/backend/var -chown -R www-data:www-data /var/www/ol/backend/app/uploads -phing generate-jwt-keys -apache2-foreground diff --git a/backend/docker/vhost.conf b/backend/docker/vhost.conf deleted file mode 100644 index 81a09d59..00000000 --- a/backend/docker/vhost.conf +++ /dev/null @@ -1,26 +0,0 @@ - - - DocumentRoot /var/www/ol/backend/web - - - # enable the .htaccess rewrites - AllowOverride All - Require all granted - - - ErrorLog /var/log/apache2/project_error.log - CustomLog /var/log/apache2/project_access.log combined - - - - DocumentRoot /var/www/ol/frontend/dist - - - # enable the .htaccess rewrites - AllowOverride All - Require all granted - - - ErrorLog /var/log/apache2/project_error.log - CustomLog /var/log/apache2/project_access.log combined - diff --git a/backend/web/config.php b/backend/web/config.php index 95a14f95..69df43cf 100644 --- a/backend/web/config.php +++ b/backend/web/config.php @@ -22,7 +22,7 @@ exit('This script is only accessible from localhost.'); } -require_once dirname(__FILE__).'/./SymfonyRequirements.php'; +require_once dirname(__FILE__).'/../var/SymfonyRequirements.php'; $symfonyRequirements = new SymfonyRequirements(); diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index 05527ba1..00000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,8 +0,0 @@ -# use as docker-compose -f docker-composer.yml -f docker-compose.dev.yml up -backend: - volumes: - - ./backend:/var/www/ol/backend - - ./backend/docker/xdebug.ini:/usr/local/etc/php.d/xdebug.ini -frontend: - volumes: - - ./frontend:/var/www diff --git a/docker-compose.test.yml b/docker-compose.test.yml deleted file mode 100644 index f6b2f964..00000000 --- a/docker-compose.test.yml +++ /dev/null @@ -1,3 +0,0 @@ -# use as docker-compose -f docker-composer.yml -f docker-compose.test.yml up -backend: - command: bash -c "composer install && bin/console assets:install --symlink && chown -R www-data:www-data /var/www/ol/backend/var && chown -R www-data:www-data /var/www/ol/backend/app/uploads && phing ci-setup-test" diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 5f79d27b..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -backend: - container_name: open_loyalty_backend - build: ./backend - links: - - elk - - db - - mail - ports: - - "8181:80" - extra_hosts: - - "web:127.0.0.1" -frontend: - container_name: open_loyalty_frontend - build: ./frontend - ports: - - "8182:3000" - - "8183:3001" - - "8184:3002" -elk: - container_name: open_loyalty_elk - image: elasticsearch:2.2 -db: - container_name: open_loyalty_postgresql - image: postgres:9 - environment: - - POSTGRES_DB=openloyalty - - POSTGRES_USER=openloyalty - - POSTGRES_PASSWORD=openloyalty -mail: - container_name: open_loyalty_mail - image: mailhog/mailhog - ports: - - "8186:8025" diff --git a/docker-compose_prod.yml b/docker-compose_prod.yml deleted file mode 100644 index a8ad48ba..00000000 --- a/docker-compose_prod.yml +++ /dev/null @@ -1,37 +0,0 @@ -backend: - container_name: open_loyalty_backend - build: ./backend - links: - - elk - - db - - mail - command: bash -c "composer install -o --prefer-dist && bin/console assets:install --symlink && chown -R www-data:www-data /var/www/ol/backend/var && apache2-foreground" - ports: - - "8181:80" - extra_hosts: - - "web:127.0.0.1" -frontend: - container_name: open_loyalty_frontend - build: ./frontend - ports: - - "8182:3000" - - "8183:3001" - - "8184:3002" -elk: - container_name: open_loyalty_elk - image: elasticsearch:2.2 - volumes: - - ./esdata:/usr/share/elasticsearch/data -db: - container_name: open_loyalty_postgresql - image: postgres - volumes: - - ./postgres_data:/var/lib/postgresql/data - environment: - - POSTGRES_DB=openloyalty - - POSTGRES_USER=openloyalty - - POSTGRES_PASSWORD=openloyalty -mail: - image: mailhog/mailhog - ports: - - "8186:8025" diff --git a/docker/.env b/docker/.env new file mode 100644 index 00000000..33afa7a5 --- /dev/null +++ b/docker/.env @@ -0,0 +1,11 @@ +POSTGRES_DB=openloyalty +POSTGRES_USER=openloyalty +POSTGRES_PASSWORD=openloyalty + +APP_DB_HOST=db +APP_DB_PORT=5432 +APP_DB_USER=openloyalty +APP_DB_PASSWORD=openloyalty +APP_DB_NAME=openloyalty + +ELK_HOST=elk diff --git a/docker/base/build_dev.sh b/docker/base/build_dev.sh new file mode 100755 index 00000000..da06ef8c --- /dev/null +++ b/docker/base/build_dev.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +## build base images +docker build -t openloyalty/base-nodejs -f nodejs-dockerfile . +docker build -t openloyalty/base-nginx -f nginx-dockerfile . +docker build -t openloyalty/base-php-fpm -f php-fpm-dockerfile . diff --git a/docker/base/nginx-dockerfile b/docker/base/nginx-dockerfile new file mode 100644 index 00000000..234dedaa --- /dev/null +++ b/docker/base/nginx-dockerfile @@ -0,0 +1,4 @@ +FROM nginx:1.13 + +RUN apt-get update && apt-get install -qy vim +RUN usermod -s /bin/bash www-data diff --git a/docker/base/nodejs-dockerfile b/docker/base/nodejs-dockerfile new file mode 100644 index 00000000..5d523e0d --- /dev/null +++ b/docker/base/nodejs-dockerfile @@ -0,0 +1,6 @@ +FROM node:5 + +RUN apt-get update \ + && apt-get install -y ruby-full rubygems \ + && gem instal sass +RUN npm install -g gulp node-sass yarn \ No newline at end of file diff --git a/docker/base/php-fpm-dockerfile b/docker/base/php-fpm-dockerfile new file mode 100644 index 00000000..7e4af953 --- /dev/null +++ b/docker/base/php-fpm-dockerfile @@ -0,0 +1,10 @@ +FROM php:7.1-fpm + +COPY ["scripts/php-configure.sh", "/opt/bin/"] +RUN /bin/bash /opt/bin/php-configure.sh + +RUN usermod --non-unique --uid 1000 www-data +RUN rm -rf /var/www/html/* +RUN usermod -s /bin/bash www-data + +COPY php.ini /usr/local/etc/php/php.ini diff --git a/backend/docker/php.ini b/docker/base/php.ini similarity index 71% rename from backend/docker/php.ini rename to docker/base/php.ini index 4d8c1468..d85d5d13 100644 --- a/backend/docker/php.ini +++ b/docker/base/php.ini @@ -1,3 +1,3 @@ date.timezone = Europe/Warsaw short_open_tag = off -memory_limit = 256M +memory_limit = 512M diff --git a/docker/base/scripts/php-configure.sh b/docker/base/scripts/php-configure.sh new file mode 100644 index 00000000..9d6eb5e1 --- /dev/null +++ b/docker/base/scripts/php-configure.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +apt-get -qy update \ + && apt-get install -qy locales libicu-dev zlib1g-dev libghc-postgresql-libpq-dev git libcurl4-openssl-dev vim netcat postgresql python-setuptools \ + && locale-gen C.UTF-8 \ + && /usr/sbin/update-locale LANG=C.UTF-8 \ + && apt-get autoremove -y \ + && apt-get clean all + +docker-php-ext-configure pgsql -with-pgsql=/usr/include/postgresql/ && docker-php-ext-install pdo pgsql pdo_pgsql pdo_mysql mysqli intl opcache bcmath zip curl +docker-php-ext-enable curl \ No newline at end of file diff --git a/docker/ci/php/fpm-dockerfile b/docker/ci/php/fpm-dockerfile new file mode 100644 index 00000000..196cb6f0 --- /dev/null +++ b/docker/ci/php/fpm-dockerfile @@ -0,0 +1,16 @@ +FROM composer/composer:1.1-alpine AS composer +FROM divante/open-loyalty-base-php-fpm AS base + +ENV SYMFONY_ENV="prod" + +ADD https://www.phing.info/get/phing-latest.phar /usr/local/bin/phing +RUN chmod a+x /usr/local/bin/phing +RUN chown www-data:www-data /usr/local/bin/phing + +COPY ./backend /var/www/openloyalty +COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer + +RUN mkdir /var/www/openloyalty/var/cache && chmod 755 /var/www/openloyalty/var && chmod 755 /var/www/openloyalty/var/cache && chmod 755 /var/www/openloyalty/var/logs + +WORKDIR /var/www/openloyalty +RUN composer install && bin/console assets:install && chown -R www-data:www-data /var/www/openloyalty/var diff --git a/docker/dev/php/fpm-dockerfile b/docker/dev/php/fpm-dockerfile new file mode 100644 index 00000000..62780b02 --- /dev/null +++ b/docker/dev/php/fpm-dockerfile @@ -0,0 +1,24 @@ +FROM composer/composer:1.1-alpine AS composer +FROM divante/open-loyalty-base-php-fpm AS base + +RUN pecl install xdebug +RUN docker-php-ext-enable xdebug +RUN usermod -u 1000 www-data + +COPY ./docker/dev/php/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini +COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer + +ADD https://www.phing.info/get/phing-latest.phar /usr/local/bin/phing +RUN chmod a+x /usr/local/bin/phing + +WORKDIR /var/www/openloyalty + +ONBUILD RUN chmod -R 777 /var/www/openloyalty/var +ONBUILD RUN chmod 777 /var/www/openloyalty/var/cache +ONBUILD RUN chmod 777 /var/www/openloyalty/var/logs +ONBUILD RUN chown -R www-data:www-data /var/www/openloyalty/var + +ENV SYMFONY_ENV="dev" + +CMD composer install && bin/console assets:install && chown -R www-data:www-data /var/www/openloyalty/var && php-fpm + diff --git a/backend/docker/xdebug.ini b/docker/dev/php/xdebug.ini similarity index 84% rename from backend/docker/xdebug.ini rename to docker/dev/php/xdebug.ini index d830b9d8..390749d5 100644 --- a/backend/docker/xdebug.ini +++ b/docker/dev/php/xdebug.ini @@ -3,4 +3,4 @@ xdebug.remote_connect_back=on xdebug.remote_log=/tmp/xdebug.log xdebug.extended_info=1 xdebug.remote_autostart=1 -xdebug.remote_port=9012 +xdebug.remote_port=10001 diff --git a/docker/dev/web/backend-dockerfile b/docker/dev/web/backend-dockerfile new file mode 100644 index 00000000..7ec21fde --- /dev/null +++ b/docker/dev/web/backend-dockerfile @@ -0,0 +1,6 @@ +FROM divante/open-loyalty-base-nginx as www + +RUN usermod -u 1000 www-data + +COPY ./docker/dev/web/backend.conf /etc/nginx/conf.d/backend.conf +COPY ./backend/web/ /var/www/openloyalty/web diff --git a/docker/dev/web/backend.conf b/docker/dev/web/backend.conf new file mode 100644 index 00000000..86e96638 --- /dev/null +++ b/docker/dev/web/backend.conf @@ -0,0 +1,37 @@ +server { + server_name openloyalty.localhost; + root /var/www/openloyalty/web; + listen 80; + + location / { + # try to serve file directly, fallback to app.php + try_files $uri /app.php$is_args$args; + } + # DEV + # This rule should only be placed on your development environment + # In production, don't include this and don't deploy app_dev.php or config.php + location ~ ^/(app|app_dev|config)\.php(/|$) { + fastcgi_pass php:9000; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + # When you are using symlinks to link the document root to the + # current version of your application, you should pass the real + # application path instead of the path to the symlink to PHP + # FPM. + # Otherwise, PHP's OPcache may not properly detect changes to + # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 + # for more information). + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + } + + + # return 404 for all other php files not matching the front controller + # this prevents access to other php files you don't want to be accessible. + location ~ \.php$ { + return 404; + } + + error_log /var/log/nginx/openloyalty_error.log; + access_log /var/log/nginx/openloyalty_access.log; +} diff --git a/docker/dev/web/config.js b/docker/dev/web/config.js new file mode 100644 index 00000000..087107a9 --- /dev/null +++ b/docker/dev/web/config.js @@ -0,0 +1,16 @@ +const config = { + "apiUrl": "http://openloyalty.localhost/app_dev.php/api", + "dateFormat": "YYYY-MM-DD", + "dateTimeFormat": "YYYY-MM-DD HH:mm", + "perPage": 20, + "debug": false, + "modules": [] +}; +window.OpenLoyaltyConfig = { + "apiUrl": "http://openloyalty.localhost/app_dev.php/api", + "dateFormat": "YYYY-MM-DD", + "dateTimeFormat": "YYYY-MM-DD HH:mm", + "perPage": 20, + "debug": false, + "modules": [] +}; diff --git a/docker/dev/web/front-dockerfile b/docker/dev/web/front-dockerfile new file mode 100644 index 00000000..a5e8ea16 --- /dev/null +++ b/docker/dev/web/front-dockerfile @@ -0,0 +1,13 @@ +FROM divante/open-loyalty-base-nodejs AS front + +RUN usermod -u 1000 www-data +WORKDIR /var/www/frontend + +RUN cd $(npm root -g)/npm \ + && npm install fs-extra \ + && sed -i -e s/graceful-fs/fs-extra/ -e s/fs.rename/fs.move/ ./lib/utils/rename.js \ + && npm install -g yarn + +EXPOSE 3000 +WORKDIR /var/www/frontend +CMD yarn install && npm start diff --git a/docker/dev/web/parameters.json b/docker/dev/web/parameters.json new file mode 100644 index 00000000..5517ce64 --- /dev/null +++ b/docker/dev/web/parameters.json @@ -0,0 +1,8 @@ +{ + "apiUrl": "http://openloyalty.localhost/app_dev.php/api", + "dateFormat": "YYYY-MM-DD", + "dateTimeFormat": "YYYY-MM-DD HH:mm", + "perPage": 20, + "debug": false, + "modules": [] +} diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml new file mode 100644 index 00000000..f34338b2 --- /dev/null +++ b/docker/docker-compose.dev.yml @@ -0,0 +1,33 @@ +version: "2" + +services: + php: + build: + context: '../' + dockerfile: './docker/dev/php/fpm-dockerfile' + links: + - db + - elk + - mail + ports: + - "9000:9000" + volumes: + - '../backend:/var/www/openloyalty' + nginx: + build: + context: '../' + dockerfile: './docker/dev/web/backend-dockerfile' + links: + - php + ports: + - "80:80" + frontend: + container_name: open_loyalty_frontend_dev + build: + context: '../' + dockerfile: './docker/dev/web/front-dockerfile' + ports: + - "8081:8081" + volumes: + - '../frontend/:/var/www/frontend' + - './dev/web/config.js:/var/www/frontend/src/config.js' diff --git a/docker/docker-compose.test.yml b/docker/docker-compose.test.yml new file mode 100644 index 00000000..5095062c --- /dev/null +++ b/docker/docker-compose.test.yml @@ -0,0 +1,8 @@ +version: "2" + +services: + php: + build: + context: '../' + dockerfile: './docker/ci/php/fpm-dockerfile' + command: bash -c "phing ci-setup-test" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000..f6bab4b4 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,41 @@ +version: "2" + +services: + php: + container_name: open_loyalty_backend + build: + context: '../' + dockerfile: './docker/prod/php/fpm-dockerfile' + links: + - db + - elk + - mail + depends_on: + - db + env_file: + - .env + nginx: + container_name: open_loyalty_frontend + build: + context: '../' + dockerfile: './docker/prod/web/app-dockerfile' + links: + - php + ports: + - "80:80" + - "8182:3001" + - "8183:3002" + - "8184:3003" + elk: + container_name: open_loyalty_elk + image: elasticsearch:2.2 + db: + container_name: open_loyalty_db + image: postgres:9 + env_file: + - .env + mail: + container_name: open_loyalty_mail + image: mailhog/mailhog + ports: + - "8186:8025" diff --git a/docker/prod/php/bin/init.sh b/docker/prod/php/bin/init.sh new file mode 100644 index 00000000..cf9fdb2a --- /dev/null +++ b/docker/prod/php/bin/init.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +function info { + printf "\033[0;36m===> \033[0;33m${1}\033[0m\n" +} + +until nc -z ${APP_DB_HOST} ${APP_DB_PORT}; do + info "Waiting database on ${APP_DB_HOST}:${APP_DB_PORT} ..." + sleep 2 +done + +until nc -z ${ELK_HOST} 9200; do + info "Waiting for elasticsearch" + sleep 2 +done + +info "Setting permissions." +chown -R www-data:www-data /var/www/openloyalty/var + +info "Checking if database is already initialized" +if [[ `PGPASSWORD="$APP_DB_PASSWORD" psql -h $APP_DB_HOST -U $APP_DB_USER -l -A -t | grep $APP_DB_NAME | wc -l` -gt 0 ]] \ + && ! [[ `PGPASSWORD="$APP_DB_PASSWORD" psql -h $APP_DB_HOST -U $APP_DB_USER -d $APP_DB_NAME -A -t -q -c '\dt' | wc -l` -gt 0 ]]; then + info "Running initializing scripts..." + runuser -s /bin/sh -c 'phing setup' www-data + info "Tables are initialized." +else + info "Database already initialized." +fi + +info "Starting supervisord with php-fpm and cron." +exec /usr/local/bin/supervisord -n -c /etc/supervisord/supervisord.conf diff --git a/docker/prod/php/conf/crontab.txt b/docker/prod/php/conf/crontab.txt new file mode 100644 index 00000000..6a90c02e --- /dev/null +++ b/docker/prod/php/conf/crontab.txt @@ -0,0 +1,3 @@ +* * * * * /usr/local/bin/php /var/www/openloyalty/bin/console oloy:segment:recreate > /var/log/cron_ol_segment_recreate.log 2>&1 + +* * * * * /usr/local/bin/php /var/www/openloyalty/bin/console ol:points:transfers:expire > /var/log/cron_ol_points_expire.log 2>&1 diff --git a/docker/prod/php/conf/supervisord/conf.d/cron.conf b/docker/prod/php/conf/supervisord/conf.d/cron.conf new file mode 100644 index 00000000..b9609adf --- /dev/null +++ b/docker/prod/php/conf/supervisord/conf.d/cron.conf @@ -0,0 +1,4 @@ +[program:cron] +command=cron -f -L 15 +autostart=true +autorestart=true \ No newline at end of file diff --git a/docker/prod/php/conf/supervisord/conf.d/php-fpm.conf b/docker/prod/php/conf/supervisord/conf.d/php-fpm.conf new file mode 100644 index 00000000..2096a882 --- /dev/null +++ b/docker/prod/php/conf/supervisord/conf.d/php-fpm.conf @@ -0,0 +1,12 @@ +[program:php-fpm] +command=php-fpm +autostart=true +autorestart=true +priority=5 +stdout_events_enabled=true +stderr_events_enabled=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true diff --git a/docker/prod/php/conf/supervisord/supervisord.conf b/docker/prod/php/conf/supervisord/supervisord.conf new file mode 100644 index 00000000..17ae0e61 --- /dev/null +++ b/docker/prod/php/conf/supervisord/supervisord.conf @@ -0,0 +1,27 @@ +[supervisord] +logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=false ; (start in foreground if true;default false) +minfds=1024 ; (min. avail startup file descriptors;default 1024) +minprocs=200 ; (min. avail process descriptors;default 200) + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=http://127.0.0.1:9001 ; use a unix:// URL for a unix socket + +[include] +files = /etc/supervisord/conf.d/*.conf + +[eventlistener:stdout] +command = supervisor_stdout +buffer_size = 100 +events = PROCESS_LOG +result_handler = supervisor_stdout:event_handler diff --git a/docker/prod/php/fpm-dockerfile b/docker/prod/php/fpm-dockerfile new file mode 100644 index 00000000..2f840a2a --- /dev/null +++ b/docker/prod/php/fpm-dockerfile @@ -0,0 +1,26 @@ +FROM composer/composer:1.1-alpine AS composer +FROM divante/open-loyalty-base-php-fpm AS base + +ENV SYMFONY_ENV="prod" + +RUN easy_install supervisor +RUN easy_install supervisor-stdout +COPY ./docker/prod/php/conf/supervisord/ /etc/supervisord/ +COPY ./docker/prod/php/conf/crontab.txt /var/crontab.txt +RUN crontab /var/crontab.txt +RUN chmod 600 /etc/crontab + +ADD https://www.phing.info/get/phing-latest.phar /usr/local/bin/phing +RUN chmod a+x /usr/local/bin/phing +RUN chown www-data:www-data /usr/local/bin/phing + +COPY ./backend /var/www/openloyalty +COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer + +RUN mkdir /var/www/openloyalty/var/cache && chmod 755 /var/www/openloyalty/var && chmod 755 /var/www/openloyalty/var/cache && chmod 755 /var/www/openloyalty/var/logs + +WORKDIR /var/www/openloyalty +COPY ./docker/prod/php/bin/init.sh init.sh +RUN chmod a+x init.sh && rm web/app_dev.php && composer install --no-dev -o --prefer-dist && bin/console assets:install && rm web/config.php && chown -R www-data:www-data /var/www/openloyalty/var + +CMD ["./init.sh"] diff --git a/docker/prod/web/app-dockerfile b/docker/prod/web/app-dockerfile new file mode 100644 index 00000000..8718d13c --- /dev/null +++ b/docker/prod/web/app-dockerfile @@ -0,0 +1,17 @@ +FROM divante/open-loyalty-base-nodejs AS front + +COPY ./frontend /var/www/frontend +WORKDIR /var/www/frontend +RUN npm rebuild node-sass && yarn install && npm run-script build + +FROM divante/open-loyalty-base-nginx as www + +RUN usermod -u 1000 www-data +COPY ./docker/prod/web/bin/init.sh init.sh +RUN chmod a+x init.sh +COPY ./docker/prod/web/backend.conf /etc/nginx/conf.d/backend.conf +COPY ./backend/web/ /var/www/openloyalty/web +COPY ./docker/prod/web/frontend.conf /etc/nginx/conf.d/front.conf +COPY --from=front /var/www/frontend/dist /var/www/openloyalty/front +COPY --from=front /var/www/frontend/rancher/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh diff --git a/docker/prod/web/backend.conf b/docker/prod/web/backend.conf new file mode 100644 index 00000000..c166bf33 --- /dev/null +++ b/docker/prod/web/backend.conf @@ -0,0 +1,36 @@ +server { + root /var/www/openloyalty/web; + listen 80; + + location / { + # try to serve file directly, fallback to app.php + try_files $uri /app.php$is_args$args; + } + # DEV + # This rule should only be placed on your development environment + # In production, don't include this and don't deploy app_dev.php or config.php + location ~ ^/app\.php(/|$) { + fastcgi_pass php:9000; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + # When you are using symlinks to link the document root to the + # current version of your application, you should pass the real + # application path instead of the path to the symlink to PHP + # FPM. + # Otherwise, PHP's OPcache may not properly detect changes to + # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 + # for more information). + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + } + + + # return 404 for all other php files not matching the front controller + # this prevents access to other php files you don't want to be accessible. + location ~ \.php$ { + return 404; + } + + error_log /var/log/nginx/openloyalty_error.log; + access_log /var/log/nginx/openloyalty_access.log; +} diff --git a/docker/prod/web/bin/init.sh b/docker/prod/web/bin/init.sh new file mode 100755 index 00000000..1badcb93 --- /dev/null +++ b/docker/prod/web/bin/init.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +if ! [ -z "$BACKEND_API_URL" ]; then + sed -i -e 's/APIURL/'"${BACKEND_API_URL}"'/g' /var/www/openloyalty/front/assets/js/commons.js +fi diff --git a/docker/prod/web/frontend.conf b/docker/prod/web/frontend.conf new file mode 100644 index 00000000..c0222225 --- /dev/null +++ b/docker/prod/web/frontend.conf @@ -0,0 +1,23 @@ +server { + listen 3001; + root /var/www/openloyalty/front; + index admin/index.html; + location ~* \.(?:js|css|jpg|jpeg|gif|png|svg|ico|pdf|html|htm)$ { + } +} + +server { + listen 3002; + root /var/www/openloyalty/front; + index client/index.html; + location ~* \.(?:js|css|jpg|jpeg|gif|png|svg|ico|pdf|html|htm)$ { + } +} + +server { + listen 3003; + root /var/www/openloyalty/front; + index pos/index.html; + location ~* \.(?:js|css|jpg|jpeg|gif|png|svg|ico|pdf|html|htm)$ { + } +} \ No newline at end of file diff --git a/docker/prod/web/parameters.json b/docker/prod/web/parameters.json new file mode 100644 index 00000000..0c7a4bcb --- /dev/null +++ b/docker/prod/web/parameters.json @@ -0,0 +1,8 @@ +{ + "apiUrl": "http://openloyalty.localhost/api", + "dateFormat": "YYYY-MM-DD", + "dateTimeFormat": "YYYY-MM-DD HH:mm", + "perPage": 20, + "debug": false, + "modules": [] +} diff --git a/frontend/.eslintrc b/frontend/.eslintrc new file mode 100644 index 00000000..ad1baffc --- /dev/null +++ b/frontend/.eslintrc @@ -0,0 +1,26 @@ +{ + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "env": { + "browser": true, + "amd": true, + "es6": true, + "node": true + }, + "rules": { + "comma-dangle": 1, + "quotes": [ 1, "single" ], + "no-undef": 1, + "global-strict": 0, + "no-extra-semi": 1, + "no-underscore-dangle": 0, + "no-console": 1, + "no-unused-vars": 1, + "no-trailing-spaces": [1, { "skipBlankLines": true }], + "no-unreachable": 1, + "no-alert": 0 + } +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..49582351 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,6 @@ +dist/ +node_modules/ +.idea/ +dev/reports/ +npm-debug.log +docs/sass diff --git a/frontend/.sass-lint.yml b/frontend/.sass-lint.yml new file mode 100644 index 00000000..d4123bc6 --- /dev/null +++ b/frontend/.sass-lint.yml @@ -0,0 +1,49 @@ +files: + include: + - 'src/**/*.s+(a|c)ss' + +# Linter Options +options: + merge-default-rules: false + +# Rule Configuration +rules: + brace-style: + - 2 + - + style: 'stroustrup' + clean-import-paths: 2 + extends-before-declarations: 2 + extends-before-mixins: 2 + final-newline: 2 + indentation: + - 2 + - + size: 4 + leading-zero: + - 2 + - + include: true + no-css-comments: 2 + no-debug: 1 + no-empty-rulesets: 2 + no-ids: 1 + no-important: 1 + no-invalid-hex: 2 + no-misspelled-properties: + - 2 + - + extra-properties: + - 'touch-callout' + - 'overflow-scrolling' + no-vendor-prefixes: 1 + no-warn: 1 + one-declaration-per-line: 2 + single-line-per-selector: 2 + space-after-colon: 2 + space-after-comma: 2 + space-around-operator: 2 + space-before-bang: 2 + space-before-brace: 2 + trailing-semicolon: 2 + zero-unit: 2 diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index 73a74243..00000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:5 - -RUN apt-get update \ - && apt-get install -y ruby-full rubygems \ - && gem instal sass -RUN npm install -g gulp node-sass yarn -COPY . /var/www -WORKDIR /var/www -EXPOSE 3000 - -CMD npm rebuild node-sass && yarn install && gulp config --prod && gulp compile && gulp prod \ No newline at end of file diff --git a/frontend/config.js.dist b/frontend/config.js.dist deleted file mode 100644 index 4bfce031..00000000 --- a/frontend/config.js.dist +++ /dev/null @@ -1,2 +0,0 @@ -const config = {$$jsonConfig} -window.OpenLoyaltyConfig = {$$jsonConfig} \ No newline at end of file diff --git a/frontend/dev/accessibility-validation.js b/frontend/dev/accessibility-validation.js new file mode 100644 index 00000000..c2a98666 --- /dev/null +++ b/frontend/dev/accessibility-validation.js @@ -0,0 +1,14 @@ +var AccessSniff = require('access-sniff'); + +var options = { + accessibilityLevel: 'WCAG2AAA' +}; + + +AccessSniff + .default(['dist/**/*.html'], options) + .then(function(report) { + AccessSniff.report(report); + }, function(error) { + console.error(error) + }); diff --git a/frontend/dev/html-validator.js b/frontend/dev/html-validator.js new file mode 100644 index 00000000..08e90356 --- /dev/null +++ b/frontend/dev/html-validator.js @@ -0,0 +1,31 @@ +var validator = require('html-validator'); +var fs = require('fs'); +var options = { + validator: 'http://html5.validator.nu', + format: 'text' +}; + +var Filehound = require('filehound'); + +Filehound.create() + .ext('html') + .paths("./dist") + .find((err, htmlFiles) => { + if (err) return console.error('handle err', err); + + htmlFiles.forEach(function(filename) { + fs.readFile(filename, function(err, content) { + if (err) { + throw err; + } + options.data = content; + validator(options, (error, data) => { + if (error) { + console.error(error) + } + + console.log(filename + '\n' + data) + }) + }); + }); + }); diff --git a/frontend/dev/sassdoc.js b/frontend/dev/sassdoc.js new file mode 100644 index 00000000..e87ce8fb --- /dev/null +++ b/frontend/dev/sassdoc.js @@ -0,0 +1,6 @@ +var sassdoc = require('sassdoc'); +var source = './src/**/*.scss'; +var config = { + dest: './docs/sass' +}; +sassdoc(source, config); diff --git a/frontend/docs/index.html b/frontend/docs/index.html new file mode 100644 index 00000000..fd77b434 --- /dev/null +++ b/frontend/docs/index.html @@ -0,0 +1,16 @@ + + + + + Project documentation + + +

Project documentation:

+ + + + diff --git a/frontend/docs/main.js b/frontend/docs/main.js new file mode 100644 index 00000000..e69de29b diff --git a/frontend/karma.conf.js b/frontend/karma.conf.js index 160f730e..745b41f6 100644 --- a/frontend/karma.conf.js +++ b/frontend/karma.conf.js @@ -1,71 +1,50 @@ -// Karma configuration -// Generated on Fri Sep 09 2016 08:39:24 GMT+0200 (CEST) +var path = require('path'); module.exports = function (config) { config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', - - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['jasmine'], - - - // list of files / patterns to load in the browser files: [ - 'dist/assets.js', - 'dist/app.js', - 'test/TestUtils.js', - 'node_modules/angular-mocks/angular-mocks.js', - 'test/*.js' + 'test/loadtests.js' ], - - - // list of files to exclude exclude: [], - - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: {}, - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['spec'], - - - // web server port + preprocessors: { + 'test/loadtests.js': ['webpack', 'sourcemap'] + }, + webpack: { + module: { + rules: [ + { + test: /\.js$/, + include: [ + path.resolve(__dirname, 'src'), + path.resolve(__dirname, 'test') + ], + use: [{ + loader: 'babel-loader', + options: { + presets: [ + ['es2015', { modules: false }] + ] + } + }] + } + ] + } + }, + reporters: ['progress'], port: 9876, - - - // enable / disable colors in the output (reporters and logs) colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, - - - // enable / disable watching file and executing tests whenever any file changes autoWatch: false, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Chrome'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits + browsers: ['PhantomJS'], singleRun: true, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: Infinity + concurrency: Infinity, + plugins: [ + 'karma-webpack', + 'karma-jasmine', + 'karma-sourcemap-loader', + 'karma-phantomjs-launcher' + ] }) -} +}; diff --git a/frontend/package.json b/frontend/package.json index 5c28f9e6..dab8e8c7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,78 +1,91 @@ { - "name": "openloyalty", - "version": "0.0.1", + "name": "open-loyalty-frontend", + "version": "1.0.0", "description": "Frontend application for OpenLoyalty", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "prestart": "npm rebuild node-sass", + "start": "webpack-dev-server --inline --content-base dist --host 0.0.0.0 --port 8081", + "eslint": "./node_modules/.bin/eslint src/*.js", + "accessibility": "node ./dev/accessibility-validation.js", + "htmllint": "node ./dev/html-validator.js", + "sasslint": "node ./node_modules/sass-lint/bin/sass-lint.js -v -q", + "test": "npm run build && karma start && npm run eslint && npm run accessibility && npm run htmllint && npm run sasslint", + "build": "rm -rf dist/ && webpack", + "sassdoc": "node ./dev/sassdoc.js", + "docsserver": "npm run sassdoc && webpack-dev-server --port 8010 --config webpack.docs.config.js --content-base ./docs/ --open" }, - "author": "Divante sp. z o.o.", + "keywords": [ + "frontend", + "webpack" + ], + "author": "Divante Ltd.", "license": "ISC", "devDependencies": { + "access-sniff": "^3.0.1", + "autoprefixer": "^6.7.7", + "babel-core": "^6.23.1", + "babel-eslint": "^7.1.1", + "babel-loader": "^6.4.0", + "babel-preset-es2015": "^6.22.0", + "css-loader": "^0.26.4", + "cssnano": "^3.10.0", + "eslint": "^3.18.0", + "extract-loader": "^0.1.0", + "extract-text-webpack-plugin": "^2.0.0-beta.4", + "file-loader": "^0.10.1", + "filehound": "^1.16.0", + "html-loader": "^0.4.5", + "html-validator": "^2.2.0", + "jasmine-core": "^2.5.2", + "karma": "^1.5.0", + "karma-jasmine": "^1.1.0", + "karma-phantomjs-launcher": "^1.0.4", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^2.0.3", + "node-sass": "^4.5.2", + "postcss-loader": "^1.3.3", + "sass-lint": "^1.10.2", + "sass-loader": "^6.0.3", + "style-loader": "^0.13.2", + "url-loader": "^0.5.8", + "webpack": "^2.2.1", + "webpack-dev-server": "^2.0.0-beta", + "sassdoc": "^2.2.2", "angular-mocks": "^1.5.8", - "babel-core": "^6.21.0", - "babel-preset-es2015": "^6.18.0", "babelify": "^7.3.0", "browser-sync": "^2.13.0", "browserify": "^13.1.0", - "gulp": "^3.9.1", - "gulp-assets": "^0.2.2", - "gulp-babel": "^6.1.2", - "gulp-browserify": "^0.5.1", - "gulp-clean-css": "^2.0.12", - "gulp-cli": "^1.2.2", - "gulp-concat": "^2.6.1", - "gulp-confirm": "^1.0.4", - "gulp-connect-multi": "^1.0.8", - "gulp-copy": "0.0.2", - "gulp-file-include": "^0.13.7", - "gulp-flatten": "^0.3.1", - "gulp-htmlbuild": "^0.4.2", - "gulp-inject": "^4.1.0", - "gulp-ng-annotate": "^2.0.0", - "gulp-pipemin": "^2.2.4", - "gulp-rename": "^1.2.2", - "gulp-replace": "^0.5.4", - "gulp-replace-path": "^0.4.0", - "gulp-sass": "^2.3.2", - "gulp-uglify": "^2.0.0", - "gulp-util": "^3.0.7", "jasmine": "^2.5.1", - "jasmine-core": "^2.5.1", - "karma": "^1.2.0", "karma-chrome-launcher": "^2.0.0", - "karma-jasmine": "^1.0.2", - "karma-phantomjs-launcher": "^1.0.2", "karma-spec-reporter": "0.0.26", "merge-stream": "^1.0.1", "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0" + "vinyl-source-stream": "^1.1.0", + "concurrently": "^3.5.0" }, "dependencies": { "ace-angular": "^0.1.1", - "ace-builds": "^1.2.6", - "angular": "1.5", - "angular-animate": "1.5.1", + "angular": "1.6.6", + "angular-animate": "1.6.6", "angular-chart.js": "^1.0.3", "angular-flash-alert": "^2.3.0", "angular-jwt": "0.0.9", - "angular-legacy-sortablejs": "^0.4.1", + "angular-legacy-sortablejs-maintained": "^0.5.2", "angular-loading-bar": "^0.9.0", "angular-mm-foundation": "^0.7.0-SNAPSHOT", "angular-moment": "^1.0.0-beta.6", - "angular-sanitize": "^1.5.8", + "angular-sanitize": "^1.6.6", "angular-selectize2": "^1.2.3", "angular-translate": "^2.12.0", "angular-ui-router": "^0.3.1", "autoprefixer": "^6.3.7", + "brace": "^0.10.0", "chart.js": "^2.2.2", - "extract-text-webpack-plugin": "^1.0.1", + "copy-webpack-plugin": "^4.2.0", "font-awesome": "^4.6.3", "foundation": "^4.2.1-1", - "foundation-sites": "^6.2.3", - "gulp-connect": "^5.0.0", - "gulp-connect-multi": "^1.0.8", - "gulp-rename": "^1.2.2", + "foundation-sites": "6.2.3", "jquery": "2.2.4", "jquery-datetimepicker": "^2.5.4", "jsoneditor": "^5.5.11", diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 00000000..9ba8003d --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,8 @@ +module.exports = { + plugins: [ + require('autoprefixer')({ + browsers: ['last 2 versions', 'ie >= 11'] + }), + require('cssnano')() + ] +}; diff --git a/frontend/rancher/entrypoint.sh b/frontend/rancher/entrypoint.sh new file mode 100644 index 00000000..698fe175 --- /dev/null +++ b/frontend/rancher/entrypoint.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +sed -i -e 's@"http://openloyalty.localhost/api"@'\"${API_HOST}\"'@g' /var/www/openloyalty/front/config.js +nginx -g 'daemon off;' diff --git a/frontend/src/appAdmin.js b/frontend/src/appAdmin.js index 2a1920f5..dad54f5e 100644 --- a/frontend/src/appAdmin.js +++ b/frontend/src/appAdmin.js @@ -1,5 +1,49 @@ +require('./templates/admin.html'); + var _ = require('lodash'); +// import jquery +import 'jquery'; +import 'foundation-sites/dist/foundation'; +import 'jquery-datetimepicker'; +import 'chart.js/src/chart'; +import 'select2'; +import angular from 'angular'; +import 'sortablejs/Sortable'; +import 'microplugin'; +import 'sifter'; +import 'angular-legacy-sortablejs-maintained'; +import 'angular-translate'; +import 'angular-sanitize'; +import 'ng-table'; +import 'angular-moment'; +import 'angular-ui-router'; +import 'restangular'; +import 'angular-jwt/'; +import 'ui-select'; +import 'pickadate/lib/picker'; +import 'angular-flash-alert'; +window.Selectize = require('selectize'); +import 'angular-selectize2/dist/selectize'; +import 'angular-chart.js/angular-chart'; +window.JSONEditor = require('jsoneditor'); +import 'ng-jsoneditor'; +require ('brace/mode/json'); +import 'brace'; +import 'angular-animate'; +import 'angular-loading-bar'; +import 'ace-angular'; + +// global styles +import 'pickadate/lib/themes/classic.css'; +import 'pickadate/lib/themes/classic.date.css'; +import 'angular-flash-alert/dist/angular-flash.min.css'; +import 'ui-select/dist/select.min.css'; +import 'selectize/dist/css/selectize.css'; +import 'jquery-datetimepicker/jquery.datetimepicker.css'; +import 'jsoneditor/dist/jsoneditor.min.css'; +import 'angular-loading-bar/build/loading-bar.css'; + import EditableMap from './component/global/map/EditableMap'; import ParamsMap from './component/global/map/ParamsMap'; import Validation from './component/global/validation/Validation'; @@ -30,6 +74,32 @@ import DebugController from './component/global/debug/DebugController'; import Filters from './component/global/filters/Filters'; +// global scss +import './style/main.scss'; + +// global js +import './scripts/main'; + +// open loyalty modules +require('./modules/admin.campaign/module.js'); +require('./modules/admin.customers/module.js'); +require('./modules/admin.dashboard/module.js'); +require('./modules/admin.data/module.js'); +require('./modules/admin.earning-rules/module.js'); +require('./modules/admin.levels/module.js'); +require('./modules/admin.login/module.js'); +require('./modules/admin.partials/module.js'); +require('./modules/admin.pos/module.js'); +require('./modules/admin.segment/module.js'); +require('./modules/admin.seller/module.js'); +require('./modules/admin.settings/module.js'); +require('./modules/admin.transactions/module.js'); +require('./modules/admin.transfers/module.js'); +require('./modules/admin.translations/module.js'); +require('./modules/admin.users/module.js'); +require('./modules/admin.emails/module.js'); +require('./modules/admin.logs/module.js'); + if (!window.OpenLoyaltyConfig.debug) { if (!window.console) window.console = {}; var methods = ["log", "debug", "warn", "info"]; @@ -40,40 +110,40 @@ if (!window.OpenLoyaltyConfig.debug) { } angular.module('OpenLoyalty', [ - 'ui.router', - 'ace.angular', - 'angular-jwt', - 'restangular', - 'ngFlash', - 'angularMoment', - 'ngTable', - 'ui.select', - 'ngSanitize', - 'ng-sortable', - 'pascalprecht.translate', - 'selectize', - 'chart.js', - 'ng.jsoneditor', - 'angular-loading-bar', - 'ngAnimate', - 'admin.campaign', - 'admin.customers', - 'admin.dashboard', - 'admin.data', - 'admin.earning-rules', - 'admin.levels', - 'admin.login', - 'admin.partials', - 'admin.pos', - 'admin.segment', - 'admin.seller', - 'admin.settings', - 'admin.transactions', - 'admin.transfers', - 'admin.translations', - 'admin.users', - 'admin.emails', - 'admin.logs' + 'ui.router', + 'angular-jwt', + 'restangular', + 'ngFlash', + 'angularMoment', + 'ngTable', + 'ui.select', + 'ngSanitize', + 'ng-sortable', + 'pascalprecht.translate', + 'selectize', + 'chart.js', + 'ng.jsoneditor', + 'ace.angular', + 'angular-loading-bar', + 'ngAnimate', + 'admin.campaign', + 'admin.customers', + 'admin.dashboard', + 'admin.data', + 'admin.earning-rules', + 'admin.levels', + 'admin.login', + 'admin.partials', + 'admin.pos', + 'admin.segment', + 'admin.seller', + 'admin.settings', + 'admin.transactions', + 'admin.transfers', + 'admin.translations', + 'admin.users', + 'admin.emails', + 'admin.logs' ]) .config(function ($stateProvider, $urlRouterProvider, $httpProvider, jwtInterceptorProvider, RestangularProvider, $translateProvider, $locationProvider, cfpLoadingBarProvider) { let config = window.OpenLoyaltyConfig; @@ -149,19 +219,19 @@ angular.module('OpenLoyalty', [ $stateProvider .state('admin-login', { url: "/", - templateUrl: './templates/login.html', + templateUrl: require('./modules/admin.login/templates/login.html'), controller: 'LoginController', controllerAs: 'LoginCtrl' }) .state('forgot-password-request-admin', { url: "/admin/password/request", - templateUrl: './templates/password-request.html', + templateUrl: require('./modules/admin.login/templates/password-request.html'), controller: 'SecurityController', controllerAs: 'SecurityCtrl' }) .state('forgot-password-reset-admin', { url: "/password/reset/:token", - templateUrl: './templates/password-reset.html', + templateUrl: require('./modules/admin.login/templates/password-reset.html'), controller: 'SecurityController', controllerAs: 'SecurityCtrl' }) @@ -169,7 +239,7 @@ angular.module('OpenLoyalty', [ url: "/page/:pageName", views: { '@': { - templateUrl: './templates/static-pages.html', + templateUrl: require('./component/global/pages/templates/static-pages.html'), controller: 'StaticPagesController', controllerAs: 'StaticPagesCtrl' } @@ -181,7 +251,7 @@ angular.module('OpenLoyalty', [ url: "/debug", views: { '@': { - templateUrl: './templates/debug.html', + templateUrl: require('./component/global/debug/templates/debug.html'), controller: 'DebugController', controllerAs: 'DebugCtrl' } diff --git a/frontend/src/appClient.js b/frontend/src/appClient.js new file mode 100644 index 00000000..af1a338e --- /dev/null +++ b/frontend/src/appClient.js @@ -0,0 +1,274 @@ +require('./templates/client.html'); + +var _ = require('lodash'); + +// import jquery +import 'jquery'; +import 'foundation-sites/dist/foundation'; +import 'jquery-datetimepicker'; +import 'chart.js/src/chart'; +import 'select2'; +import angular from 'angular'; +import 'sortablejs/Sortable'; +import 'microplugin'; +import 'sifter'; +import 'angular-legacy-sortablejs-maintained'; +import 'angular-translate'; +import 'angular-sanitize'; +import 'ng-table'; +import 'angular-moment'; +import 'angular-ui-router'; +import 'restangular'; +import 'angular-jwt/'; +import 'ui-select'; +import 'pickadate/lib/picker'; +import 'angular-flash-alert'; +window.Selectize = require('selectize'); +import 'angular-selectize2/dist/selectize'; +import 'angular-chart.js/angular-chart'; +import 'angular-loading-bar'; + +// global styles +import 'pickadate/lib/themes/classic.css'; +import 'pickadate/lib/themes/classic.date.css'; +import 'angular-flash-alert/dist/angular-flash.min.css'; +import 'ui-select/dist/select.min.css'; +import 'selectize/dist/css/selectize.css'; +import 'jquery-datetimepicker/jquery.datetimepicker.css'; +import 'angular-loading-bar/build/loading-bar.css'; + +import EditableMap from './component/global/map/EditableMap'; +import ParamsMap from './component/global/map/ParamsMap'; +import CheckboxDirective from './component/global/checkbox/CheckboxDirective'; +import ModalDirective from './component/global/modal/ModalDirective'; +import DatepickerDirective from './component/global/datepicker/DatepickerDirective'; +import FormValidationDirective from './component/global/validation/FormValidationDirective'; +import CsvUploadDirective from './component/global/csv/CsvUploadDirective'; +import SecurityController from './component/global/security/SecurityController'; +import SecurityService from './component/global/security/SecurityService'; +import DataService from './component/global/data/DataService'; +import Validation from './component/global/validation/Validation'; +import TranslationService from './component/global/translations/TranslationService'; +import TranslationLoader from './component/global/translations/TranslationLoader'; +import AuthService from './component/global/auth/AuthService'; +import RootController from './component/global/root/RootController'; +import StaticPagesController from './component/global/pages/StaticPagesController'; +import StaticPagesDirective from './component/global/pages/StaticPagesDirective'; +import BoxLoaderDirective from './component/global/boxLoader/BoxLoaderDirective'; +import Filters from './component/global/filters/Filters'; +import DebugController from './component/global/debug/DebugController'; + +// global scss +import './style/main.scss'; + +// global js +import './scripts/main'; + +// open loyalty modules +require('./modules/client.campaign/module.js'); +require('./modules/client.dashboard/module.js'); +require('./modules/client.earning-rules/module.js'); +require('./modules/client.login/module.js'); +require('./modules/client.partials/module.js'); +require('./modules/client.profile/module.js'); +require('./modules/client.registration/module.js'); +require('./modules/client.transactions/module.js'); +require('./modules/client.transfers/module.js'); + +if (!window.OpenLoyaltyConfig.debug) { + if (!window.console) window.console = {}; + var methods = ["log", "debug", "warn", "info"]; + for (var i = 0; i < methods.length; i++) { + console[methods[i]] = function () { + }; + } +} + +angular.module('OpenLoyalty', [ + 'ui.router', + 'angular-jwt', + 'restangular', + 'ngFlash', + 'angularMoment', + 'ngTable', + 'ui.select', + 'ngSanitize', + 'angular-loading-bar', + 'ng-sortable', + 'pascalprecht.translate', + 'selectize', + 'client.campaign', + 'client.dashboard', + 'client.earning-rules', + 'client.login', + 'client.partials', + 'client.profile', + 'client.registration', + 'client.transactions', + 'client.transfers', +]) + + .config(function ($stateProvider, $urlRouterProvider, $httpProvider, jwtInterceptorProvider, RestangularProvider, $translateProvider, $locationProvider, cfpLoadingBarProvider) { + let config = window.OpenLoyaltyConfig; + + cfpLoadingBarProvider.includeSpinner = false; + $locationProvider.hashPrefix('!'); + $translateProvider.useLoader('TranslationLoader'); + $translateProvider.preferredLanguage('en'); + + RestangularProvider.setBaseUrl(config.apiUrl); + + RestangularProvider.addResponseInterceptor(function (data, operation, what, url, response, $state) { + var extractedData = data; + + if (extractedData.customers) { + for (let i in data.customers) { + if (extractedData.customers[i].customerId) { + extractedData.customers[i].id = extractedData.customers[i].customerId + } + } + } + if (extractedData.customerId) { + extractedData.id = extractedData.customerId + } + if (extractedData.campaignId) { + extractedData.id = extractedData.campaignId + } + + if (operation === "getList") { + let keys = Object.keys(data); + extractedData = data[keys[0]]; + extractedData.total = data.total; + } + + return extractedData; + }); + + jwtInterceptorProvider.tokenGetter = ['AuthService', 'jwtHelper', 'config', '$state', function (AuthService, jwtHelper, config, $state) { + if (config.url.indexOf('login_check') !== -1 || config.url.indexOf('token/refresh') !== -1) { + return null; + } + + let idToken = AuthService.getStoredToken(); + + if (idToken && jwtHelper.isTokenExpired(idToken) && AuthService.isRememberMe()) { + return AuthService.getRefreshToken() + .then( + res => { + let id_token = res.token; + let refresh_token = res.refresh_token; + + AuthService.setStoredRefreshToken(refresh_token); + AuthService.setStoredToken(id_token); + + return id_token; + }, + res => { + AuthService.logout(); + } + ); + } else if (idToken && !jwtHelper.isTokenExpired(idToken)) { + return idToken; + } else { + return null + } + }]; + + $httpProvider.interceptors.push('jwtInterceptor'); + + $urlRouterProvider + .otherwise("/"); + $stateProvider + .state('customer', { + url: "/customer" + }) + .state('customer.panel', { + url: "/panel", + resolve: { + DataServiceResolver: ['DataService', function (DataService) { + return DataService.getAvailableData() + }] + } + }) + .state('customer.static', { + url: "/page/:pageName", + views: { + '@': { + templateUrl: require('./component/global/pages/templates/static-pages.html'), + controller: 'StaticPagesController', + controllerAs: 'StaticPagesCtrl' + } + } + }) + + + if (window.OpenLoyaltyConfig.debug) { + $stateProvider.state('debug', { + url: "/debug", + views: { + '@': { + templateUrl: require('./component/global/debug/templates/debug.html'), + controller: 'DebugController', + controllerAs: 'DebugCtrl' + } + } + }); + } + }) + + .run(['Restangular', '$state', 'AuthService', '$rootScope', '$templateCache', function (Restangular, $state, AuthService, $rootScope, $templateCache) { + $rootScope.pendingRequests = _.isNumber($rootScope.pendingRequests) ? $rootScope.pendingRequests : 0; + Restangular.setErrorInterceptor(function (response) { + $rootScope.pendingRequests -= 1; + if (response.data.message && response.data.message === 'Bad credentials') { + return true; + } + if (response.status === 401) { + AuthService.logout(); + return false; + } + return true; + }); + Restangular.addResponseInterceptor(res => { + $rootScope.pendingRequests -= 1; + + return res; + }); + Restangular.addRequestInterceptor(req => { + $rootScope.pendingRequests += 1; + + return req; + }); + $templateCache.put('ng-table/filters/text.html', ' '); + $templateCache.put('ng-table/filters/number.html', ' '); + + }]) + + .filter('commaToDot', () => new Filters.CommaToDecimal()) + .filter('percent', () => new Filters.Percent()) + .filter('propsFilter', () => new Filters.PropsFilter()) + .filter('isEmpty', () => new Filters.IsEmptyFilter()) + + .directive('modal', () => new ModalDirective()) + .directive('datepicker', () => new DatepickerDirective()) + .directive('formValidation', () => new FormValidationDirective()) + .directive('csvUpload', () => new CsvUploadDirective()) + .directive('checkbox', () => new CheckboxDirective()) + .directive('staticPage', () => new StaticPagesDirective()) + .directive('boxLoader', BoxLoaderDirective.create) + + + .service('Validation', Validation) + .service('EditableMap', EditableMap) + .service('ParamsMap', ParamsMap) + .service('DataService', DataService) + .service('Validation', Validation) + .service('AuthService', AuthService) + .service('SecurityService', SecurityService) + .service('TranslationService', TranslationService) + .factory('TranslationLoader', ['TranslationService', (TranslationService) => new TranslationLoader(TranslationService)]) + + .controller('RootController', RootController) + .controller('SecurityController', SecurityController) + .controller('StaticPagesController', StaticPagesController) + .controller('DebugController', DebugController) diff --git a/frontend/src/appPos.js b/frontend/src/appPos.js new file mode 100644 index 00000000..f486340f --- /dev/null +++ b/frontend/src/appPos.js @@ -0,0 +1,258 @@ +require('./templates/pos.html'); + +var _ = require('lodash'); + +// import jquery +import 'jquery'; +import 'foundation-sites/dist/foundation'; +import 'jquery-datetimepicker'; +import 'chart.js/src/chart'; +import 'select2'; +import angular from 'angular'; +import 'sortablejs/Sortable'; +import 'microplugin'; +import 'sifter'; +import 'angular-legacy-sortablejs-maintained'; +import 'angular-translate'; +import 'angular-sanitize'; +import 'ng-table'; +import 'angular-moment'; +import 'angular-ui-router'; +import 'restangular'; +import 'angular-jwt/'; +import 'ui-select'; +import 'pickadate/lib/picker'; +import 'angular-flash-alert'; +window.Selectize = require('selectize'); +import 'angular-selectize2/dist/selectize'; +import 'angular-chart.js/angular-chart'; +import 'angular-loading-bar'; + +// global styles +import 'pickadate/lib/themes/classic.css'; +import 'pickadate/lib/themes/classic.date.css'; +import 'angular-flash-alert/dist/angular-flash.min.css'; +import 'ui-select/dist/select.min.css'; +import 'selectize/dist/css/selectize.css'; +import 'jquery-datetimepicker/jquery.datetimepicker.css'; +import 'angular-loading-bar/build/loading-bar.css'; + +import EditableMap from './component/global/map/EditableMap'; +import ParamsMap from './component/global/map/ParamsMap'; +import Validation from './component/global/validation/Validation'; + +import CheckboxDirective from './component/global/checkbox/CheckboxDirective'; +import ModalDirective from './component/global/modal/ModalDirective'; +import DatepickerDirective from './component/global/datepicker/DatepickerDirective'; +import FormValidationDirective from './component/global/validation/FormValidationDirective'; +import CsvUploadDirective from './component/global/csv/CsvUploadDirective'; +import BoxLoaderDirective from './component/global/boxLoader/BoxLoaderDirective'; +import SecurityController from './component/global/security/SecurityController'; +import SecurityService from './component/global/security/SecurityService'; +import DataService from './component/global/data/DataService'; +import AuthService from './component/global/auth/AuthService'; +import TranslationService from './component/global/translations/TranslationService'; +import TranslationLoader from './component/global/translations/TranslationLoader'; + + +import RootController from './component/global/root/RootController'; +import Filters from './component/global/filters/Filters'; + +import DebugController from './component/global/debug/DebugController'; + +// global scss +import './style/main.scss'; + +// global js +import './scripts/main'; + +// open loyalty modules +require('./modules/pos.login/module.js'); +require('./modules/pos.campaigns/module.js'); +require('./modules/pos.dashboard/module.js'); +require('./modules/pos.earning-rules/module.js'); +require('./modules/pos.partials/module.js'); +require('./modules/pos.customers/module.js'); +require('./modules/pos.transactions/module.js'); + +if (!window.OpenLoyaltyConfig.debug) { + if (!window.console) window.console = {}; + var methods = ["log", "debug", "warn", "info"]; + for (var i = 0; i < methods.length; i++) { + console[methods[i]] = function () { + }; + } +} + +angular.module('OpenLoyalty', [ + 'ui.router', + 'angular-jwt', + 'restangular', + 'ngFlash', + 'angularMoment', + 'ngTable', + 'ui.select', + 'ngSanitize', + 'ng-sortable', + 'pascalprecht.translate', + 'selectize', + 'angular-loading-bar', + 'pos.login', + 'pos.campaigns', + 'pos.customers', + 'pos.dashboard', + 'pos.earning-rules', + 'pos.partials', + 'pos.transactions' +]) + + .config(function ($stateProvider, $urlRouterProvider, $httpProvider, jwtInterceptorProvider, RestangularProvider, $translateProvider, $locationProvider, cfpLoadingBarProvider) { + let config = window.OpenLoyaltyConfig; + + cfpLoadingBarProvider.includeSpinner = false; + $locationProvider.hashPrefix('!'); + $translateProvider.useLoader('TranslationLoader'); + $translateProvider.preferredLanguage('en'); + + RestangularProvider.setBaseUrl(config.apiUrl); + + RestangularProvider.addResponseInterceptor(function (data, operation, what, url, response, $state) { + var extractedData = data; + + if (extractedData.customers) { + for (let i in data.customers) { + if (extractedData.customers[i].customerId) { + extractedData.customers[i].id = extractedData.customers[i].customerId + } + } + } + if (extractedData.customerId) { + extractedData.id = extractedData.customerId + } + if (extractedData.campaignId) { + extractedData.id = extractedData.campaignId + } + + if (operation === "getList") { + let keys = Object.keys(data); + extractedData = data[keys[0]]; + extractedData.total = data.total; + } + + return extractedData; + }); + + jwtInterceptorProvider.tokenGetter = ['AuthService', 'jwtHelper', 'config', '$state', function (AuthService, jwtHelper, config, $state) { + if (config.url.indexOf('login_check') !== -1 || config.url.indexOf('token/refresh') !== -1) { + return null; + } + + let idToken = AuthService.getStoredToken(); + + if (idToken && jwtHelper.isTokenExpired(idToken) && AuthService.isRememberMe()) { + return AuthService.getRefreshToken() + .then( + res => { + let id_token = res.token; + let refresh_token = res.refresh_token; + + AuthService.setStoredRefreshToken(refresh_token); + AuthService.setStoredToken(id_token); + + return id_token; + }, + res => { + AuthService.logout(); + } + ); + } else if (idToken && !jwtHelper.isTokenExpired(idToken)) { + return idToken; + } else { + return null + } + }]; + + $httpProvider.interceptors.push('jwtInterceptor'); + + $urlRouterProvider + .otherwise("/"); + $stateProvider + .state('seller', { + url: "/seller", + resolve: { + DataServiceResolver: ['DataService', function (DataService) { + return DataService.getAvailableData() + }] + } + }) + .state('seller.panel', { + url: "/panel" + }) + + if (window.OpenLoyaltyConfig.debug) { + $stateProvider.state('debug', { + url: "/debug", + views: { + '@': { + templateUrl: require('./component/global/debug/templates/debug.html'), + controller: 'DebugController', + controllerAs: 'DebugCtrl' + } + } + }); + } + }) + + .run(['Restangular', '$state', 'AuthService', '$rootScope', '$templateCache', function (Restangular, $state, AuthService, $rootScope, $templateCache) { + $rootScope.pendingRequests = _.isNumber($rootScope.pendingRequests) ? $rootScope.pendingRequests : 0; + Restangular.setErrorInterceptor(function (response) { + $rootScope.pendingRequests -= 1; + if (response.data.message && response.data.message === 'Bad credentials') { + return true; + } + if (response.status === 401) { + AuthService.logout(); + return false; + } + return true; + }); + Restangular.addResponseInterceptor(res => { + $rootScope.pendingRequests -= 1; + + return res; + }); + Restangular.addRequestInterceptor(req => { + $rootScope.pendingRequests += 1; + + return req; + }); + $templateCache.put('ng-table/filters/text.html', ' '); + $templateCache.put('ng-table/filters/number.html', ' '); + + }]) + .filter('commaToDot', () => new Filters.CommaToDecimal()) + .filter('percent', () => new Filters.Percent()) + .filter('propsFilter', () => new Filters.PropsFilter()) + .filter('isEmpty', () => new Filters.IsEmptyFilter()) + + .directive('modal', () => new ModalDirective()) + .directive('datepicker', () => new DatepickerDirective()) + .directive('formValidation', () => new FormValidationDirective()) + .directive('csvUpload', () => new CsvUploadDirective()) + .directive('checkbox', () => new CheckboxDirective()) + .directive('boxLoader', BoxLoaderDirective.create) + + .service('EditableMap', EditableMap) + .service('ParamsMap', ParamsMap) + .service('DataService', DataService) + .service('Validation', Validation) + .service('AuthService', AuthService) + .service('SecurityService', SecurityService) + + .service('TranslationService', TranslationService) + .factory('TranslationLoader', ['TranslationService', (TranslationService) => new TranslationLoader(TranslationService)]) + + .controller('RootController', RootController) + .controller('SecurityController', SecurityController) + + .controller('DebugController', DebugController) diff --git a/frontend/src/component/global/boxLoader/BoxLoaderDirective.js b/frontend/src/component/global/boxLoader/BoxLoaderDirective.js index 7f8c15ef..b361b668 100644 --- a/frontend/src/component/global/boxLoader/BoxLoaderDirective.js +++ b/frontend/src/component/global/boxLoader/BoxLoaderDirective.js @@ -15,7 +15,7 @@ export default class BoxLoaderDirective { delay: '=?', cover: '=?' }; - this.templateUrl = './templates/box-loader.html'; + this.templateUrl = require('./templates/box-loader.html'); this.link = (scope, element) => { element.parent().addClass('loader-relative'); @@ -48,4 +48,4 @@ export default class BoxLoaderDirective { } } -BoxLoaderDirective.create.$inject = ['$timeout']; \ No newline at end of file +BoxLoaderDirective.create.$inject = ['$timeout']; diff --git a/frontend/src/component/global/checkbox/CheckboxDirective.js b/frontend/src/component/global/checkbox/CheckboxDirective.js index 2b1a4b47..f4bae523 100644 --- a/frontend/src/component/global/checkbox/CheckboxDirective.js +++ b/frontend/src/component/global/checkbox/CheckboxDirective.js @@ -2,7 +2,7 @@ export default class CheckboxDirective { constructor() { this.restrict = 'E'; this.require = '?ngModel'; - this.templateUrl = './templates/checkbox.html'; + this.templateUrl = require('./templates/checkbox.html'); this.scope = { value: '=ngModel' }; @@ -23,4 +23,4 @@ export default class CheckboxDirective { } } -CheckboxDirective.$inject = []; \ No newline at end of file +CheckboxDirective.$inject = []; diff --git a/frontend/src/component/global/csv/CsvUploadDirective.js b/frontend/src/component/global/csv/CsvUploadDirective.js index f12a9ea4..0d5f8483 100644 --- a/frontend/src/component/global/csv/CsvUploadDirective.js +++ b/frontend/src/component/global/csv/CsvUploadDirective.js @@ -4,7 +4,7 @@ export default class CsvUploadDirective { this.scope = {ngModel: "=?"}; this.replace = true; this.transclude = true; - this.templateUrl = './templates/csv-upload.html'; + this.templateUrl = require('./templates/csv-upload.html'); this.controller = ['$scope', '$element', ($scope, $element) => { $scope.fileName = ''; $scope.chosenFile = ''; @@ -53,4 +53,4 @@ export default class CsvUploadDirective { } } -CsvUploadDirective.$inject = []; \ No newline at end of file +CsvUploadDirective.$inject = []; diff --git a/frontend/src/component/global/filereader/FileModelDirective.js b/frontend/src/component/global/filereader/FileModelDirective.js index f3d2aaa2..a70a89ca 100644 --- a/frontend/src/component/global/filereader/FileModelDirective.js +++ b/frontend/src/component/global/filereader/FileModelDirective.js @@ -9,7 +9,7 @@ export default class FileModelDirective { this.restrict = 'A'; this.replace = true; this.transclude = true; - this.templateUrl = './templates/file-upload.html'; + this.templateUrl = require('./templates/file-upload.html'); this.link = (scope, element, attrs) => { let model = $parse(attrs.fileModel); let modelSetter = model.assign; @@ -33,4 +33,4 @@ export default class FileModelDirective { } } -FileModelDirective.create.$inject = ['$parse']; \ No newline at end of file +FileModelDirective.create.$inject = ['$parse']; diff --git a/frontend/src/component/global/filters/Filters.js b/frontend/src/component/global/filters/Filters.js index 19896391..80014a00 100644 --- a/frontend/src/component/global/filters/Filters.js +++ b/frontend/src/component/global/filters/Filters.js @@ -1,3 +1,6 @@ +import angular from 'angular'; +import moment from 'moment'; + export default class Filters { static CommaToDecimal() { return function (value) { @@ -56,6 +59,6 @@ export default class Filters { } return input; - } + }; } -} \ No newline at end of file +} diff --git a/frontend/src/component/global/map/EditableMap.js b/frontend/src/component/global/map/EditableMap.js index dac5508c..91b0a366 100644 --- a/frontend/src/component/global/map/EditableMap.js +++ b/frontend/src/component/global/map/EditableMap.js @@ -1,3 +1,5 @@ +import moment from 'moment'; + export default class EditableMap { constructor($filter, DataService) { this.config = window.OpenLoyaltyConfig; @@ -662,4 +664,4 @@ export default class EditableMap { } } -EditableMap.$inject = ['$filter', 'DataService']; \ No newline at end of file +EditableMap.$inject = ['$filter', 'DataService']; diff --git a/frontend/src/component/global/modal/ModalDirective.js b/frontend/src/component/global/modal/ModalDirective.js index 55705dd0..7a117db4 100644 --- a/frontend/src/component/global/modal/ModalDirective.js +++ b/frontend/src/component/global/modal/ModalDirective.js @@ -36,8 +36,8 @@ export default class ModalDirective { element.find('.modal').get(0).style.minWidth = scope.minWidth; } }; - this.templateUrl = './templates/modal.html'; + this.templateUrl = require('./templates/modal.html'); } } -ModalDirective.$inject = []; \ No newline at end of file +ModalDirective.$inject = []; diff --git a/frontend/src/component/global/pages/StaticPagesDirective.js b/frontend/src/component/global/pages/StaticPagesDirective.js index 31db8469..6c150ca9 100644 --- a/frontend/src/component/global/pages/StaticPagesDirective.js +++ b/frontend/src/component/global/pages/StaticPagesDirective.js @@ -8,11 +8,12 @@ export default class StaticPagesDirective { this.controller = ['$scope', '$stateParams', ($scope, $stateParams) => { $scope.getTemplateUrl = () => { if ($stateParams.pageName) { - return './templates/static/'+$stateParams.pageName+'.html'; + require('./templates/static/'+$stateParams.pageName+'.html'); + return './templates/'+$stateParams.pageName+'.html'; } }; }]; } } -StaticPagesDirective.$inject = ['$scope', '$stateParams']; \ No newline at end of file +StaticPagesDirective.$inject = ['$scope', '$stateParams']; diff --git a/frontend/src/component/global/pages/templates/static-pages.html b/frontend/src/component/global/pages/templates/static-pages.html index 312f9656..2a3e8e04 100644 --- a/frontend/src/component/global/pages/templates/static-pages.html +++ b/frontend/src/component/global/pages/templates/static-pages.html @@ -4,9 +4,7 @@
-
- - \ No newline at end of file + diff --git a/frontend/src/component/global/security/SecurityController.js b/frontend/src/component/global/security/SecurityController.js index 0678949b..d9935a7e 100644 --- a/frontend/src/component/global/security/SecurityController.js +++ b/frontend/src/component/global/security/SecurityController.js @@ -80,4 +80,4 @@ export default class SecurityController { } } -SecurityController.$inject = ['$scope', '$state', 'SecurityService', 'Flash', '$filter', 'Validation', '$stateParams']; \ No newline at end of file +SecurityController.$inject = ['$scope', '$state', 'SecurityService', 'Flash', '$filter', 'Validation', '$stateParams']; diff --git a/frontend/src/component/global/spinnerLoader/SpinnerLoaderDirective.js b/frontend/src/component/global/spinnerLoader/SpinnerLoaderDirective.js index 6c101935..defd2841 100644 --- a/frontend/src/component/global/spinnerLoader/SpinnerLoaderDirective.js +++ b/frontend/src/component/global/spinnerLoader/SpinnerLoaderDirective.js @@ -14,7 +14,7 @@ export default class SpinnerLoaderDirective { loading: '=?', delay: '=?' }; - this.templateUrl = './templates/spinner-loader.html'; + this.templateUrl = require('./templates/spinner-loader.html'); this.link = (scope, element) => { element.parent().addClass('loader-relative'); @@ -48,4 +48,4 @@ export default class SpinnerLoaderDirective { } } -SpinnerLoaderDirective.create.$inject = ['$timeout']; \ No newline at end of file +SpinnerLoaderDirective.create.$inject = ['$timeout']; diff --git a/frontend/src/component/global/validation/FormValidationDirective.js b/frontend/src/component/global/validation/FormValidationDirective.js index 348f02a5..8eb2d3cb 100644 --- a/frontend/src/component/global/validation/FormValidationDirective.js +++ b/frontend/src/component/global/validation/FormValidationDirective.js @@ -4,8 +4,8 @@ export default class FormValidationDirective { this.scope = {formValidation: "=?"}; this.replace = true; this.transclude = true; - this.templateUrl = './templates/formFieldError.html'; + this.templateUrl = require('./templates/formFieldError.html'); } } -FormValidationDirective.$inject = []; \ No newline at end of file +FormValidationDirective.$inject = []; diff --git a/frontend/src/img/ol_ban_1.jpg b/frontend/src/img/ol_ban_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b56e661d8133fb12cae6b0d8e94b1671f3bdca25 GIT binary patch literal 85657 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
  • F%z4_GHxRJOS2Fw>MboX9JX%d*{> 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

    ^uR)6*|(RQnQP&^#Ym}-!o@M5z!L%(o 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 literal 0 HcmV?d00001 diff --git a/frontend/src/img/ol_ban_10.jpg b/frontend/src/img/ol_ban_10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0a084619f99016800470a982d34baaf23f7e6f1d GIT binary patch literal 79582 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