├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── back-end
├── .dockerignore
├── .env
├── .env.test
├── .gitignore
├── Dockerfile
├── bin
│ ├── console
│ └── phpunit
├── composer.json
├── config
│ ├── bootstrap.php
│ ├── bundles.php
│ ├── jwt
│ │ ├── private.pem
│ │ └── public.pem
│ ├── packages
│ │ ├── cache.yaml
│ │ ├── dev
│ │ │ ├── debug.yaml
│ │ │ ├── easy_log_handler.yaml
│ │ │ ├── monolog.yaml
│ │ │ ├── swiftmailer.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── doctrine.yaml
│ │ ├── doctrine_migrations.yaml
│ │ ├── fos_rest.yaml
│ │ ├── fos_user.yaml
│ │ ├── framework.yaml
│ │ ├── lexik_jwt_authentication.yaml
│ │ ├── nelmio_cors.yaml
│ │ ├── prod
│ │ │ ├── doctrine.yaml
│ │ │ ├── monolog.yaml
│ │ │ └── routing.yaml
│ │ ├── routing.yaml
│ │ ├── security.yaml
│ │ ├── sensio_framework_extra.yaml
│ │ ├── swiftmailer.yaml
│ │ ├── test
│ │ │ ├── dama_doctrine_test_bundle.yaml
│ │ │ ├── framework.yaml
│ │ │ ├── monolog.yaml
│ │ │ ├── swiftmailer.yaml
│ │ │ ├── validator.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── translation.yaml
│ │ ├── twig.yaml
│ │ └── validator.yaml
│ ├── routes.yaml
│ ├── routes
│ │ ├── annotations.yaml
│ │ ├── dev
│ │ │ ├── twig.yaml
│ │ │ └── web_profiler.yaml
│ │ └── fos_user.yaml
│ └── services.yaml
├── phpunit.xml.dist
├── public
│ └── index.php
├── src
│ ├── Controller
│ │ ├── .gitignore
│ │ ├── ApiController.php
│ │ └── DefaultController.php
│ ├── DataFixtures
│ │ └── UserFixtures.php
│ ├── Entity
│ │ ├── .gitignore
│ │ └── User.php
│ ├── Kernel.php
│ ├── Migrations
│ │ ├── .gitignore
│ │ └── Version20191115160910.php
│ └── Repository
│ │ └── .gitignore
├── symfony.lock
├── templates
│ └── base.html.twig
├── tests
│ ├── .gitignore
│ └── Controller
│ │ ├── ApiControllerTest.php
│ │ └── DefaultControllerTest.php
└── translations
│ └── .gitignore
├── buy-me-a-coffee.png
├── config
└── nginx
│ ├── angular.conf
│ ├── nginx.conf
│ └── symfony.conf
├── docker-compose.yml
└── front-end
├── .dockerignore
├── .gitignore
├── Dockerfile
├── README.md
├── angular.json
├── browserslist
├── e2e
├── protractor.conf.js
├── src
│ ├── app.e2e-spec.ts
│ └── app.po.ts
└── tsconfig.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── src
├── app
│ ├── api.service.spec.ts
│ ├── api.service.ts
│ ├── app-routing.module.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── hello
│ │ ├── hello.component.css
│ │ ├── hello.component.html
│ │ ├── hello.component.spec.ts
│ │ └── hello.component.ts
│ ├── http-interceptor
│ │ ├── index.ts
│ │ └── jwt-interceptor.ts
│ ├── login
│ │ ├── login.component.css
│ │ ├── login.component.html
│ │ ├── login.component.spec.ts
│ │ └── login.component.ts
│ ├── token.service.spec.ts
│ └── token.service.ts
├── assets
│ └── .gitkeep
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
└── test.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Cache and logs (Symfony2)
2 | /back-end/app/cache/*
3 | /back-end/app/logs/*
4 | !/back-end/app/cache/.gitkeep
5 | !/back-end/app/logs/.gitkeep
6 |
7 |
8 | # Assets and user uploads
9 | /back-end/vendor/
10 | /back-end/web/bundles/
11 | /back-end/web/uploads/
12 |
13 | # PHPUnit
14 | /back-end/app/phpunit.xml
15 | /back-end/phpunit.
16 |
17 | # Dist
18 | /front-end/dist*
19 |
20 | # Composer PHAR
21 | *composer.phar
22 | *composer.lock
23 |
24 | node_modules
25 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.3
5 | - 7.4
6 |
7 | services:
8 | - postgresql
9 |
10 | before_script:
11 | - psql -c 'create database symfony_test;' -U postgres
12 | - phpenv config-rm xdebug.ini
13 | - cd back-end
14 | - composer self-update
15 | - composer install
16 | - APP_ENV=test bin/console doctrine:schema:create -q
17 | - APP_ENV=test bin/console doctrine:fixtures:load -q --purge-with-truncate
18 |
19 | script:
20 | - phpunit
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Nassim Ben Ghmiss
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | angular-symfony [](https://travis-ci.org/FlyersWeb/angular-symfony)
2 | ===============
3 |
4 | Project Bootstrap for an Angular 2+ and Symfony 4+ webservices project.
5 |
6 | Introduction
7 | ------------
8 |
9 | This project is a template application with a secured RestFul API communication via JWT security scheme.
10 |
11 | Buy me a coffee
12 | ---------------
13 |
14 | [](https://paypal.me/nac1dbois)
15 |
16 | I'm working on this project in my free time and offering it free of charges. To help me work more on this you can send me tips to buy more coffee :)
17 |
18 | Installation
19 | ------------
20 |
21 | Install docker and docker-compose.
22 |
23 | Clone the project :
24 |
25 | git clone git@github.com:FlyersWeb/angular-symfony.git
26 |
27 | Launch dockerized environment :
28 |
29 | docker-compose up -d
30 |
31 | Log in application docker image :
32 |
33 | docker-compose exec application bash
34 |
35 | Install dependencies :
36 |
37 | composer install
38 |
39 | Create database if necessary :
40 |
41 | php bin/console doctrine:database:create
42 |
43 | Create schemas (FOSUserBundle) :
44 |
45 | php bin/console doctrine:schema:create
46 |
47 | Create and activate user :
48 |
49 | php bin/console doctrine:fixtures:load
50 |
51 | Access the front end using port 4200 :
52 |
53 | firefox http://localhost:4200 &
54 |
55 | Launching tests
56 | ---------------
57 |
58 | If you want to contribute to project you'll need to have tests to pass. So in order to run them you'll need to :
59 |
60 | Log in application docker image :
61 |
62 | docker-compose exec application bash
63 |
64 | Update database connection information in `.env.test`
65 |
66 | Create database :
67 |
68 | php bin/console doctrine:database:create --env=test
69 |
70 | Create schemas (FOSUserBundle) :
71 |
72 | php bin/console doctrine:schema:create --env=test
73 |
74 | Create and activate user :
75 |
76 | php bin/console doctrine:fixtures:load --env=test
77 |
78 | Copy Phpunit config :
79 |
80 | cp phpunit.xml.dist phpunit.xml
81 |
82 | Launch tests using :
83 |
84 | bin/phpunit
85 |
86 | Authentication system
87 | ---------------------
88 |
89 | The Authentication system is based on the JWT token as implemented by [Lexik](https://github.com/lexik/LexikJWTAuthenticationBundle)
90 |
91 | User management is done through [FOSUserBundle](https://github.com/FriendsOfSymfony/FOSUserBundle), you can easily add / edit / delete users by using their API.
92 |
93 | The server provides a Rest API using [FOSRestBundle](https://github.com/FriendsOfSymfony/FOSRestBundle) allowing you to connect using the following query:
94 |
95 | `curl -X POST -H "Content-Type: application/json" http://localhost:8000/api/login_check -d '{"username":"bob","password":"Abc123"}'`
96 |
97 | Client Side specifics
98 | ---------------------
99 |
100 | On the client side, I've inspired my code from Angular official documentation about HttpInterceptor, allowing me to send the JWT Token on each HTTP request when token is available.
101 |
102 | The token is sent in *Authorization* headers:
103 |
104 | `Authorization: Bearer xxx`
105 |
106 | LICENSE
107 | -------
108 |
109 | This program is free software. It comes without any warranty, to the extent permitted by applicable law.
110 |
111 | This software is LICENSED under the MIT License. Use it at your own risk.
112 |
113 | WARNING
114 | -------
115 |
116 | Servers are configured for developments purposes. Do not deploy this project on production as is. You should have a look to [Symfony deployment documentation](https://symfony.com/doc/4.4/deployment.html) for the Back-end and the [Angular deployment documentation](https://angular.io/guide/deployment) for the Front-End part.
117 |
118 | You should also change the preconfigured keys for signatures by generating your own keys using :
119 |
120 | openssl genpkey -out config/jwt/private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
121 | openssl pkey -in config/jwt/private.pem -out config/jwt/public.pem -pubout
122 |
123 | And copy the passphrase into the field `JWT_PASSPHRASE` in `.env` file.
124 |
125 | You should also update the `APP_SECRET` in `.env` file.
126 |
127 | Conclusion
128 | ----------
129 |
130 | You can use this template and adapt it to your needs.
131 |
132 | @FlyersWeb
133 |
--------------------------------------------------------------------------------
/back-end/.dockerignore:
--------------------------------------------------------------------------------
1 | app/cache/*
2 | app/logs/*
3 | vendor/*
--------------------------------------------------------------------------------
/back-end/.env:
--------------------------------------------------------------------------------
1 | # In all environments, the following files are loaded if they exist,
2 | # the latter taking precedence over the former:
3 | #
4 | # * .env contains default values for the environment variables needed by the app
5 | # * .env.local uncommitted file with local overrides
6 | # * .env.$APP_ENV committed environment-specific defaults
7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides
8 | #
9 | # Real environment variables win over .env files.
10 | #
11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
12 | #
13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
14 | # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
15 |
16 | ###> symfony/framework-bundle ###
17 | APP_ENV=dev
18 | APP_SECRET=abb685fe97081c338ed39e8b1cb4bd69
19 | #TRUSTED_PROXIES=127.0.0.1,127.0.0.2
20 | #TRUSTED_HOSTS='^localhost|example\.com$'
21 | ###< symfony/framework-bundle ###
22 |
23 | ###> doctrine/doctrine-bundle ###
24 | # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
25 | # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
26 | # For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11"
27 | # IMPORTANT: You MUST configure your db driver and server version, either here or in config/packages/doctrine.yaml
28 | DATABASE_URL=postgresql://postgres:postgres@database:5432/symfony_dev?serverVersion=10.10
29 | ###< doctrine/doctrine-bundle ###
30 |
31 | ###> symfony/swiftmailer-bundle ###
32 | # For Gmail as a transport, use: "gmail://username:password@localhost"
33 | # For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode="
34 | # Delivery is disabled by default via "null://localhost"
35 | MAILER_URL=null://localhost
36 | ###< symfony/swiftmailer-bundle ###
37 |
38 | ###> nelmio/cors-bundle ###
39 | CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$
40 | ###< nelmio/cors-bundle ###
41 |
42 | ###> lexik/jwt-authentication-bundle ###
43 | JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
44 | JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
45 | JWT_PASSPHRASE=7724eb8ec2bcd93bade2b15bcd946911
46 | ###< lexik/jwt-authentication-bundle ###
47 |
--------------------------------------------------------------------------------
/back-end/.env.test:
--------------------------------------------------------------------------------
1 | # define your env variables for the test env here
2 | KERNEL_CLASS='App\Kernel'
3 | APP_ENV=test
4 | APP_SECRET='$ecretf0rt3st'
5 | SYMFONY_DEPRECATIONS_HELPER=999999
6 | PANTHER_APP_ENV=panther
7 | DATABASE_URL=postgresql://postgres@localhost:5432/symfony_test?serverVersion=9.2
8 |
--------------------------------------------------------------------------------
/back-end/.gitignore:
--------------------------------------------------------------------------------
1 | var
2 |
--------------------------------------------------------------------------------
/back-end/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:7.4-fpm
2 |
3 | # Install Composer
4 | RUN apt-get update && apt-get install -y \
5 | openssl \
6 | git \
7 | unzip
8 |
9 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
10 | && composer --version
11 |
12 | ADD . /var/www
13 | WORKDIR /var/www
14 |
15 | RUN apt-get update && apt-get install -y \
16 | libfreetype6-dev \
17 | libjpeg62-turbo-dev \
18 | libmcrypt-dev \
19 | libpq-dev \
20 | libpng-dev
21 |
22 | RUN pecl install mcrypt-1.0.3
23 |
24 | RUN docker-php-ext-enable mcrypt \
25 | && docker-php-ext-configure gd --with-freetype --with-jpeg \
26 | && docker-php-ext-install -j$(nproc) gd pdo_pgsql
27 |
28 | # Use the default production configuration
29 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
30 |
31 | RUN usermod -u 1000 www-data \
32 | && mkdir -p /var/www/app/cache \
33 | && mkdir -p /var/www/app/logs \
34 | && chmod -R 777 /var/www/app/cache \
35 | && chmod -R 777 /var/www/app/logs
36 |
37 | EXPOSE 9000
38 | CMD ["php-fpm"]
39 |
--------------------------------------------------------------------------------
/back-end/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(['--env', '-e'], null, true)) {
23 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
24 | }
25 |
26 | if ($input->hasParameterOption('--no-debug', true)) {
27 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
28 | }
29 |
30 | require dirname(__DIR__).'/config/bootstrap.php';
31 |
32 | if ($_SERVER['APP_DEBUG']) {
33 | umask(0000);
34 |
35 | if (class_exists(Debug::class)) {
36 | Debug::enable();
37 | }
38 | }
39 |
40 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
41 | $application = new Application($kernel);
42 | $application->run($input);
43 |
--------------------------------------------------------------------------------
/back-end/bin/phpunit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | =1.2)
9 | if (is_array($env = @include dirname(__DIR__).'/.env.local.php')) {
10 | foreach ($env as $k => $v) {
11 | $_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && 0 !== strpos($k, 'HTTP_') ? $_SERVER[$k] : $v);
12 | }
13 | } elseif (!class_exists(Dotenv::class)) {
14 | throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
15 | } else {
16 | // load all the .env files
17 | (new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
18 | }
19 |
20 | $_SERVER += $_ENV;
21 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
22 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
23 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
24 |
--------------------------------------------------------------------------------
/back-end/config/bundles.php:
--------------------------------------------------------------------------------
1 | ['all' => true],
5 | Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
6 | Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true],
7 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
8 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
9 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
10 | Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true],
11 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
12 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
13 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
14 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
15 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
16 | Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true],
17 | FOS\UserBundle\FOSUserBundle::class => ['all' => true],
18 | FOS\RestBundle\FOSRestBundle::class => ['all' => true],
19 | Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
20 | Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
21 | Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
22 | DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
23 | ];
24 |
--------------------------------------------------------------------------------
/back-end/config/jwt/private.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN ENCRYPTED PRIVATE KEY-----
2 | MIIJnzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIu9HJIGBAV74CAggA
3 | MB0GCWCGSAFlAwQBKgQQ+l0f/ekDwk6LHbsS9uLKrASCCVAJxBdrl7eAdlOBfmNr
4 | WUMxGTdsn3QM8DJByfwD/AKMW3GYRgAT9kVz/5vwxQp0r1RsfwgEY5itFXOqzW9U
5 | 4x9EfTjgjstN42dqAx2Xni1YFOwUjK9t9/Oae4+gdzewuA4soSzmmQa6/HXzWlZW
6 | uaIGtgCQf2d76TwVkr1UTZBwlhcswv0v4pYA3jmW1m8pLSoiQvTRHoIOHXq//3Fp
7 | TxnLiGzxdg0AtZdrfO1OA+HUw+F6Yw3bmveWnxf41wsnl+Y1CSMVd1HjlnbINcRp
8 | inmJoZir5VJEjEwpO2R+ASwWgSwdIdLswFR83UkZ5TNwmWP4+v9AFNvM9ikCGibs
9 | zKu9CSoyXoQB9KjKSheKI++KeED7OJbsS2LbCBGm1B40CSaXu8NUi0kW2lxTjf0z
10 | gUxhps1JbqTy+WdOTxlP5AA4uZPTrNq04pPswqcHDgoWMCgUcBFyQ9fqOoAbWOj4
11 | d0yTW0tpuMqsizC6HOW227QKzWJd93dU9x7ajLzxp3F9wyCShm6NpDqdyGU4CiHk
12 | cjNBy+C8HOEaeWLyTk9ZHXkkVGgaT6o1YunECyz4IkpA0mxYfQtX65XMDSa7tXOq
13 | 7Lq1HWsIaUj50AXUfTGtOwtWyt7ldL5i3Ih0pOBLmsDKFv6yuaQcKdm9RZvybb3+
14 | AWP7yz4iqZV5xtyHzPCFGDn2YyXAdTwc1ZtaH/QJfrVsdBvbNVLjCnVM7fbQHEH0
15 | Iske1K+1U9sZjQf804urwlK4+dbXKWYvmf0RR35U0AyEG9Scc5lch6NLlb5Gt57Z
16 | 1WYdyORDgNSmU+PPCrYpQaatWQA/MTUMRklGputdjKtX5qJrMVOJsIazY8qXK9rD
17 | 7aqNFdVsHV2pmdj1Y4h2SzwWlmc8SaHlZdo+44hS57SjN3QaQL4oWJPjgyT2IBQ0
18 | UDOd5BdxkUpaUWMzNZcLAD5pigOmQAHJ1GEWvPw5zRztLUYeYXA8R0axwuKDru1k
19 | Ncm4QffwuxuCLpxEeQtxn+U5DTTv8L5a6kqbsr/5vCRcLHJeeXbWQF6hi5YTahf+
20 | 8zhDpedBQ/Cy+/04ZRyUgnFn1UGzg24PfG0f0AKOtbwx1xXII3cFafiUCU35eMPg
21 | NfyWzjz0Dz66rq+PYxMKNdqiiO/C+GnuxDcFvNmNv0Soda4eBvmtnZorh3BUgdNw
22 | MkbVp2xiHoJZTWfdxYsGuSi5Z5/jq2VSUNQ2c+Y6Dkq42k5wh0oe1M0u3D4j9JPK
23 | 2ybE8PHC2jRkvvQcxgEtDA843JD5ud344XmdZe4jOhMZxWGsKhz3YjyuKp/jbq1e
24 | IuXtwvVk5DIMTz0AzmpvNNS04+Fq1Eg0xIXIq9BCyMWOg14s6uNCK6eY8ux3vFTO
25 | SueZayqbcLQWLUoIgqiFUifq/hxbWP2J8eunSJwjhi0TLiU9qyiw38Rd9CJSaunP
26 | lC14d5ESGzJvgzY0HoSUfstG0KL9cP5s4P58SwKU2/qVKYgcb60aU+xRzW/esBmo
27 | 3kLJSAszkRKAe2vQn9pdNuSPBjoCirYYr2XqjYPjeBPeL6lDuf0bVmhal/VLaHls
28 | SjSn8iTKduJU9kyJjGF9Yqh7FFkbu/HasVPKNOZHPbcgffuq8laShZYncTBq557q
29 | OpNl113BLjaaOp3aB1OcTC5CqoLKBFPxq/oIdy4x75tgM74yekECLUZqCv5Nn8Nt
30 | R1fkLISCF2FApGE3/w1c6m9gSmnaelNJ9RFqylf2Q5qvbBBAe0nEagXfU3xsW/gs
31 | YtgffFIvBSowdT/yj7i8FMB3Uo8DUzCi1vAfOmR7Nhv9s/kfnw5+8qr4DvKoc7ng
32 | Jhh2lbI9drb9kuNgyczzzhOiNqNsQOMSvjqzgxkC2L2VLbuImq/x5KZQzSWbcgdh
33 | 88bplFfBSqWiR5hnr2DTFYZGQQXd8GCii89jXqhkXBG5QI0tPs1Qx68HCIla/obR
34 | VquulBzG524jE3F+/FG9rsf1fQ1bhS7g0yqdiEnCJX1SdbMtYjrgr5tVV82I/lsK
35 | ytlpWe1QhPmjBoQZTVt3K4TltjlGwuBxCjQw48bdpxlB3p3Exaso4tyU9w3TarHz
36 | moOQh5PKlcfhQl0Yzqpgdvfv9E72EcNR3aRKxbWIpvVIOKEZ8zK90ICsJ66I2K/X
37 | epRMyGGzFaTMMgIsjtt8+/l9O3pgW2ZvjwiSiDICJCbP7OD7uPZDhuxF1CSKAgOA
38 | T32R9g7mvW0y75ZjVZdD+7thcgGQsw8EKOavfOgISsxke4pzLPfWDonw5FWTOYNw
39 | 5tWubhUxYfMEuE1y4M+f2bnhwJYdTUoY5pPeeS1bpnO7lINHh52/zxrpvssH4Flm
40 | 5E4X9Jtbrh7aT8+Ao1hWva/spFa5VgaIrYdxZlj0x2Z/R0+d7spEtHPgLFiX15dz
41 | 7Sir+7cs7aL9qosjMdvLg8eiUQAxDh3OGw/NJ2MQU4MULYeq9S1OI3HLLctg9DgJ
42 | q26d0OQdQEZ9nmGIOvkKhy4yNkqiKTUXA0k0d3+aaKnmtBvxKXQyilum/nUvzU9S
43 | nR37aITffiyTmNYTtqgPneKQPX1FZQntQgSJUEw0scfzThuCgu0mWlkGoq8rvnX7
44 | 6trZM7yo4WepBW+S+CDHlgvvDOFFndRQatAynXE2knaiEyhFgCUWJRizeZwI3R23
45 | M7HIKZRFtynwAZoK/3eSFxSxLvSvAHzDH/r0euUHJsK/41sGB080M+DKYm5haKTM
46 | CTBa4hz6+2bKvLbo56jPDZHC5U3UyL6dbc6pKFJnAFMP/2Q90z5An321bUt1sHFz
47 | SN5+RozvwRB9M4lfFPzc9P2MXpyMJqJ+T8XJrLcd4iTTN5yqO1RcpjeO4/0Uk8/T
48 | tZ3tLrkYKfcTQCTjWsIN0XCndxN9ybkCGYw+eDr/KKzkK86FSXi6saB+oCaXLFcH
49 | cY4h7EVmjaCp069EIsZPjXiV+vgPFSK0DHoSakU61HTy0gXSdd10psFzBa4G+faj
50 | t5fPsGyb1/I1LTrhRmImNE+xyHTAkhv041H1aIYBpUzR03sCefq39S2BnoUUa9lP
51 | aQyZczmhfGCwuLs7BgNK86weWQqPs80qwGvTlNF1RtAuwEILxfyHWGXzQcoYDko8
52 | E05B9XPIZzSeIRjOQW9HB7H72zWGtp4jT12RrYngSAWpJ3zVlWNlALaeO4tt+Cdx
53 | VMOvT0HwSamtQdGoZTvjjZbKtA==
54 | -----END ENCRYPTED PRIVATE KEY-----
55 |
--------------------------------------------------------------------------------
/back-end/config/jwt/public.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwEJ4isNm/VxgIYUCp/qs
3 | WMU6EEXpsiLhNHtyYC5ThoTLAIjmgC5nncQrpZ936PoBRaqXVC6U/+bS6cEyTGT/
4 | nJkXRl+CznIJ+2j3X0N5pcbgfhWnTFsgI3CkKNLG57W4F+squAHVr3bxouRy4d6B
5 | goKrrdkaZifxA9MB5RB1XQuEEPiBRZC+x3XugxAY0AEius2g6i3XyKahUcptDi+Q
6 | GhjttJBQ58nmB4J9iOb5bTvFK7wkSv29qU9qpw8LwTYPkWgnYzUTIOEzZS172vB2
7 | +rkc3LirmKwrTtA70JLS6lBoG2zBIa97bYocYKYjGdOlb1Yk1pTZyKWY5pNPH9jY
8 | bTvJ4F/wO224W08J6LA19fy6ZMORMgRsCO4iUU0AWW7yQ08+x8qHDREOMERNgZLy
9 | A+kMILNLa9BTBhAG2tdwt2LagYdPdbgUUS4m6S9kYenBhrqehwDYlKuO66ZxCCCA
10 | CkqG8We5oyUKWiM4J923Ai9SlSCJK9G1wRa4ShhmI9K/RGPYKkgslJuHJ0zE0Z3n
11 | FoPjgJVYr+67c2vJoULa4xXJIGwODro5fD1/Qi1uMhgsn+sVqQbqmixSr/Mc6rpJ
12 | HRq0GsZ2aCL4wZ7KnjhUfYmivpGAHZb24bzf7r1gKu6j4B/hAg6EYCAK0okHJUDy
13 | OZjAiWdrPITL+wOKj0o0jS8CAwEAAQ==
14 | -----END PUBLIC KEY-----
15 |
--------------------------------------------------------------------------------
/back-end/config/packages/cache.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | cache:
3 | app: cache.adapter.filesystem
4 | system: cache.adapter.system
5 | # Put the unique name of your app here: the prefix seed
6 | # is used to compute stable namespaces for cache keys.
7 | #prefix_seed: your_vendor_name/app_name
8 | # The app cache caches to the filesystem by default.
9 | # Other options include:
10 | # Redis
11 | #app: cache.adapter.redis
12 | #default_redis_provider: redis://localhost
13 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
14 | #app: cache.adapter.apcu
15 | # Namespaced pools use the above "app" backend by default
16 | #pools:
17 | #my.dedicated.cache: null
18 |
--------------------------------------------------------------------------------
/back-end/config/packages/dev/debug.yaml:
--------------------------------------------------------------------------------
1 | debug:
2 | # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
3 | # See the "server:dump" command to start a new server.
4 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
5 |
--------------------------------------------------------------------------------
/back-end/config/packages/dev/easy_log_handler.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | EasyCorp\EasyLog\EasyLogHandler:
3 | public: false
4 | arguments: ['%kernel.logs_dir%/%kernel.environment%.log']
5 |
6 | #// FIXME: How to add this configuration automatically without messing up with the monolog configuration?
7 | #monolog:
8 | # handlers:
9 | # buffered:
10 | # type: buffer
11 | # handler: easylog
12 | # channels: ['!event']
13 | # level: debug
14 | # easylog:
15 | # type: service
16 | # id: EasyCorp\EasyLog\EasyLogHandler
17 |
--------------------------------------------------------------------------------
/back-end/config/packages/dev/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: stream
5 | path: "php://stderr"
6 | level: debug
7 | channels: ["!event"]
8 | # uncomment to get logging in your browser
9 | # you may have to allow bigger header sizes in your Web server configuration
10 | #firephp:
11 | # type: firephp
12 | # level: info
13 | #chromephp:
14 | # type: chromephp
15 | # level: info
16 | console:
17 | type: console
18 | process_psr_3_messages: false
19 | channels: ["!event", "!doctrine", "!console"]
20 |
--------------------------------------------------------------------------------
/back-end/config/packages/dev/swiftmailer.yaml:
--------------------------------------------------------------------------------
1 | # See https://symfony.com/doc/current/email/dev_environment.html
2 | swiftmailer:
3 | # send all emails to a specific address
4 | #delivery_addresses: ['me@example.com']
5 |
--------------------------------------------------------------------------------
/back-end/config/packages/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: true
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { only_exceptions: false }
7 |
--------------------------------------------------------------------------------
/back-end/config/packages/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | dbal:
3 | url: "%env(resolve:DATABASE_URL)%"
4 |
5 | # IMPORTANT: You MUST configure your db driver and server version,
6 | # either here or in the DATABASE_URL env var (see .env file)
7 | driver: "pgsql"
8 | server_version: "10.10"
9 |
10 | # Only needed for MySQL (ignored otherwise)
11 | # charset: utf8mb4
12 | # default_table_options:
13 | # collate: utf8mb4_unicode_ci
14 | orm:
15 | auto_generate_proxy_classes: true
16 | naming_strategy: doctrine.orm.naming_strategy.underscore
17 | auto_mapping: true
18 | mappings:
19 | App:
20 | is_bundle: false
21 | type: annotation
22 | dir: "%kernel.project_dir%/src/Entity"
23 | prefix: 'App\Entity'
24 | alias: App
25 |
--------------------------------------------------------------------------------
/back-end/config/packages/doctrine_migrations.yaml:
--------------------------------------------------------------------------------
1 | doctrine_migrations:
2 | dir_name: "%kernel.project_dir%/src/Migrations"
3 | # namespace is arbitrary but should be different from App\Migrations
4 | # as migrations classes should NOT be autoloaded
5 | namespace: DoctrineMigrations
6 |
--------------------------------------------------------------------------------
/back-end/config/packages/fos_rest.yaml:
--------------------------------------------------------------------------------
1 | fos_rest:
2 | param_fetcher_listener: true
3 | allowed_methods_listener: true
4 | view:
5 | view_response_listener: true
6 | format_listener:
7 | rules:
8 | - {
9 | path: ^/,
10 | prefer_extension: true,
11 | fallback_format: json,
12 | priorities: [json],
13 | }
14 |
--------------------------------------------------------------------------------
/back-end/config/packages/fos_user.yaml:
--------------------------------------------------------------------------------
1 | fos_user:
2 | db_driver: orm
3 | firewall_name: main
4 | user_class: App\Entity\User
5 | # error The service "security.authentication.provider.dao.main" has a dependency on a non-existent service "fos_user.user_checker".
6 | service:
7 | mailer: fos_user.mailer.twig_swift
8 | from_email:
9 | address: "contact@company.com"
10 | sender_name: "contact@company.com"
11 |
--------------------------------------------------------------------------------
/back-end/config/packages/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | secret: "%env(APP_SECRET)%"
3 | #csrf_protection: true
4 | #http_method_override: true
5 |
6 | # Enables session support. Note that the session will ONLY be started if you read or write from it.
7 | # Remove or comment this section to explicitly disable session support.
8 | session:
9 | handler_id: null
10 | cookie_secure: auto
11 | cookie_samesite: lax
12 |
13 | #esi: true
14 | #fragments: true
15 | php_errors:
16 | log: true
17 |
--------------------------------------------------------------------------------
/back-end/config/packages/lexik_jwt_authentication.yaml:
--------------------------------------------------------------------------------
1 | lexik_jwt_authentication:
2 | secret_key: "%env(resolve:JWT_SECRET_KEY)%"
3 | public_key: "%env(resolve:JWT_PUBLIC_KEY)%"
4 | pass_phrase: "%env(JWT_PASSPHRASE)%"
5 |
--------------------------------------------------------------------------------
/back-end/config/packages/nelmio_cors.yaml:
--------------------------------------------------------------------------------
1 | nelmio_cors:
2 | defaults:
3 | origin_regex: true
4 | allow_origin: ["%env(CORS_ALLOW_ORIGIN)%"]
5 | allow_methods: ["GET", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"]
6 | allow_headers: ["Content-Type", "Authorization", "X-WSSE"]
7 | expose_headers: ["Link"]
8 | max_age: 3600
9 | paths:
10 | "^/": null
11 |
--------------------------------------------------------------------------------
/back-end/config/packages/prod/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | orm:
3 | auto_generate_proxy_classes: false
4 | metadata_cache_driver:
5 | type: service
6 | id: doctrine.system_cache_provider
7 | query_cache_driver:
8 | type: service
9 | id: doctrine.system_cache_provider
10 | result_cache_driver:
11 | type: service
12 | id: doctrine.result_cache_provider
13 |
14 | services:
15 | doctrine.result_cache_provider:
16 | class: Symfony\Component\Cache\DoctrineProvider
17 | public: false
18 | arguments:
19 | - '@doctrine.result_cache_pool'
20 | doctrine.system_cache_provider:
21 | class: Symfony\Component\Cache\DoctrineProvider
22 | public: false
23 | arguments:
24 | - '@doctrine.system_cache_pool'
25 |
26 | framework:
27 | cache:
28 | pools:
29 | doctrine.result_cache_pool:
30 | adapter: cache.app
31 | doctrine.system_cache_pool:
32 | adapter: cache.system
33 |
--------------------------------------------------------------------------------
/back-end/config/packages/prod/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: fingers_crossed
5 | action_level: error
6 | handler: nested
7 | excluded_http_codes: [404, 405]
8 | nested:
9 | type: stream
10 | path: "php://stderr"
11 | level: debug
12 | console:
13 | type: console
14 | process_psr_3_messages: false
15 | channels: ["!event", "!doctrine"]
16 | deprecation:
17 | type: stream
18 | path: "php://stderr"
19 | deprecation_filter:
20 | type: filter
21 | handler: deprecation
22 | max_level: info
23 | channels: ["php"]
24 |
--------------------------------------------------------------------------------
/back-end/config/packages/prod/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: null
4 |
--------------------------------------------------------------------------------
/back-end/config/packages/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | utf8: true
4 |
--------------------------------------------------------------------------------
/back-end/config/packages/security.yaml:
--------------------------------------------------------------------------------
1 | security:
2 | encoders:
3 | App\Entity\User:
4 | algorithm: sha512
5 | encode_as_base64: true
6 | iterations: 5000
7 |
8 | role_hierarchy:
9 | ROLE_ADMIN: ROLE_USER
10 | ROLE_SUPER_ADMIN: ROLE_ADMIN
11 |
12 | providers:
13 | fos_userbundle:
14 | id: fos_user.user_provider.username
15 |
16 | firewalls:
17 | login:
18 | pattern: ^/api/login
19 | stateless: true
20 | anonymous: true
21 | json_login:
22 | check_path: /api/login_check
23 | success_handler: lexik_jwt_authentication.handler.authentication_success
24 | failure_handler: lexik_jwt_authentication.handler.authentication_failure
25 | api:
26 | pattern: ^/api
27 | stateless: true
28 | guard:
29 | authenticators:
30 | - lexik_jwt_authentication.jwt_token_authenticator
31 |
32 | # Easy way to control access for large sections of your site
33 | # Note: Only the *first* access control that matches will be used
34 | access_control:
35 | - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
36 | - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
37 |
--------------------------------------------------------------------------------
/back-end/config/packages/sensio_framework_extra.yaml:
--------------------------------------------------------------------------------
1 | sensio_framework_extra:
2 | router:
3 | annotations: false
4 |
--------------------------------------------------------------------------------
/back-end/config/packages/swiftmailer.yaml:
--------------------------------------------------------------------------------
1 | swiftmailer:
2 | url: "%env(MAILER_URL)%"
3 | spool: { type: "memory" }
4 |
--------------------------------------------------------------------------------
/back-end/config/packages/test/dama_doctrine_test_bundle.yaml:
--------------------------------------------------------------------------------
1 | dama_doctrine_test:
2 | enable_static_connection: true
3 | enable_static_meta_data_cache: true
4 | enable_static_query_cache: true
5 |
--------------------------------------------------------------------------------
/back-end/config/packages/test/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | test: true
3 | session:
4 | storage_id: session.storage.mock_file
5 |
--------------------------------------------------------------------------------
/back-end/config/packages/test/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: stream
5 | path: "php://stderr"
6 | level: debug
7 | channels: ["!event"]
8 |
--------------------------------------------------------------------------------
/back-end/config/packages/test/swiftmailer.yaml:
--------------------------------------------------------------------------------
1 | swiftmailer:
2 | disable_delivery: true
3 |
--------------------------------------------------------------------------------
/back-end/config/packages/test/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | not_compromised_password: false
4 |
--------------------------------------------------------------------------------
/back-end/config/packages/test/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: false
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { collect: false }
7 |
--------------------------------------------------------------------------------
/back-end/config/packages/translation.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | default_locale: en
3 | translator:
4 | default_path: "%kernel.project_dir%/translations"
5 | fallbacks:
6 | - en
7 |
--------------------------------------------------------------------------------
/back-end/config/packages/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | default_path: "%kernel.project_dir%/templates"
3 | debug: "%kernel.debug%"
4 | strict_variables: "%kernel.debug%"
5 |
--------------------------------------------------------------------------------
/back-end/config/packages/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | email_validation_mode: html5
4 | # Enables validator auto-mapping support.
5 | # For instance, basic validation constraints will be inferred from Doctrine's metadata.
6 | #auto_mapping:
7 | # App\Entity\: []
8 |
--------------------------------------------------------------------------------
/back-end/config/routes.yaml:
--------------------------------------------------------------------------------
1 | api_login_check:
2 | path: /api/login_check
3 |
--------------------------------------------------------------------------------
/back-end/config/routes/annotations.yaml:
--------------------------------------------------------------------------------
1 | controllers:
2 | resource: ../../src/Controller/
3 | type: annotation
4 |
--------------------------------------------------------------------------------
/back-end/config/routes/dev/twig.yaml:
--------------------------------------------------------------------------------
1 | _errors:
2 | resource: '@TwigBundle/Resources/config/routing/errors.xml'
3 | prefix: /_error
4 |
--------------------------------------------------------------------------------
/back-end/config/routes/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler_wdt:
2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
3 | prefix: /_wdt
4 |
5 | web_profiler_profiler:
6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
7 | prefix: /_profiler
8 |
--------------------------------------------------------------------------------
/back-end/config/routes/fos_user.yaml:
--------------------------------------------------------------------------------
1 | fos_user:
2 | resource: "@FOSUserBundle/Resources/config/routing/all.xml"
--------------------------------------------------------------------------------
/back-end/config/services.yaml:
--------------------------------------------------------------------------------
1 | # This file is the entry point to configure your own services.
2 | # Files in the packages/ subdirectory configure your dependencies.
3 |
4 | # Put parameters here that don't need to change on each machine where the app is deployed
5 | # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
6 | parameters:
7 |
8 | services:
9 | # default configuration for services in *this* file
10 | _defaults:
11 | autowire: true # Automatically injects dependencies in your services.
12 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
13 |
14 | # makes classes in src/ available to be used as services
15 | # this creates a service per class whose id is the fully-qualified class name
16 | App\:
17 | resource: "../src/*"
18 | exclude: "../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}"
19 |
20 | # controllers are imported separately to make sure services can be injected
21 | # as action arguments even if you don't extend any base controller class
22 | App\Controller\:
23 | resource: "../src/Controller"
24 | tags: ["controller.service_arguments"]
25 | # add more service definitions when explicit configuration is needed
26 | # please note that last definitions always *replace* previous ones
27 |
--------------------------------------------------------------------------------
/back-end/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | tests
21 |
22 |
23 |
24 |
25 |
26 | src
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/back-end/public/index.php:
--------------------------------------------------------------------------------
1 | handle($request);
26 | $response->send();
27 | $kernel->terminate($request, $response);
28 |
--------------------------------------------------------------------------------
/back-end/src/Controller/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/back-end/src/Controller/.gitignore
--------------------------------------------------------------------------------
/back-end/src/Controller/ApiController.php:
--------------------------------------------------------------------------------
1 | json(['hello' => 'world']);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/back-end/src/Controller/DefaultController.php:
--------------------------------------------------------------------------------
1 | passwordEncoder = $passwordEncoder;
17 | }
18 |
19 | public function load(ObjectManager $manager)
20 | {
21 | $user = new User();
22 |
23 | $user->setUsername('bob');
24 | $user->setUsernameCanonical('Bobby');
25 | $user->setEmail('bob@doe.com');
26 | $user->setEnabled(true);
27 | // Password is Abc123
28 | $user->setSalt('e4TNCCgLvPbDRh7ih+pK58pab0NToFzdZHuPmA0e');
29 | $user->setPassword('sM1GM+zlChZH4xlLokuCueeWSDq+4I7XGtn+GErMF1ehMVrFRXWklCK0/LtTZ4gQEebbLW9lrSS0ocA/9/12Gw==');
30 |
31 | $manager->persist($user);
32 | $manager->flush();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/back-end/src/Entity/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/back-end/src/Entity/.gitignore
--------------------------------------------------------------------------------
/back-end/src/Entity/User.php:
--------------------------------------------------------------------------------
1 | getProjectDir().'/var/cache/'.$this->environment;
20 | }
21 |
22 | public function getLogDir()
23 | {
24 | return $this->getProjectDir().'/var/log';
25 | }
26 |
27 | public function registerBundles()
28 | {
29 | $contents = require $this->getProjectDir().'/config/bundles.php';
30 | foreach ($contents as $class => $envs) {
31 | if (isset($envs['all']) || isset($envs[$this->environment])) {
32 | yield new $class();
33 | }
34 | }
35 | }
36 |
37 | protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
38 | {
39 | $container->setParameter('container.autowiring.strict_mode', true);
40 | $container->setParameter('container.dumper.inline_class_loader', true);
41 | $confDir = $this->getProjectDir().'/config';
42 | $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob');
43 | if (is_dir($confDir.'/packages/'.$this->environment)) {
44 | $loader->load($confDir.'/packages/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
45 | }
46 | $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob');
47 | $loader->load($confDir.'/services_'.$this->environment.self::CONFIG_EXTS, 'glob');
48 | }
49 |
50 | protected function configureRoutes(RouteCollectionBuilder $routes)
51 | {
52 | $confDir = $this->getProjectDir().'/config';
53 | if (is_dir($confDir.'/routes/')) {
54 | $routes->import($confDir.'/routes/*'.self::CONFIG_EXTS, '/', 'glob');
55 | }
56 | if (is_dir($confDir.'/routes/'.$this->environment)) {
57 | $routes->import($confDir.'/routes/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob');
58 | }
59 | $routes->import($confDir.'/routes'.self::CONFIG_EXTS, '/', 'glob');
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/back-end/src/Migrations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/back-end/src/Migrations/.gitignore
--------------------------------------------------------------------------------
/back-end/src/Migrations/Version20191115160910.php:
--------------------------------------------------------------------------------
1 | abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'postgresql\'.');
24 |
25 | $this->addSql('CREATE SEQUENCE fos_user_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
26 | $this->addSql('CREATE TABLE fos_user (id INT NOT NULL, username VARCHAR(180) NOT NULL, username_canonical VARCHAR(180) NOT NULL, email VARCHAR(180) NOT NULL, email_canonical VARCHAR(180) NOT NULL, enabled BOOLEAN NOT NULL, salt VARCHAR(255) DEFAULT NULL, password VARCHAR(255) NOT NULL, last_login TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, confirmation_token VARCHAR(180) DEFAULT NULL, password_requested_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, roles TEXT NOT NULL, PRIMARY KEY(id))');
27 | $this->addSql('CREATE UNIQUE INDEX UNIQ_957A647992FC23A8 ON fos_user (username_canonical)');
28 | $this->addSql('CREATE UNIQUE INDEX UNIQ_957A6479A0D96FBF ON fos_user (email_canonical)');
29 | $this->addSql('CREATE UNIQUE INDEX UNIQ_957A6479C05FB297 ON fos_user (confirmation_token)');
30 | $this->addSql('COMMENT ON COLUMN fos_user.roles IS \'(DC2Type:array)\'');
31 | }
32 |
33 | public function down(Schema $schema): void
34 | {
35 | // this down() migration is auto-generated, please modify it to your needs
36 | $this->abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'postgresql\'.');
37 |
38 | $this->addSql('CREATE SCHEMA public');
39 | $this->addSql('DROP SEQUENCE fos_user_id_seq CASCADE');
40 | $this->addSql('DROP TABLE fos_user');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/back-end/src/Repository/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/back-end/src/Repository/.gitignore
--------------------------------------------------------------------------------
/back-end/symfony.lock:
--------------------------------------------------------------------------------
1 | {
2 | "dama/doctrine-test-bundle": {
3 | "version": "4.0",
4 | "recipe": {
5 | "repo": "github.com/symfony/recipes-contrib",
6 | "branch": "master",
7 | "version": "4.0",
8 | "ref": "56eaa387b5e48ebcc7c95a893b47dfa1ad51449c"
9 | },
10 | "files": [
11 | "config/packages/test/dama_doctrine_test_bundle.yaml"
12 | ]
13 | },
14 | "doctrine/annotations": {
15 | "version": "1.0",
16 | "recipe": {
17 | "repo": "github.com/symfony/recipes",
18 | "branch": "master",
19 | "version": "1.0",
20 | "ref": "cb4152ebcadbe620ea2261da1a1c5a9b8cea7672"
21 | },
22 | "files": [
23 | "config/routes/annotations.yaml"
24 | ]
25 | },
26 | "doctrine/cache": {
27 | "version": "1.9.0"
28 | },
29 | "doctrine/collections": {
30 | "version": "1.6.4"
31 | },
32 | "doctrine/common": {
33 | "version": "v2.11.0"
34 | },
35 | "doctrine/data-fixtures": {
36 | "version": "1.4.0"
37 | },
38 | "doctrine/dbal": {
39 | "version": "v2.10.0"
40 | },
41 | "doctrine/doctrine-bundle": {
42 | "version": "1.6",
43 | "recipe": {
44 | "repo": "github.com/symfony/recipes",
45 | "branch": "master",
46 | "version": "1.6",
47 | "ref": "ae7f137d0cacaf8f259f4e05af59e326f065ba5e"
48 | },
49 | "files": [
50 | "config/packages/doctrine.yaml",
51 | "config/packages/prod/doctrine.yaml",
52 | "src/Entity/.gitignore",
53 | "src/Repository/.gitignore"
54 | ]
55 | },
56 | "doctrine/doctrine-cache-bundle": {
57 | "version": "1.3.5"
58 | },
59 | "doctrine/doctrine-fixtures-bundle": {
60 | "version": "3.0",
61 | "recipe": {
62 | "repo": "github.com/symfony/recipes",
63 | "branch": "master",
64 | "version": "3.0",
65 | "ref": "fc52d86631a6dfd9fdf3381d0b7e3df2069e51b3"
66 | },
67 | "files": [
68 | "src/DataFixtures/AppFixtures.php"
69 | ]
70 | },
71 | "doctrine/doctrine-migrations-bundle": {
72 | "version": "1.2",
73 | "recipe": {
74 | "repo": "github.com/symfony/recipes",
75 | "branch": "master",
76 | "version": "1.2",
77 | "ref": "c1431086fec31f17fbcfe6d6d7e92059458facc1"
78 | },
79 | "files": [
80 | "config/packages/doctrine_migrations.yaml",
81 | "src/Migrations/.gitignore"
82 | ]
83 | },
84 | "doctrine/event-manager": {
85 | "version": "1.1.0"
86 | },
87 | "doctrine/inflector": {
88 | "version": "1.3.1"
89 | },
90 | "doctrine/instantiator": {
91 | "version": "1.3.0"
92 | },
93 | "doctrine/lexer": {
94 | "version": "1.2.0"
95 | },
96 | "doctrine/migrations": {
97 | "version": "2.2.0"
98 | },
99 | "doctrine/orm": {
100 | "version": "v2.6.4"
101 | },
102 | "doctrine/persistence": {
103 | "version": "1.2.0"
104 | },
105 | "doctrine/reflection": {
106 | "version": "v1.0.0"
107 | },
108 | "easycorp/easy-log-handler": {
109 | "version": "1.0",
110 | "recipe": {
111 | "repo": "github.com/symfony/recipes",
112 | "branch": "master",
113 | "version": "1.0",
114 | "ref": "70062abc2cd58794d2a90274502f81b55cd9951b"
115 | },
116 | "files": [
117 | "config/packages/dev/easy_log_handler.yaml"
118 | ]
119 | },
120 | "egulias/email-validator": {
121 | "version": "2.1.11"
122 | },
123 | "fig/link-util": {
124 | "version": "1.0.0"
125 | },
126 | "friendsofsymfony/rest-bundle": {
127 | "version": "2.2",
128 | "recipe": {
129 | "repo": "github.com/symfony/recipes-contrib",
130 | "branch": "master",
131 | "version": "2.2",
132 | "ref": "cad41ef93d6150067ae2bb3c7fd729492dff6f0a"
133 | },
134 | "files": [
135 | "config/packages/fos_rest.yaml"
136 | ]
137 | },
138 | "friendsofsymfony/user-bundle": {
139 | "version": "v2.1.2"
140 | },
141 | "jdorn/sql-formatter": {
142 | "version": "v1.2.17"
143 | },
144 | "laminas/laminas-code": {
145 | "version": "3.4.1"
146 | },
147 | "laminas/laminas-eventmanager": {
148 | "version": "3.2.1"
149 | },
150 | "laminas/laminas-zendframework-bridge": {
151 | "version": "1.0.3"
152 | },
153 | "lcobucci/jwt": {
154 | "version": "3.3.1"
155 | },
156 | "lexik/jwt-authentication-bundle": {
157 | "version": "2.5",
158 | "recipe": {
159 | "repo": "github.com/symfony/recipes",
160 | "branch": "master",
161 | "version": "2.5",
162 | "ref": "5b2157bcd5778166a5696e42f552ad36529a07a6"
163 | },
164 | "files": [
165 | "config/packages/lexik_jwt_authentication.yaml"
166 | ]
167 | },
168 | "monolog/monolog": {
169 | "version": "1.25.2"
170 | },
171 | "namshi/jose": {
172 | "version": "7.2.3"
173 | },
174 | "nelmio/cors-bundle": {
175 | "version": "1.5",
176 | "recipe": {
177 | "repo": "github.com/symfony/recipes",
178 | "branch": "master",
179 | "version": "1.5",
180 | "ref": "6388de23860284db9acce0a7a5d9d13153bcb571"
181 | },
182 | "files": [
183 | "config/packages/nelmio_cors.yaml"
184 | ]
185 | },
186 | "nikic/php-parser": {
187 | "version": "v4.3.0"
188 | },
189 | "ocramius/package-versions": {
190 | "version": "1.4.1"
191 | },
192 | "ocramius/proxy-manager": {
193 | "version": "2.2.3"
194 | },
195 | "php": {
196 | "version": "7.4"
197 | },
198 | "phpdocumentor/reflection-common": {
199 | "version": "2.0.0"
200 | },
201 | "phpdocumentor/reflection-docblock": {
202 | "version": "4.3.2"
203 | },
204 | "phpdocumentor/type-resolver": {
205 | "version": "1.0.1"
206 | },
207 | "psr/cache": {
208 | "version": "1.0.1"
209 | },
210 | "psr/container": {
211 | "version": "1.0.0"
212 | },
213 | "psr/link": {
214 | "version": "1.0.0"
215 | },
216 | "psr/log": {
217 | "version": "1.1.2"
218 | },
219 | "sensio/framework-extra-bundle": {
220 | "version": "5.2",
221 | "recipe": {
222 | "repo": "github.com/symfony/recipes",
223 | "branch": "master",
224 | "version": "5.2",
225 | "ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b"
226 | },
227 | "files": [
228 | "config/packages/sensio_framework_extra.yaml"
229 | ]
230 | },
231 | "swiftmailer/swiftmailer": {
232 | "version": "v6.2.3"
233 | },
234 | "symfony/asset": {
235 | "version": "v4.3.8"
236 | },
237 | "symfony/browser-kit": {
238 | "version": "v4.3.8"
239 | },
240 | "symfony/cache": {
241 | "version": "v4.3.8"
242 | },
243 | "symfony/cache-contracts": {
244 | "version": "v1.1.7"
245 | },
246 | "symfony/config": {
247 | "version": "v4.3.8"
248 | },
249 | "symfony/console": {
250 | "version": "3.3",
251 | "recipe": {
252 | "repo": "github.com/symfony/recipes",
253 | "branch": "master",
254 | "version": "3.3",
255 | "ref": "482d233eb8de91ebd042992077bbd5838858890c"
256 | },
257 | "files": [
258 | "bin/console",
259 | "config/bootstrap.php"
260 | ]
261 | },
262 | "symfony/css-selector": {
263 | "version": "v4.3.8"
264 | },
265 | "symfony/debug": {
266 | "version": "v4.3.8"
267 | },
268 | "symfony/debug-bundle": {
269 | "version": "4.1",
270 | "recipe": {
271 | "repo": "github.com/symfony/recipes",
272 | "branch": "master",
273 | "version": "4.1",
274 | "ref": "f8863cbad2f2e58c4b65fa1eac892ab189971bea"
275 | },
276 | "files": [
277 | "config/packages/dev/debug.yaml"
278 | ]
279 | },
280 | "symfony/debug-pack": {
281 | "version": "v1.0.7"
282 | },
283 | "symfony/dependency-injection": {
284 | "version": "v4.3.8"
285 | },
286 | "symfony/doctrine-bridge": {
287 | "version": "v4.3.8"
288 | },
289 | "symfony/dom-crawler": {
290 | "version": "v4.3.8"
291 | },
292 | "symfony/dotenv": {
293 | "version": "v4.3.8"
294 | },
295 | "symfony/event-dispatcher": {
296 | "version": "v4.3.8"
297 | },
298 | "symfony/event-dispatcher-contracts": {
299 | "version": "v1.1.7"
300 | },
301 | "symfony/expression-language": {
302 | "version": "v4.3.8"
303 | },
304 | "symfony/filesystem": {
305 | "version": "v4.3.8"
306 | },
307 | "symfony/finder": {
308 | "version": "v4.3.8"
309 | },
310 | "symfony/flex": {
311 | "version": "1.0",
312 | "recipe": {
313 | "repo": "github.com/symfony/recipes",
314 | "branch": "master",
315 | "version": "1.0",
316 | "ref": "19fa03bacd9a6619583d1e4939da4388df22984d"
317 | },
318 | "files": [
319 | ".env"
320 | ]
321 | },
322 | "symfony/form": {
323 | "version": "v4.3.8"
324 | },
325 | "symfony/framework-bundle": {
326 | "version": "4.2",
327 | "recipe": {
328 | "repo": "github.com/symfony/recipes",
329 | "branch": "master",
330 | "version": "4.2",
331 | "ref": "61ad963f28c091b8bb9449507654b9c7d8bbb53c"
332 | },
333 | "files": [
334 | "config/bootstrap.php",
335 | "config/packages/cache.yaml",
336 | "config/packages/framework.yaml",
337 | "config/packages/test/framework.yaml",
338 | "config/services.yaml",
339 | "public/index.php",
340 | "src/Controller/.gitignore",
341 | "src/Kernel.php"
342 | ]
343 | },
344 | "symfony/http-client": {
345 | "version": "v4.3.8"
346 | },
347 | "symfony/http-client-contracts": {
348 | "version": "v1.1.8"
349 | },
350 | "symfony/http-foundation": {
351 | "version": "v4.3.8"
352 | },
353 | "symfony/http-kernel": {
354 | "version": "v4.3.8"
355 | },
356 | "symfony/inflector": {
357 | "version": "v4.3.8"
358 | },
359 | "symfony/intl": {
360 | "version": "v4.3.8"
361 | },
362 | "symfony/maker-bundle": {
363 | "version": "1.0",
364 | "recipe": {
365 | "repo": "github.com/symfony/recipes",
366 | "branch": "master",
367 | "version": "1.0",
368 | "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
369 | }
370 | },
371 | "symfony/mime": {
372 | "version": "v4.3.8"
373 | },
374 | "symfony/monolog-bridge": {
375 | "version": "v4.3.8"
376 | },
377 | "symfony/monolog-bundle": {
378 | "version": "3.3",
379 | "recipe": {
380 | "repo": "github.com/symfony/recipes",
381 | "branch": "master",
382 | "version": "3.3",
383 | "ref": "6240c6d43e8237a32452f057f81816820fd56ab6"
384 | },
385 | "files": [
386 | "config/packages/dev/monolog.yaml",
387 | "config/packages/prod/monolog.yaml",
388 | "config/packages/test/monolog.yaml"
389 | ]
390 | },
391 | "symfony/options-resolver": {
392 | "version": "v4.3.8"
393 | },
394 | "symfony/orm-pack": {
395 | "version": "v1.0.7"
396 | },
397 | "symfony/phpunit-bridge": {
398 | "version": "4.3",
399 | "recipe": {
400 | "repo": "github.com/symfony/recipes",
401 | "branch": "master",
402 | "version": "4.3",
403 | "ref": "b0582341f1df39aaf3a9a866cdbe49937da35984"
404 | },
405 | "files": [
406 | ".env.test",
407 | "bin/phpunit",
408 | "config/bootstrap.php",
409 | "phpunit.xml.dist",
410 | "tests/.gitignore"
411 | ]
412 | },
413 | "symfony/polyfill-intl-icu": {
414 | "version": "v1.12.0"
415 | },
416 | "symfony/polyfill-intl-idn": {
417 | "version": "v1.12.0"
418 | },
419 | "symfony/polyfill-mbstring": {
420 | "version": "v1.12.0"
421 | },
422 | "symfony/polyfill-php72": {
423 | "version": "v1.12.0"
424 | },
425 | "symfony/polyfill-php73": {
426 | "version": "v1.12.0"
427 | },
428 | "symfony/process": {
429 | "version": "v4.3.8"
430 | },
431 | "symfony/profiler-pack": {
432 | "version": "v1.0.4"
433 | },
434 | "symfony/property-access": {
435 | "version": "v4.3.8"
436 | },
437 | "symfony/property-info": {
438 | "version": "v4.3.8"
439 | },
440 | "symfony/routing": {
441 | "version": "4.2",
442 | "recipe": {
443 | "repo": "github.com/symfony/recipes",
444 | "branch": "master",
445 | "version": "4.2",
446 | "ref": "683dcb08707ba8d41b7e34adb0344bfd68d248a7"
447 | },
448 | "files": [
449 | "config/packages/prod/routing.yaml",
450 | "config/packages/routing.yaml",
451 | "config/routes.yaml"
452 | ]
453 | },
454 | "symfony/security-bundle": {
455 | "version": "3.3",
456 | "recipe": {
457 | "repo": "github.com/symfony/recipes",
458 | "branch": "master",
459 | "version": "3.3",
460 | "ref": "e5a0228251d1dd2bca4c8ef918e14423c06db625"
461 | },
462 | "files": [
463 | "config/packages/security.yaml"
464 | ]
465 | },
466 | "symfony/security-core": {
467 | "version": "v4.3.8"
468 | },
469 | "symfony/security-csrf": {
470 | "version": "v4.3.8"
471 | },
472 | "symfony/security-guard": {
473 | "version": "v4.3.8"
474 | },
475 | "symfony/security-http": {
476 | "version": "v4.3.8"
477 | },
478 | "symfony/serializer": {
479 | "version": "v4.3.8"
480 | },
481 | "symfony/serializer-pack": {
482 | "version": "v1.0.2"
483 | },
484 | "symfony/service-contracts": {
485 | "version": "v1.1.8"
486 | },
487 | "symfony/stopwatch": {
488 | "version": "v4.3.8"
489 | },
490 | "symfony/swiftmailer-bundle": {
491 | "version": "2.5",
492 | "recipe": {
493 | "repo": "github.com/symfony/recipes",
494 | "branch": "master",
495 | "version": "2.5",
496 | "ref": "429afc6c6778a1fdddb52a4f708cd94ff2c9960f"
497 | },
498 | "files": [
499 | "config/packages/dev/swiftmailer.yaml",
500 | "config/packages/swiftmailer.yaml",
501 | "config/packages/test/swiftmailer.yaml"
502 | ]
503 | },
504 | "symfony/templating": {
505 | "version": "v4.3.8"
506 | },
507 | "symfony/test-pack": {
508 | "version": "v1.0.6"
509 | },
510 | "symfony/translation": {
511 | "version": "3.3",
512 | "recipe": {
513 | "repo": "github.com/symfony/recipes",
514 | "branch": "master",
515 | "version": "3.3",
516 | "ref": "2ad9d2545bce8ca1a863e50e92141f0b9d87ffcd"
517 | },
518 | "files": [
519 | "config/packages/translation.yaml",
520 | "translations/.gitignore"
521 | ]
522 | },
523 | "symfony/translation-contracts": {
524 | "version": "v1.1.7"
525 | },
526 | "symfony/twig-bridge": {
527 | "version": "v4.3.8"
528 | },
529 | "symfony/twig-bundle": {
530 | "version": "3.3",
531 | "recipe": {
532 | "repo": "github.com/symfony/recipes",
533 | "branch": "master",
534 | "version": "3.3",
535 | "ref": "7e5911186d596214c14dd28305485a3c143ee746"
536 | },
537 | "files": [
538 | "config/packages/twig.yaml",
539 | "config/routes/dev/twig.yaml",
540 | "templates/base.html.twig"
541 | ]
542 | },
543 | "symfony/validator": {
544 | "version": "4.3",
545 | "recipe": {
546 | "repo": "github.com/symfony/recipes",
547 | "branch": "master",
548 | "version": "4.3",
549 | "ref": "d902da3e4952f18d3bf05aab29512eb61cabd869"
550 | },
551 | "files": [
552 | "config/packages/test/validator.yaml",
553 | "config/packages/validator.yaml"
554 | ]
555 | },
556 | "symfony/var-dumper": {
557 | "version": "v4.3.8"
558 | },
559 | "symfony/var-exporter": {
560 | "version": "v4.3.8"
561 | },
562 | "symfony/web-link": {
563 | "version": "v4.3.8"
564 | },
565 | "symfony/web-profiler-bundle": {
566 | "version": "3.3",
567 | "recipe": {
568 | "repo": "github.com/symfony/recipes",
569 | "branch": "master",
570 | "version": "3.3",
571 | "ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6"
572 | },
573 | "files": [
574 | "config/packages/dev/web_profiler.yaml",
575 | "config/packages/test/web_profiler.yaml",
576 | "config/routes/dev/web_profiler.yaml"
577 | ]
578 | },
579 | "symfony/web-server-bundle": {
580 | "version": "3.3",
581 | "recipe": {
582 | "repo": "github.com/symfony/recipes",
583 | "branch": "master",
584 | "version": "3.3",
585 | "ref": "dae9b39fd6717970be7601101ce5aa960bf53d9a"
586 | }
587 | },
588 | "symfony/yaml": {
589 | "version": "v4.3.8"
590 | },
591 | "twig/twig": {
592 | "version": "v2.12.2"
593 | },
594 | "webimpress/safe-writer": {
595 | "version": "2.0.1"
596 | },
597 | "webmozart/assert": {
598 | "version": "1.5.0"
599 | },
600 | "willdurand/jsonp-callback-validator": {
601 | "version": "v1.1.0"
602 | },
603 | "willdurand/negotiation": {
604 | "version": "v2.3.1"
605 | },
606 | "zendframework/zend-code": {
607 | "version": "3.4.0"
608 | },
609 | "zendframework/zend-eventmanager": {
610 | "version": "3.2.1"
611 | }
612 | }
613 |
--------------------------------------------------------------------------------
/back-end/templates/base.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% block title %}Welcome!{% endblock %}
6 | {% block stylesheets %}{% endblock %}
7 |
8 |
9 | {% block body %}{% endblock %}
10 | {% block javascripts %}{% endblock %}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/back-end/tests/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/back-end/tests/.gitignore
--------------------------------------------------------------------------------
/back-end/tests/Controller/ApiControllerTest.php:
--------------------------------------------------------------------------------
1 | request(
21 | 'POST',
22 | '/api/login_check',
23 | [],
24 | [],
25 | ['CONTENT_TYPE' => 'application/json'],
26 | json_encode([
27 | 'username' => $username,
28 | 'password' => $password,
29 | ])
30 | );
31 |
32 | $data = json_decode($client->getResponse()->getContent(), true);
33 |
34 | $client = static::createClient();
35 | $client->setServerParameter('HTTP_Authorization', sprintf('Bearer %s', $data['token']));
36 |
37 | return $client;
38 | }
39 |
40 | public function testGetHelloWithoutToken()
41 | {
42 | $client = static::createClient();
43 |
44 | $client->request('GET', '/api/hello');
45 |
46 | $this->assertEquals(401, $client->getResponse()->getStatusCode());
47 | }
48 |
49 | public function testGetHelloWithToken()
50 | {
51 | // User created by running doctrine fixtures
52 | $credentials = ['username' => 'bob', 'password' => 'Abc123'];
53 |
54 | $client = $this->createAuthenticatedClient($credentials['username'], $credentials['password']);
55 | $client->request('GET', '/api/hello');
56 |
57 | $this->assertEquals(200, $client->getResponse()->getStatusCode());
58 | $content = json_decode($client->getResponse()->getContent(), true);
59 | $this->assertEquals('world', $content['hello']);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/back-end/tests/Controller/DefaultControllerTest.php:
--------------------------------------------------------------------------------
1 | request('GET', '/');
14 |
15 | $this->assertEquals(200, $client->getResponse()->getStatusCode());
16 | }
17 |
18 | public function testPostLogin()
19 | {
20 | // User created by running doctrine fixtures
21 | $credentials = ['username' => 'bob', 'password' => 'Abc123'];
22 | $client = static::createClient();
23 | $client->request(
24 | 'POST',
25 | '/api/login_check',
26 | [],
27 | [],
28 | ['CONTENT_TYPE' => 'application/json'],
29 | json_encode($credentials)
30 | );
31 |
32 | // Get the user session token
33 | $this->assertEquals(200, $client->getResponse()->getStatusCode());
34 | $content = json_decode($client->getResponse()->getContent(), true);
35 | $this->assertArrayHasKey('token', $content);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/back-end/translations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/back-end/translations/.gitignore
--------------------------------------------------------------------------------
/buy-me-a-coffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/buy-me-a-coffee.png
--------------------------------------------------------------------------------
/config/nginx/angular.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8080; ## listen for ipv4; this line is default and implied
3 | listen [::]:8080 default ipv6only=on; ## listen for ipv6
4 |
5 | root /app/dist;
6 | index index.php index.html index.htm;
7 |
8 | # Add stdout logging
9 |
10 | error_log /dev/stdout info;
11 | access_log /dev/stdout;
12 |
13 | location / {
14 | proxy_pass http://client:4200/;
15 | }
16 |
17 | # deny access to . files, for security
18 | #
19 | location ~ /\. {
20 | log_not_found off;
21 | deny all;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/config/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | user www-data www-data;
2 | worker_processes 1;
3 |
4 | error_log /var/log/nginx/error.log warn;
5 | pid /var/run/nginx.pid;
6 |
7 |
8 | events {
9 | worker_connections 1024;
10 | }
11 |
12 |
13 | http {
14 | include /etc/nginx/mime.types;
15 | default_type application/octet-stream;
16 |
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 |
21 | access_log /var/log/nginx/access.log main;
22 |
23 | sendfile off;
24 | #tcp_nopush on;
25 |
26 | keepalive_timeout 65;
27 |
28 | #gzip on;
29 |
30 | include /etc/nginx/conf.d/*.conf;
31 | }
32 |
--------------------------------------------------------------------------------
/config/nginx/symfony.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8000; ## listen for ipv4; this line is default and implied
3 | listen [::]:8000 default ipv6only=on; ## listen for ipv6
4 |
5 | root /var/www/public;
6 | index index.php index.html index.htm;
7 |
8 | # Make site accessible from http://localhost/
9 | #server_name localhost;
10 |
11 | # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
12 | #sendfile off;
13 |
14 | # Add stdout logging
15 |
16 | error_log /dev/stdout info;
17 | access_log /dev/stdout;
18 |
19 | location / {
20 | # try to serve file directly, fallback to index.php
21 | try_files $uri /index.php$is_args$args;
22 | }
23 |
24 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
25 | #
26 | location ~ ^/index\.php(/|$) {
27 | fastcgi_pass application:9000;
28 | fastcgi_split_path_info ^(.+\.php)(/.*)$;
29 | include fastcgi_params;
30 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
31 | fastcgi_param DOCUMENT_ROOT $document_root;
32 | fastcgi_param HTTPS off;
33 | internal;
34 | }
35 |
36 | # return 404 for all other php files not matching the front controller
37 | # this prevents access to other php files you don't want to be accessible.
38 | location ~ \.php$ {
39 | return 404;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | application:
2 | build: back-end
3 | volumes:
4 | - "./back-end:/var/www"
5 | links:
6 | - database
7 |
8 | client:
9 | build: front-end
10 | volumes:
11 | - "./front-end:/app"
12 | links:
13 | - nginx-back
14 |
15 | database:
16 | image: postgres:10
17 | ports:
18 | - 5432:5432
19 | environment:
20 | POSTGRES_PASSWORD: postgres
21 | POSTGRES_USER: postgres
22 | POSTGRES_DB: symfony_dev
23 |
24 | nginx-front:
25 | image: nginx
26 | ports:
27 | - 8080:8080
28 | links:
29 | - client
30 | volumes:
31 | - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
32 | - ./config/nginx/angular.conf:/etc/nginx/conf.d/default.conf
33 |
34 | nginx-back:
35 | image: nginx
36 | ports:
37 | - 8000:8000
38 | links:
39 | - application
40 | volumes:
41 | - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
42 | - ./config/nginx/symfony.conf:/etc/nginx/conf.d/default.conf
43 |
--------------------------------------------------------------------------------
/front-end/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .git
3 | .gitignore
4 |
--------------------------------------------------------------------------------
/front-end/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .tool-versions
3 |
--------------------------------------------------------------------------------
/front-end/Dockerfile:
--------------------------------------------------------------------------------
1 | # base image
2 | FROM node:12.16
3 |
4 | # install chrome for protractor tests
5 | RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
6 | RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
7 | RUN apt-get update && apt-get install -yq google-chrome-stable
8 |
9 | # set working directory
10 | WORKDIR /app
11 |
12 | # install and cache app dependencies
13 | COPY package.json /app/package.json
14 | RUN npm install
15 | RUN npm install -g @angular/cli@7.3.9
16 |
17 | # add `/app/node_modules/.bin` to $PATH
18 | ENV PATH /app/node_modules/.bin:$PATH
19 |
20 | # add app
21 | COPY . /app
22 |
23 | EXPOSE 4200
24 | # start app
25 | CMD ng serve --host 0.0.0.0 --disable-host-check
26 |
27 |
--------------------------------------------------------------------------------
/front-end/README.md:
--------------------------------------------------------------------------------
1 | # Angular Symfony
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.19.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
28 |
--------------------------------------------------------------------------------
/front-end/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "angularSymfony": {
7 | "projectType": "application",
8 | "schematics": {},
9 | "root": "",
10 | "sourceRoot": "src",
11 | "prefix": "app",
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "outputPath": "dist/angularSymfony",
17 | "index": "src/index.html",
18 | "main": "src/main.ts",
19 | "polyfills": "src/polyfills.ts",
20 | "tsConfig": "tsconfig.app.json",
21 | "aot": false,
22 | "assets": [
23 | "src/favicon.ico",
24 | "src/assets"
25 | ],
26 | "styles": [
27 | "src/styles.css"
28 | ],
29 | "scripts": []
30 | },
31 | "configurations": {
32 | "production": {
33 | "fileReplacements": [
34 | {
35 | "replace": "src/environments/environment.ts",
36 | "with": "src/environments/environment.prod.ts"
37 | }
38 | ],
39 | "optimization": true,
40 | "outputHashing": "all",
41 | "sourceMap": false,
42 | "extractCss": true,
43 | "namedChunks": false,
44 | "aot": true,
45 | "extractLicenses": true,
46 | "vendorChunk": false,
47 | "buildOptimizer": true,
48 | "budgets": [
49 | {
50 | "type": "initial",
51 | "maximumWarning": "2mb",
52 | "maximumError": "5mb"
53 | },
54 | {
55 | "type": "anyComponentStyle",
56 | "maximumWarning": "6kb",
57 | "maximumError": "10kb"
58 | }
59 | ]
60 | }
61 | }
62 | },
63 | "serve": {
64 | "builder": "@angular-devkit/build-angular:dev-server",
65 | "options": {
66 | "browserTarget": "angularSymfony:build"
67 | },
68 | "configurations": {
69 | "production": {
70 | "browserTarget": "angularSymfony:build:production"
71 | }
72 | }
73 | },
74 | "extract-i18n": {
75 | "builder": "@angular-devkit/build-angular:extract-i18n",
76 | "options": {
77 | "browserTarget": "angularSymfony:build"
78 | }
79 | },
80 | "test": {
81 | "builder": "@angular-devkit/build-angular:karma",
82 | "options": {
83 | "main": "src/test.ts",
84 | "polyfills": "src/polyfills.ts",
85 | "tsConfig": "tsconfig.spec.json",
86 | "karmaConfig": "karma.conf.js",
87 | "assets": [
88 | "src/favicon.ico",
89 | "src/assets"
90 | ],
91 | "styles": [
92 | "src/styles.css"
93 | ],
94 | "scripts": []
95 | }
96 | },
97 | "lint": {
98 | "builder": "@angular-devkit/build-angular:tslint",
99 | "options": {
100 | "tsConfig": [
101 | "tsconfig.app.json",
102 | "tsconfig.spec.json",
103 | "e2e/tsconfig.json"
104 | ],
105 | "exclude": [
106 | "**/node_modules/**"
107 | ]
108 | }
109 | },
110 | "e2e": {
111 | "builder": "@angular-devkit/build-angular:protractor",
112 | "options": {
113 | "protractorConfig": "e2e/protractor.conf.js",
114 | "devServerTarget": "angularSymfony:serve"
115 | },
116 | "configurations": {
117 | "production": {
118 | "devServerTarget": "angularSymfony:serve:production"
119 | }
120 | }
121 | }
122 | }
123 | }},
124 | "defaultProject": "angularSymfony"
125 | }
--------------------------------------------------------------------------------
/front-end/browserslist:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # You can see what browsers were selected by your queries by running:
6 | # npx browserslist
7 |
8 | > 0.5%
9 | last 2 versions
10 | Firefox ESR
11 | not dead
12 | not IE 9-11 # For IE 9-11 support, remove 'not'.
--------------------------------------------------------------------------------
/front-end/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Protractor configuration file, see link for more information
3 | // https://github.com/angular/protractor/blob/master/lib/config.ts
4 |
5 | const { SpecReporter } = require('jasmine-spec-reporter');
6 |
7 | /**
8 | * @type { import("protractor").Config }
9 | */
10 | exports.config = {
11 | allScriptsTimeout: 11000,
12 | specs: [
13 | './src/**/*.e2e-spec.ts'
14 | ],
15 | capabilities: {
16 | browserName: 'chrome'
17 | },
18 | directConnect: true,
19 | baseUrl: 'http://localhost:4200/',
20 | framework: 'jasmine',
21 | jasmineNodeOpts: {
22 | showColors: true,
23 | defaultTimeoutInterval: 30000,
24 | print: function() {}
25 | },
26 | onPrepare() {
27 | require('ts-node').register({
28 | project: require('path').join(__dirname, './tsconfig.json')
29 | });
30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
31 | }
32 | };
--------------------------------------------------------------------------------
/front-end/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 | import { browser, logging } from 'protractor';
3 |
4 | describe('workspace-project App', () => {
5 | let page: AppPage;
6 |
7 | beforeEach(() => {
8 | page = new AppPage();
9 | });
10 |
11 | it('should display welcome message', () => {
12 | page.navigateTo();
13 | expect(page.getTitleText()).toEqual('angular symfony app is running!');
14 | });
15 |
16 | afterEach(async () => {
17 | // Assert that there are no errors emitted from the browser
18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER);
19 | expect(logs).not.toContain(jasmine.objectContaining({
20 | level: logging.Level.SEVERE,
21 | } as logging.Entry));
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/front-end/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get(browser.baseUrl) as Promise;
6 | }
7 |
8 | getTitleText() {
9 | return element(by.css('app-root .content span')).getText() as Promise;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/front-end/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "types": [
8 | "jasmine",
9 | "jasminewd2",
10 | "node"
11 | ]
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/front-end/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, './coverage/project'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/front-end/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "full-front-project",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "test": "ng test",
9 | "lint": "ng lint",
10 | "e2e": "ng e2e"
11 | },
12 | "private": true,
13 | "dependencies": {
14 | "@angular/animations": "~8.2.14",
15 | "@angular/common": "~8.2.14",
16 | "@angular/compiler": "~8.2.14",
17 | "@angular/core": "~8.2.14",
18 | "@angular/forms": "~8.2.14",
19 | "@angular/platform-browser": "~8.2.14",
20 | "@angular/platform-browser-dynamic": "~8.2.14",
21 | "@angular/router": "~8.2.14",
22 | "rxjs": "~6.4.0",
23 | "zone.js": "~0.9.1"
24 | },
25 | "devDependencies": {
26 | "@angular-devkit/build-angular": "^0.803.19",
27 | "@angular/cli": "~8.3.19",
28 | "@angular/compiler-cli": "~8.2.14",
29 | "@angular/language-service": "~8.2.14",
30 | "@types/jasmine": "~3.3.8",
31 | "@types/jasminewd2": "~2.0.3",
32 | "@types/node": "^8.10.59",
33 | "codelyzer": "^5.0.0",
34 | "jasmine-core": "~3.4.0",
35 | "jasmine-spec-reporter": "~4.2.1",
36 | "karma": "~4.1.0",
37 | "karma-chrome-launcher": "~2.2.0",
38 | "karma-coverage-istanbul-reporter": "~2.0.1",
39 | "karma-jasmine": "~2.0.1",
40 | "karma-jasmine-html-reporter": "^1.4.0",
41 | "protractor": "~5.4.0",
42 | "ts-node": "~7.0.0",
43 | "tslint": "^5.15.0",
44 | "typescript": "^3.5.3",
45 | "typescript-tslint-plugin": "^0.5.5"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/front-end/src/app/api.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { HttpClientTestingModule } from '@angular/common/http/testing';
3 |
4 | import { APIService } from './api.service';
5 |
6 | describe('APIService', () => {
7 | beforeEach(() =>
8 | TestBed.configureTestingModule({
9 | imports: [HttpClientTestingModule]
10 | })
11 | );
12 |
13 | it('should be created', () => {
14 | const service: APIService = TestBed.get(APIService);
15 | expect(service).toBeTruthy();
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/front-end/src/app/api.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { HttpClient } from '@angular/common/http';
4 |
5 | import { environment } from '../environments/environment';
6 | import { Observable } from 'rxjs';
7 |
8 | interface CredentialsType {
9 | username: string;
10 | password: string;
11 | }
12 |
13 | @Injectable({
14 | providedIn: 'root'
15 | })
16 | export class APIService {
17 | constructor(private httpClient: HttpClient) { }
18 |
19 | postCredentials(
20 | credentials: CredentialsType
21 | ): Observable<{ token?: string }> {
22 | return this.httpClient.post(environment.server + '/api/login_check', credentials);
23 | }
24 |
25 | getHello(): Observable<{ hello?: string }> {
26 | return this.httpClient.get(environment.server + '/api/hello');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/front-end/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { Routes, RouterModule } from '@angular/router';
3 | import { LoginComponent } from './login/login.component';
4 | import { HelloComponent } from './hello/hello.component';
5 |
6 | const routes: Routes = [
7 | { path: '', component: LoginComponent },
8 | { path: 'hello', component: HelloComponent }
9 | ];
10 |
11 | @NgModule({
12 | imports: [RouterModule.forRoot(routes)],
13 | exports: [RouterModule]
14 | })
15 | export class AppRoutingModule {}
16 |
--------------------------------------------------------------------------------
/front-end/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/front-end/src/app/app.component.css
--------------------------------------------------------------------------------
/front-end/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/front-end/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, async } from '@angular/core/testing';
2 | import { RouterTestingModule } from '@angular/router/testing';
3 | import { AppComponent } from './app.component';
4 |
5 | describe('AppComponent', () => {
6 | beforeEach(async(() => {
7 | TestBed.configureTestingModule({
8 | imports: [RouterTestingModule],
9 | declarations: [AppComponent]
10 | }).compileComponents();
11 | }));
12 |
13 | it('should create the app', () => {
14 | const fixture = TestBed.createComponent(AppComponent);
15 | const app = fixture.debugElement.componentInstance;
16 | expect(app).toBeTruthy();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/front-end/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'Angular Symfony';
10 | }
11 |
--------------------------------------------------------------------------------
/front-end/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 |
4 | import { AppRoutingModule } from './app-routing.module';
5 | import { ReactiveFormsModule } from '@angular/forms';
6 | import { HttpClientModule } from '@angular/common/http';
7 | import { AppComponent } from './app.component';
8 | import { LoginComponent } from './login/login.component';
9 | import { HelloComponent } from './hello/hello.component';
10 | import { httpInterceptorProviders } from './http-interceptor';
11 |
12 | @NgModule({
13 | declarations: [AppComponent, LoginComponent, HelloComponent],
14 | imports: [
15 | BrowserModule,
16 | AppRoutingModule,
17 | ReactiveFormsModule,
18 | HttpClientModule
19 | ],
20 | providers: [httpInterceptorProviders],
21 | bootstrap: [AppComponent]
22 | })
23 | export class AppModule { }
24 |
--------------------------------------------------------------------------------
/front-end/src/app/hello/hello.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/front-end/src/app/hello/hello.component.css
--------------------------------------------------------------------------------
/front-end/src/app/hello/hello.component.html:
--------------------------------------------------------------------------------
1 | Hello Component
2 |
3 | Server sended you hello message : {{ helloMessage }}
4 |
5 |
--------------------------------------------------------------------------------
/front-end/src/app/hello/hello.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 | import { HttpClientTestingModule } from '@angular/common/http/testing';
3 | import { RouterTestingModule } from '@angular/router/testing';
4 |
5 | import { HelloComponent } from './hello.component';
6 |
7 | describe('HelloComponent', () => {
8 | let component: HelloComponent;
9 | let fixture: ComponentFixture;
10 |
11 | beforeEach(async(() => {
12 | TestBed.configureTestingModule({
13 | imports: [HttpClientTestingModule, RouterTestingModule],
14 | declarations: [HelloComponent]
15 | }).compileComponents();
16 | }));
17 |
18 | beforeEach(() => {
19 | fixture = TestBed.createComponent(HelloComponent);
20 | component = fixture.componentInstance;
21 | fixture.detectChanges();
22 | });
23 |
24 | it('should create', () => {
25 | expect(component).toBeTruthy();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/front-end/src/app/hello/hello.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { Observable } from 'rxjs';
3 |
4 | import { APIService } from '../api.service';
5 | import { HttpErrorResponse } from '@angular/common/http';
6 | import { Router } from '@angular/router';
7 | import { TokenService } from '../token.service';
8 |
9 | @Component({
10 | selector: 'app-hello',
11 | templateUrl: './hello.component.html',
12 | styleUrls: ['./hello.component.css']
13 | })
14 | export class HelloComponent implements OnInit {
15 | $hello: Observable<{ hello?: string }>;
16 | helloMessage: string;
17 |
18 | constructor(
19 | private apiService: APIService,
20 | private tokenService: TokenService,
21 | private router: Router
22 | ) {}
23 |
24 | ngOnInit() {
25 | // Example API call showing an Hello World
26 | this.$hello = this.apiService.getHello();
27 |
28 | this.$hello.subscribe(
29 | // Show API response
30 | ({ hello }) => {
31 | console.log(`Received from server ${hello}`);
32 | this.helloMessage = hello;
33 | },
34 | // Log error message and redirect to login
35 | (error: HttpErrorResponse) => {
36 | console.error(error);
37 | if (error.status === 401) {
38 | return this.router.navigate(['']);
39 | }
40 | }
41 | );
42 | }
43 |
44 | onGoBack() {
45 | return this.router.navigate(['']);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/front-end/src/app/http-interceptor/index.ts:
--------------------------------------------------------------------------------
1 | import { HTTP_INTERCEPTORS } from '@angular/common/http';
2 |
3 | import { JWTInterceptor } from './jwt-interceptor';
4 |
5 | /** Http interceptor providers in outside-in order */
6 | export const httpInterceptorProviders = [
7 | { provide: HTTP_INTERCEPTORS, useClass: JWTInterceptor, multi: true }
8 | ];
9 |
--------------------------------------------------------------------------------
/front-end/src/app/http-interceptor/jwt-interceptor.ts:
--------------------------------------------------------------------------------
1 | import { TokenService } from '../token.service';
2 | import { Injectable } from '@angular/core';
3 | import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
4 |
5 | @Injectable()
6 | export class JWTInterceptor implements HttpInterceptor {
7 | constructor(private tokenService: TokenService) {}
8 |
9 | intercept(req: HttpRequest, next: HttpHandler) {
10 | const authToken = this.tokenService.getAuthorizationToken();
11 |
12 | if (authToken) {
13 | // Clone the request and replace the original headers with
14 | // cloned headers, updated with the authorization.
15 | const authReq = req.clone({
16 | headers: req.headers.set('Authorization', `Bearer ${authToken}`)
17 | });
18 | // send cloned request with header to the next handler.
19 | return next.handle(authReq);
20 | } else {
21 | // otherwise send request without token
22 | return next.handle(req);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/front-end/src/app/login/login.component.css:
--------------------------------------------------------------------------------
1 | label {
2 | padding: 0.5em 1.5em;
3 | }
--------------------------------------------------------------------------------
/front-end/src/app/login/login.component.html:
--------------------------------------------------------------------------------
1 | Login Component
2 |
3 | Error from server : {{ error }}
4 |
5 | Generated token is
{{ token }}
6 |
7 | Please enter a symfony valid user
8 |
9 |
26 |
27 | Try to access to API after your're logged in.
28 |
29 |
--------------------------------------------------------------------------------
/front-end/src/app/login/login.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { LoginComponent } from './login.component';
4 | import { ReactiveFormsModule } from '@angular/forms';
5 | import { HttpClientTestingModule } from '@angular/common/http/testing';
6 | import { RouterTestingModule } from '@angular/router/testing';
7 |
8 | describe('LoginComponent', () => {
9 | let component: LoginComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | imports: [
15 | ReactiveFormsModule,
16 | HttpClientTestingModule,
17 | RouterTestingModule
18 | ],
19 | declarations: [LoginComponent]
20 | }).compileComponents();
21 | }));
22 |
23 | beforeEach(() => {
24 | fixture = TestBed.createComponent(LoginComponent);
25 | component = fixture.componentInstance;
26 | fixture.detectChanges();
27 | });
28 |
29 | it('should create', () => {
30 | expect(component).toBeTruthy();
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/front-end/src/app/login/login.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { FormGroup, FormControl } from '@angular/forms';
3 | import { Router } from '@angular/router';
4 |
5 | import { APIService } from '../api.service';
6 | import { TokenService } from '../token.service';
7 | import { Observable } from 'rxjs';
8 | import { HttpErrorResponse } from '@angular/common/http';
9 |
10 | @Component({
11 | selector: 'app-login',
12 | templateUrl: './login.component.html',
13 | styleUrls: ['./login.component.css']
14 | })
15 | export class LoginComponent implements OnInit {
16 | $login: Observable<{ token?: string }>;
17 | token: string;
18 | error: string;
19 |
20 | credentialsForm = new FormGroup({
21 | username: new FormControl(''),
22 | password: new FormControl('')
23 | });
24 |
25 | constructor(
26 | private apiService: APIService,
27 | private tokenService: TokenService,
28 | private router: Router
29 | ) { }
30 |
31 | ngOnInit() {
32 | this.token = this.tokenService.getAuthorizationToken();
33 | }
34 |
35 | onSubmit() {
36 | const credentials: { username: string; password: string } = this
37 | .credentialsForm.value;
38 |
39 | // Login should return jwt token
40 | this.$login = this.apiService.postCredentials(credentials);
41 |
42 | this.$login.subscribe(
43 | // Show generated token
44 | ({ token }) => {
45 | console.log('Received JWT token', token);
46 | this.tokenService.setAuthorizationToken(token);
47 | this.token = token;
48 | },
49 | // Show server error
50 | (error: HttpErrorResponse) => {
51 | console.error(error);
52 | this.error = error.message;
53 | }
54 | );
55 | }
56 |
57 | onLogout() {
58 | this.tokenService.cleanAuthorizationToken();
59 | this.token = null;
60 | return this.router.navigate(['']);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/front-end/src/app/token.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { TokenService } from './token.service';
4 |
5 | describe('TokenService', () => {
6 | beforeEach(() => TestBed.configureTestingModule({}));
7 |
8 | it('should be created', () => {
9 | const service: TokenService = TestBed.get(TokenService);
10 | expect(service).toBeTruthy();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/front-end/src/app/token.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | @Injectable({
4 | providedIn: 'root'
5 | })
6 | export class TokenService {
7 | token: string;
8 | username: string;
9 | created: string;
10 | secret: string;
11 | wsseToken: string;
12 |
13 | constructor() { }
14 |
15 | hasAuthorizationToken(): boolean {
16 | const hasToken = !!this.token;
17 |
18 | return hasToken;
19 | }
20 |
21 | getAuthorizationToken(): string {
22 | // Generate a new token with new nonce each time otherwise it's a replay attack
23 | const token = localStorage.getItem('access_token');
24 | this.token = token;
25 | return this.token;
26 | }
27 |
28 | setAuthorizationToken(token: string) {
29 | // Save static parts of the token
30 | this.token = token;
31 | localStorage.setItem('access_token', this.token);
32 | }
33 |
34 | cleanAuthorizationToken() {
35 | // Clean token informations
36 | this.token = null;
37 | localStorage.removeItem('access_token');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/front-end/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/front-end/src/assets/.gitkeep
--------------------------------------------------------------------------------
/front-end/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | server: 'http://0.0.0.0:8000',
3 | production: true
4 | };
5 |
--------------------------------------------------------------------------------
/front-end/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | server: 'http://0.0.0.0:8000',
7 | production: false
8 | };
9 |
10 | /*
11 | * For easier debugging in development mode, you can import the following file
12 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
13 | *
14 | * This import should be commented out in production mode because it will have a negative impact
15 | * on performance if an error is thrown.
16 | */
17 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
18 |
--------------------------------------------------------------------------------
/front-end/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Acrecio/angular-symfony/df1f6f0785f32ee9037f63fb0e6cc7559b5760f8/front-end/src/favicon.ico
--------------------------------------------------------------------------------
/front-end/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Angular Symfony
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/front-end/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic()
12 | .bootstrapModule(AppModule)
13 | .catch(err => console.error(err));
14 |
--------------------------------------------------------------------------------
/front-end/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 | /***************************************************************************************************
61 | * APPLICATION IMPORTS
62 | */
63 |
--------------------------------------------------------------------------------
/front-end/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/front-end/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting()
16 | );
17 | // Then we find all the tests.
18 | const context = require.context('./', true, /\.spec\.ts$/);
19 | // And load the modules.
20 | context.keys().map(context);
21 |
--------------------------------------------------------------------------------
/front-end/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/app",
5 | "types": [
6 | "node"
7 | ]
8 | },
9 | "files": [
10 | "src/main.ts",
11 | "src/polyfills.ts"
12 | ],
13 | "include": [
14 | "src/**/*.ts"
15 | ],
16 | "exclude": [
17 | "src/test.ts",
18 | "src/**/*.spec.ts"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/front-end/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "downlevelIteration": true,
9 | "experimentalDecorators": true,
10 | "module": "esnext",
11 | "moduleResolution": "node",
12 | "importHelpers": true,
13 | "target": "es2015",
14 | "plugins": [
15 | {
16 | "name": "typescript-tslint-plugin"
17 | }
18 | ],
19 | "typeRoots": [
20 | "node_modules/@types"
21 | ],
22 | "lib": [
23 | "es2018",
24 | "dom"
25 | ]
26 | },
27 | "exclude": [
28 | "node_modules"
29 | ],
30 | "angularCompilerOptions": {
31 | "fullTemplateTypeCheck": true,
32 | "strictInjectionParameters": true
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/front-end/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/front-end/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rules": {
4 | "array-type": false,
5 | "arrow-parens": false,
6 | "deprecation": {
7 | "severity": "warning"
8 | },
9 | "component-class-suffix": true,
10 | "contextual-lifecycle": true,
11 | "directive-class-suffix": true,
12 | "directive-selector": [
13 | true,
14 | "attribute",
15 | "app",
16 | "camelCase"
17 | ],
18 | "component-selector": [
19 | true,
20 | "element",
21 | "app",
22 | "kebab-case"
23 | ],
24 | "import-blacklist": [
25 | true,
26 | "rxjs/Rx"
27 | ],
28 | "interface-name": false,
29 | "max-classes-per-file": false,
30 | "max-line-length": [
31 | true,
32 | 140
33 | ],
34 | "member-access": false,
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-consecutive-blank-lines": false,
47 | "no-console": [
48 | true,
49 | "debug",
50 | "info",
51 | "time",
52 | "timeEnd",
53 | "trace"
54 | ],
55 | "no-empty": false,
56 | "no-inferrable-types": [
57 | true,
58 | "ignore-params"
59 | ],
60 | "no-non-null-assertion": true,
61 | "no-redundant-jsdoc": true,
62 | "no-switch-case-fall-through": true,
63 | "no-var-requires": false,
64 | "object-literal-key-quotes": [
65 | true,
66 | "as-needed"
67 | ],
68 | "object-literal-sort-keys": false,
69 | "ordered-imports": false,
70 | "quotemark": [
71 | true,
72 | "single"
73 | ],
74 | "trailing-comma": false,
75 | "no-conflicting-lifecycle": true,
76 | "no-host-metadata-property": true,
77 | "no-input-rename": true,
78 | "no-inputs-metadata-property": true,
79 | "no-output-native": true,
80 | "no-output-on-prefix": true,
81 | "no-output-rename": true,
82 | "no-outputs-metadata-property": true,
83 | "template-banana-in-box": true,
84 | "template-no-negated-async": true,
85 | "use-lifecycle-interface": true,
86 | "use-pipe-transform-interface": true
87 | },
88 | "rulesDirectory": [
89 | "codelyzer"
90 | ]
91 | }
--------------------------------------------------------------------------------