diff --git a/Makefile b/Makefile
index 43a071c..a4e7cdd 100644
--- a/Makefile
+++ b/Makefile
@@ -8,4 +8,7 @@ backend-shell:
docker-compose exec backend /bin/bash
frontend-shell:
- docker-compose exec frontend /bin/bash
\ No newline at end of file
+ docker-compose exec frontend /bin/bash
+
+database-mysql:
+ docker-compose exec database mysql --default-character-set=utf8 -uroot -proot logo
\ No newline at end of file
diff --git a/README.md b/README.md
index e13277c..a9de07c 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@ Squelette applicatif React/Symfony 4 pour la formation React personnalisée Logo
- [Docker](https://docs.docker.com/install/)
- [Docker Compose](https://docs.docker.com/compose/install/)
-```
+```bash
git clone https://forge.cadoles.com/wpetit/react-logo.git
cd react-logo
-docker-compose up
+make up # ou docker-compose up --build
```
Une fois la procédure d'initialisation terminée, les différentes parties de l'application devraient être disponibles aux adresses suivantes:
@@ -28,28 +28,32 @@ Une fois la procédure d'initialisation terminée, les différentes parties de l
Une fois l'application lancée, exécuter:
-```
-docker-compose exec backend /bin/bash
+```bash
+make backend-shell # ou docker-compose exec backend /bin/bash
```
#### Comment ouvrir un shell interactif dans le conteneur "frontend" ?
Une fois l'application lancée, exécuter:
-```
-docker-compose exec frontend /bin/bash
+```bash
+make frontend-shell # ou docker-compose exec frontend /bin/bash
```
#### Comment ouvrir une console MySQL ?
Une fois l'application lancée, exécuter:
-```
-docker-compose exec database mysql -uroot -proot
+```bash
+make database-mysql # ou docker-compose exec database mysql -uroot -proot logo
```
### Comment réinitialiser l'environnement ?
+```bash
+make down # ou docker-compose down -v
```
-docker-compose down -v
-```
+
+## Cahier des charges
+
+- [Application de suivi des demandes clients](./misc/projects/ticketing_app.md)
diff --git a/backend/.env b/backend/.env
index 762e995..323147f 100644
--- a/backend/.env
+++ b/backend/.env
@@ -27,3 +27,7 @@ APP_SECRET=bc3856916a3206bf0b23356f46c5cf7d
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7
###< doctrine/doctrine-bundle ###
+
+###> nelmio/cors-bundle ###
+CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$
+###< nelmio/cors-bundle ###
diff --git a/backend/composer.json b/backend/composer.json
index d872882..5d6f65b 100644
--- a/backend/composer.json
+++ b/backend/composer.json
@@ -5,15 +5,19 @@
"php": "^7.1.3",
"ext-ctype": "*",
"ext-iconv": "*",
+ "nelmio/cors-bundle": "^2.0",
+ "sensio/framework-extra-bundle": "^5.5",
"symfony/console": "4.4.*",
"symfony/dotenv": "4.4.*",
"symfony/flex": "^1.3.1",
"symfony/framework-bundle": "4.4.*",
+ "symfony/inflector": "4.4.*",
"symfony/orm-pack": "^1.0",
"symfony/security-bundle": "4.4.*",
"symfony/yaml": "4.4.*"
},
"require-dev": {
+ "doctrine/doctrine-fixtures-bundle": "^3.3",
"symfony/maker-bundle": "^1.14",
"symfony/web-server-bundle": "4.4.*"
},
diff --git a/backend/composer.lock b/backend/composer.lock
index f4c0ac9..a311122 100644
--- a/backend/composer.lock
+++ b/backend/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "6421c1affbb7f7322a6499bde9164df1",
+ "content-hash": "b8a24c5421258bb04d461c7dd0498820",
"packages": [
{
"name": "doctrine/annotations",
@@ -1369,6 +1369,63 @@
],
"time": "2020-01-07T22:58:31+00:00"
},
+ {
+ "name": "nelmio/cors-bundle",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nelmio/NelmioCorsBundle.git",
+ "reference": "9683e6d30d000ef998919261329d825de7c53499"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/9683e6d30d000ef998919261329d825de7c53499",
+ "reference": "9683e6d30d000ef998919261329d825de7c53499",
+ "shasum": ""
+ },
+ "require": {
+ "symfony/framework-bundle": "^4.3 || ^5.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^1.2",
+ "symfony/phpunit-bridge": "^4.3 || ^5.0"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Nelmio\\CorsBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nelmio",
+ "homepage": "http://nelm.io"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://github.com/nelmio/NelmioCorsBundle/contributors"
+ }
+ ],
+ "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony application",
+ "keywords": [
+ "api",
+ "cors",
+ "crossdomain"
+ ],
+ "time": "2019-11-15T08:54:08+00:00"
+ },
{
"name": "ocramius/package-versions",
"version": "1.5.1",
@@ -1639,6 +1696,84 @@
],
"time": "2019-11-01T11:05:21+00:00"
},
+ {
+ "name": "sensio/framework-extra-bundle",
+ "version": "v5.5.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git",
+ "reference": "98f0807137b13d0acfdf3c255a731516e97015de"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/98f0807137b13d0acfdf3c255a731516e97015de",
+ "reference": "98f0807137b13d0acfdf3c255a731516e97015de",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/annotations": "^1.0",
+ "php": ">=7.1.3",
+ "symfony/config": "^4.3|^5.0",
+ "symfony/dependency-injection": "^4.3|^5.0",
+ "symfony/framework-bundle": "^4.3|^5.0",
+ "symfony/http-kernel": "^4.3|^5.0"
+ },
+ "conflict": {
+ "doctrine/doctrine-cache-bundle": "<1.3.1"
+ },
+ "require-dev": {
+ "doctrine/doctrine-bundle": "^1.11|^2.0",
+ "doctrine/orm": "^2.5",
+ "nyholm/psr7": "^1.1",
+ "symfony/browser-kit": "^4.3|^5.0",
+ "symfony/dom-crawler": "^4.3|^5.0",
+ "symfony/expression-language": "^4.3|^5.0",
+ "symfony/finder": "^4.3|^5.0",
+ "symfony/monolog-bridge": "^4.0|^5.0",
+ "symfony/monolog-bundle": "^3.2",
+ "symfony/phpunit-bridge": "^4.3.5|^5.0",
+ "symfony/psr-http-message-bridge": "^1.1",
+ "symfony/security-bundle": "^4.3|^5.0",
+ "symfony/twig-bundle": "^4.3|^5.0",
+ "symfony/yaml": "^4.3|^5.0",
+ "twig/twig": "^1.34|^2.4|^3.0"
+ },
+ "suggest": {
+ "symfony/expression-language": "",
+ "symfony/psr-http-message-bridge": "To use the PSR-7 converters",
+ "symfony/security-bundle": ""
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Sensio\\Bundle\\FrameworkExtraBundle\\": "src/"
+ },
+ "exclude-from-classmap": [
+ "/tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "This bundle provides a way to configure your controllers with annotations",
+ "keywords": [
+ "annotations",
+ "controllers"
+ ],
+ "time": "2019-12-27T08:57:19+00:00"
+ },
{
"name": "symfony/cache",
"version": "v4.4.4",
@@ -4017,6 +4152,137 @@
}
],
"packages-dev": [
+ {
+ "name": "doctrine/data-fixtures",
+ "version": "1.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/data-fixtures.git",
+ "reference": "39e9777c9089351a468f780b01cffa3cb0a42907"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/39e9777c9089351a468f780b01cffa3cb0a42907",
+ "reference": "39e9777c9089351a468f780b01cffa3cb0a42907",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/common": "^2.11",
+ "doctrine/persistence": "^1.3.3",
+ "php": "^7.2"
+ },
+ "conflict": {
+ "doctrine/phpcr-odm": "<1.3.0"
+ },
+ "require-dev": {
+ "alcaeus/mongo-php-adapter": "^1.1",
+ "doctrine/coding-standard": "^6.0",
+ "doctrine/dbal": "^2.5.4",
+ "doctrine/mongodb-odm": "^1.3.0",
+ "doctrine/orm": "^2.7.0",
+ "phpunit/phpunit": "^7.0"
+ },
+ "suggest": {
+ "alcaeus/mongo-php-adapter": "For using MongoDB ODM with PHP 7",
+ "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures",
+ "doctrine/orm": "For loading ORM fixtures",
+ "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Common\\DataFixtures\\": "lib/Doctrine/Common/DataFixtures"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jonathan Wage",
+ "email": "jonwage@gmail.com"
+ }
+ ],
+ "description": "Data Fixtures for all Doctrine Object Managers",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "database"
+ ],
+ "time": "2020-01-17T11:11:28+00:00"
+ },
+ {
+ "name": "doctrine/doctrine-fixtures-bundle",
+ "version": "3.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/DoctrineFixturesBundle.git",
+ "reference": "8f07fcfdac7f3591f3c4bf13a50cbae05f65ed70"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/8f07fcfdac7f3591f3c4bf13a50cbae05f65ed70",
+ "reference": "8f07fcfdac7f3591f3c4bf13a50cbae05f65ed70",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/data-fixtures": "^1.3",
+ "doctrine/doctrine-bundle": "^1.11|^2.0",
+ "doctrine/orm": "^2.6.0",
+ "php": "^7.1",
+ "symfony/config": "^3.4|^4.3|^5.0",
+ "symfony/console": "^3.4|^4.3|^5.0",
+ "symfony/dependency-injection": "^3.4|^4.3|^5.0",
+ "symfony/doctrine-bridge": "^3.4|^4.1|^5.0",
+ "symfony/http-kernel": "^3.4|^4.3|^5.0"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^6.0",
+ "phpunit/phpunit": "^7.4",
+ "symfony/phpunit-bridge": "^4.1|^5.0"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Bundle\\FixturesBundle\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Doctrine Project",
+ "homepage": "http://www.doctrine-project.org"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony DoctrineFixturesBundle",
+ "homepage": "http://www.doctrine-project.org",
+ "keywords": [
+ "Fixture",
+ "persistence"
+ ],
+ "time": "2019-11-13T15:46:58+00:00"
+ },
{
"name": "nikic/php-parser",
"version": "v4.3.0",
diff --git a/backend/config/bundles.php b/backend/config/bundles.php
index 119166a..951eca4 100644
--- a/backend/config/bundles.php
+++ b/backend/config/bundles.php
@@ -7,4 +7,7 @@ return [
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
+ Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
+ Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
+ Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
];
diff --git a/backend/config/packages/nelmio_cors.yaml b/backend/config/packages/nelmio_cors.yaml
new file mode 100644
index 0000000..c766508
--- /dev/null
+++ b/backend/config/packages/nelmio_cors.yaml
@@ -0,0 +1,10 @@
+nelmio_cors:
+ defaults:
+ origin_regex: true
+ allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
+ allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
+ allow_headers: ['Content-Type', 'Authorization']
+ expose_headers: ['Link']
+ max_age: 3600
+ paths:
+ '^/': null
diff --git a/backend/config/packages/security.yaml b/backend/config/packages/security.yaml
index ce69ba7..a7ea7e3 100644
--- a/backend/config/packages/security.yaml
+++ b/backend/config/packages/security.yaml
@@ -1,13 +1,26 @@
security:
+ encoders:
+ App\Entity\User:
+ algorithm: auto
+
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
- in_memory: { memory: null }
+ # used to reload user from session & other features (e.g. switch_user)
+ app_user_provider:
+ entity:
+ class: App\Entity\User
+ property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
- anonymous: lazy
+ anonymous: ~
+ json_login:
+ check_path: /api/v1/login
+ logout:
+ path: /api/v1/logout
+ target: /api/v1
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
@@ -18,5 +31,3 @@ security:
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- # - { path: ^/admin, roles: ROLE_ADMIN }
- # - { path: ^/profile, roles: ROLE_USER }
diff --git a/backend/config/packages/sensio_framework_extra.yaml b/backend/config/packages/sensio_framework_extra.yaml
new file mode 100644
index 0000000..1821ccc
--- /dev/null
+++ b/backend/config/packages/sensio_framework_extra.yaml
@@ -0,0 +1,3 @@
+sensio_framework_extra:
+ router:
+ annotations: false
diff --git a/backend/config/routes.yaml b/backend/config/routes.yaml
index d1523d3..781019b 100644
--- a/backend/config/routes.yaml
+++ b/backend/config/routes.yaml
@@ -2,29 +2,9 @@
# path: /
# controller: App\Controller\DefaultController::index
-app_home:
- path: /
- controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction
- defaults:
- path: /api/v1
- permanent: true
+login:
+ path: /api/v1/login
+ controller: App\Controller\SecurityController::login
-app_api_login:
- path: /api/v1/login
- methods: ['POST']
- controller: App\Controller\ApiController::login
-
-app_api_logout:
- path: /api/v1/logout
- methods: ['POST']
- controller: App\Controller\ApiController::logout
-
-app_api_show_info:
- path: /api/v1
- methods: ['GET']
- controller: App\Controller\ApiController::showVersionInfo
-
-app_api_list_users:
- path: /api/v1/users
- methods: ['GET']
- controller: App\Controller\ApiController::listUsers
+logout:
+ path: /api/v1/logout
\ No newline at end of file
diff --git a/backend/src/Controller/ApiController.php b/backend/src/Controller/ApiController.php
deleted file mode 100644
index a68c3c5..0000000
--- a/backend/src/Controller/ApiController.php
+++ /dev/null
@@ -1,33 +0,0 @@
- '1',
- ]);
- }
-
- public function listUsers()
- {
- return new JsonResponse([]);
- }
-}
\ No newline at end of file
diff --git a/backend/src/Controller/IndexController.php b/backend/src/Controller/IndexController.php
new file mode 100644
index 0000000..279476c
--- /dev/null
+++ b/backend/src/Controller/IndexController.php
@@ -0,0 +1,20 @@
+ '1',
+ ]);
+ }
+
+}
\ No newline at end of file
diff --git a/backend/src/Controller/RequestController.php b/backend/src/Controller/RequestController.php
new file mode 100644
index 0000000..23f3c5e
--- /dev/null
+++ b/backend/src/Controller/RequestController.php
@@ -0,0 +1,18 @@
+getUser();
+
+ return new DataResponse([
+ 'username' => $user->getUsername(),
+ 'roles' => $user->getRoles(),
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/backend/src/Controller/UserController.php b/backend/src/Controller/UserController.php
new file mode 100644
index 0000000..67c8e7d
--- /dev/null
+++ b/backend/src/Controller/UserController.php
@@ -0,0 +1,72 @@
+getUser();
+
+ return new DataResponse([
+ 'username' => $user->getUsername(),
+ 'roles' => $user->getRoles(),
+ ]);
+ }
+
+ /**
+ * @Route("/api/v1/users", name="api_v1_list_users", methods={"GET"})
+ * @IsGranted("ROLE_DEVELOPER")
+ */
+ public function listUsers()
+ {
+ /** @var array */
+ $users = $this->getDoctrine()
+ ->getRepository(User::class)
+ ->findAll()
+ ;
+
+ $results = [];
+ foreach($users as $u) {
+ $results[] = [
+ 'id' => $u->getId(),
+ 'username' => $u->getUsername(),
+ ];
+ }
+
+ return new DataResponse([
+ 'users' => $results,
+ ]);
+ }
+
+ /**
+ * @Route("/api/v1/users/{userId}", name="api_v1_get_user", methods={"GET"}, requirements={"userId"="\d+"})
+ * @IsGranted("ROLE_DEVELOPER")
+ */
+ public function showUser($userId)
+ {
+ /** @var User */
+ $user = $this->getDoctrine()
+ ->getRepository(User::class)
+ ->find($userId)
+ ;
+
+ return new DataResponse([
+ 'user' => [
+ 'id' => $user->getId(),
+ 'username' => $user->getUsername(),
+ ]
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/backend/src/DataFixtures/AppFixtures.php b/backend/src/DataFixtures/AppFixtures.php
new file mode 100644
index 0000000..fece475
--- /dev/null
+++ b/backend/src/DataFixtures/AppFixtures.php
@@ -0,0 +1,17 @@
+persist($product);
+
+ $manager->flush();
+ }
+}
diff --git a/backend/src/DataFixtures/RequestStatusFixtures.php b/backend/src/DataFixtures/RequestStatusFixtures.php
new file mode 100644
index 0000000..1d7a867
--- /dev/null
+++ b/backend/src/DataFixtures/RequestStatusFixtures.php
@@ -0,0 +1,29 @@
+setLabel($statusLabel);
+ $manager->persist($status);
+ }
+
+ $manager->flush();
+ }
+}
diff --git a/backend/src/DataFixtures/UserFixtures.php b/backend/src/DataFixtures/UserFixtures.php
new file mode 100644
index 0000000..0447c20
--- /dev/null
+++ b/backend/src/DataFixtures/UserFixtures.php
@@ -0,0 +1,55 @@
+passwordEncoder = $passwordEncoder;
+ }
+
+ public function load(ObjectManager $manager)
+ {
+ // On créait l'utilisateur client1 et client2
+ $client1 = new User();
+ $client1->setUsername('client1');
+ $client1->setPassword($this->passwordEncoder->encodePassword(
+ $client1,
+ 'client1'
+ ));
+ $client1->setRoles(['ROLE_CLIENT']);
+ $manager->persist($client1);
+
+ $client2 = new User();
+ $client2->setUsername('client2');
+ $client2->setPassword($this->passwordEncoder->encodePassword(
+ $client2,
+ 'client2'
+ ));
+ $client2->setRoles(['ROLE_CLIENT']);
+ $manager->persist($client2);
+
+ // On créait l'utilisateur dev1
+ $dev1 = new User();
+ $dev1->setUsername('dev1');
+ $dev1->setPassword($this->passwordEncoder->encodePassword(
+ $dev1,
+ 'dev1'
+ ));
+ $dev1->setRoles(['ROLE_DEVELOPER']);
+ $manager->persist($dev1);
+
+ $manager->flush();
+
+ }
+
+
+}
diff --git a/backend/src/Entity/Comment.php b/backend/src/Entity/Comment.php
new file mode 100644
index 0000000..13cc96f
--- /dev/null
+++ b/backend/src/Entity/Comment.php
@@ -0,0 +1,93 @@
+id;
+ }
+
+ public function getRequest(): ?Request
+ {
+ return $this->request;
+ }
+
+ public function setRequest(?Request $request): self
+ {
+ $this->request = $request;
+
+ return $this;
+ }
+
+ public function getCreatedAt(): ?\DateTimeInterface
+ {
+ return $this->createdAt;
+ }
+
+ public function setCreatedAt(\DateTimeInterface $createdAt): self
+ {
+ $this->createdAt = $createdAt;
+
+ return $this;
+ }
+
+ public function getAuthor(): ?User
+ {
+ return $this->author;
+ }
+
+ public function setAuthor(?User $author): self
+ {
+ $this->author = $author;
+
+ return $this;
+ }
+
+ public function getText(): ?string
+ {
+ return $this->text;
+ }
+
+ public function setText(string $text): self
+ {
+ $this->text = $text;
+
+ return $this;
+ }
+}
diff --git a/backend/src/Entity/Project.php b/backend/src/Entity/Project.php
new file mode 100644
index 0000000..725c7b2
--- /dev/null
+++ b/backend/src/Entity/Project.php
@@ -0,0 +1,115 @@
+request = new ArrayCollection();
+ $this->users = new ArrayCollection();
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ /**
+ * @return Collection|Request[]
+ */
+ public function getRequest(): Collection
+ {
+ return $this->request;
+ }
+
+ public function addRequest(Request $request): self
+ {
+ if (!$this->request->contains($request)) {
+ $this->request[] = $request;
+ $request->setProject($this);
+ }
+
+ return $this;
+ }
+
+ public function removeRequest(Request $request): self
+ {
+ if ($this->request->contains($request)) {
+ $this->request->removeElement($request);
+ // set the owning side to null (unless already changed)
+ if ($request->getProject() === $this) {
+ $request->setProject(null);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return Collection|User[]
+ */
+ public function getUsers(): Collection
+ {
+ return $this->users;
+ }
+
+ public function addUser(User $user): self
+ {
+ if (!$this->users->contains($user)) {
+ $this->users[] = $user;
+ }
+
+ return $this;
+ }
+
+ public function removeUser(User $user): self
+ {
+ if ($this->users->contains($user)) {
+ $this->users->removeElement($user);
+ }
+
+ return $this;
+ }
+
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ public function setName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+}
diff --git a/backend/src/Entity/Request.php b/backend/src/Entity/Request.php
new file mode 100644
index 0000000..c107f21
--- /dev/null
+++ b/backend/src/Entity/Request.php
@@ -0,0 +1,154 @@
+comments = new ArrayCollection();
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getTitle(): ?string
+ {
+ return $this->title;
+ }
+
+ public function setTitle(string $title): self
+ {
+ $this->title = $title;
+
+ return $this;
+ }
+
+ public function getAuthor(): ?User
+ {
+ return $this->author;
+ }
+
+ public function setAuthor(?User $author): self
+ {
+ $this->author = $author;
+
+ return $this;
+ }
+
+ public function getCreatedAt(): ?\DateTimeInterface
+ {
+ return $this->createdAt;
+ }
+
+ public function setCreatedAt(\DateTimeInterface $createdAt): self
+ {
+ $this->createdAt = $createdAt;
+
+ return $this;
+ }
+
+ public function getProject(): ?Project
+ {
+ return $this->project;
+ }
+
+ public function setProject(?Project $project): self
+ {
+ $this->project = $project;
+
+ return $this;
+ }
+
+ /**
+ * @return Collection|Comment[]
+ */
+ public function getComments(): Collection
+ {
+ return $this->comments;
+ }
+
+ public function addComment(Comment $comment): self
+ {
+ if (!$this->comments->contains($comment)) {
+ $this->comments[] = $comment;
+ $comment->setRequest($this);
+ }
+
+ return $this;
+ }
+
+ public function removeComment(Comment $comment): self
+ {
+ if ($this->comments->contains($comment)) {
+ $this->comments->removeElement($comment);
+ // set the owning side to null (unless already changed)
+ if ($comment->getRequest() === $this) {
+ $comment->setRequest(null);
+ }
+ }
+
+ return $this;
+ }
+
+ public function getStatus(): ?RequestStatus
+ {
+ return $this->status;
+ }
+
+ public function setStatus(?RequestStatus $status): self
+ {
+ $this->status = $status;
+
+ return $this;
+ }
+}
diff --git a/backend/src/Entity/RequestStatus.php b/backend/src/Entity/RequestStatus.php
new file mode 100644
index 0000000..803adc5
--- /dev/null
+++ b/backend/src/Entity/RequestStatus.php
@@ -0,0 +1,83 @@
+requests = new ArrayCollection();
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getLabel(): ?string
+ {
+ return $this->label;
+ }
+
+ public function setLabel(string $label): self
+ {
+ $this->label = $label;
+
+ return $this;
+ }
+
+ /**
+ * @return Collection|Request[]
+ */
+ public function getRequests(): Collection
+ {
+ return $this->requests;
+ }
+
+ public function addRequest(Request $request): self
+ {
+ if (!$this->requests->contains($request)) {
+ $this->requests[] = $request;
+ $request->setStatus($this);
+ }
+
+ return $this;
+ }
+
+ public function removeRequest(Request $request): self
+ {
+ if ($this->requests->contains($request)) {
+ $this->requests->removeElement($request);
+ // set the owning side to null (unless already changed)
+ if ($request->getStatus() === $this) {
+ $request->setStatus(null);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/backend/src/Entity/User.php b/backend/src/Entity/User.php
new file mode 100644
index 0000000..8ffbdc6
--- /dev/null
+++ b/backend/src/Entity/User.php
@@ -0,0 +1,222 @@
+requests = new ArrayCollection();
+ $this->projects = new ArrayCollection();
+ $this->comments = new ArrayCollection();
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ /**
+ * A visual identifier that represents this user.
+ *
+ * @see UserInterface
+ */
+ public function getUsername(): string
+ {
+ return (string) $this->username;
+ }
+
+ public function setUsername(string $username): self
+ {
+ $this->username = $username;
+
+ return $this;
+ }
+
+ /**
+ * @see UserInterface
+ */
+ public function getRoles(): array
+ {
+ $roles = $this->roles;
+ // guarantee every user at least has ROLE_USER
+ $roles[] = 'ROLE_USER';
+
+ return array_unique($roles);
+ }
+
+ public function setRoles(array $roles): self
+ {
+ $this->roles = $roles;
+
+ return $this;
+ }
+
+ /**
+ * @see UserInterface
+ */
+ public function getPassword(): string
+ {
+ return (string) $this->password;
+ }
+
+ public function setPassword(string $password): self
+ {
+ $this->password = $password;
+
+ return $this;
+ }
+
+ /**
+ * @see UserInterface
+ */
+ public function getSalt()
+ {
+ // not needed when using the "bcrypt" algorithm in security.yaml
+ }
+
+ /**
+ * @see UserInterface
+ */
+ public function eraseCredentials()
+ {
+ // If you store any temporary, sensitive data on the user, clear it here
+ // $this->plainPassword = null;
+ }
+
+ /**
+ * @return Collection|Request[]
+ */
+ public function getRequests(): Collection
+ {
+ return $this->requests;
+ }
+
+ public function addRequest(Request $request): self
+ {
+ if (!$this->requests->contains($request)) {
+ $this->requests[] = $request;
+ $request->setAuthor($this);
+ }
+
+ return $this;
+ }
+
+ public function removeRequest(Request $request): self
+ {
+ if ($this->requests->contains($request)) {
+ $this->requests->removeElement($request);
+ // set the owning side to null (unless already changed)
+ if ($request->getAuthor() === $this) {
+ $request->setAuthor(null);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return Collection|Project[]
+ */
+ public function getProjects(): Collection
+ {
+ return $this->projects;
+ }
+
+ public function addProject(Project $project): self
+ {
+ if (!$this->projects->contains($project)) {
+ $this->projects[] = $project;
+ $project->addUser($this);
+ }
+
+ return $this;
+ }
+
+ public function removeProject(Project $project): self
+ {
+ if ($this->projects->contains($project)) {
+ $this->projects->removeElement($project);
+ $project->removeUser($this);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return Collection|Comment[]
+ */
+ public function getComments(): Collection
+ {
+ return $this->comments;
+ }
+
+ public function addComment(Comment $comment): self
+ {
+ if (!$this->comments->contains($comment)) {
+ $this->comments[] = $comment;
+ $comment->setAuthor($this);
+ }
+
+ return $this;
+ }
+
+ public function removeComment(Comment $comment): self
+ {
+ if ($this->comments->contains($comment)) {
+ $this->comments->removeElement($comment);
+ // set the owning side to null (unless already changed)
+ if ($comment->getAuthor() === $this) {
+ $comment->setAuthor(null);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/backend/src/Http/DataResponse.php b/backend/src/Http/DataResponse.php
new file mode 100644
index 0000000..e52dd0d
--- /dev/null
+++ b/backend/src/Http/DataResponse.php
@@ -0,0 +1,16 @@
+ $data],
+ $status,
+ $headers,
+ $json,
+ );
+ }
+}
\ No newline at end of file
diff --git a/backend/src/Http/ErrorResponse.php b/backend/src/Http/ErrorResponse.php
new file mode 100644
index 0000000..0d6a53c
--- /dev/null
+++ b/backend/src/Http/ErrorResponse.php
@@ -0,0 +1,22 @@
+ [
+ 'code' => $code,
+ 'message' => $message,
+ 'data' => $data,
+ ],
+ ],
+ $status,
+ $headers,
+ $json,
+ );
+ }
+}
\ No newline at end of file
diff --git a/backend/src/Migrations/Version20200217203938.php b/backend/src/Migrations/Version20200217203938.php
new file mode 100644
index 0000000..e179c33
--- /dev/null
+++ b/backend/src/Migrations/Version20200217203938.php
@@ -0,0 +1,57 @@
+abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
+
+ $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(180) NOT NULL, roles LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_8D93D649F85E0677 (username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE request_status (id INT AUTO_INCREMENT NOT NULL, label VARCHAR(64) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE comment (id INT AUTO_INCREMENT NOT NULL, request_id INT NOT NULL, author_id INT NOT NULL, created_at DATETIME NOT NULL, text LONGTEXT NOT NULL, INDEX IDX_9474526C427EB8A5 (request_id), INDEX IDX_9474526CF675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE project (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE project_user (project_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_B4021E51166D1F9C (project_id), INDEX IDX_B4021E51A76ED395 (user_id), PRIMARY KEY(project_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE request (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, project_id INT NOT NULL, title VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, INDEX IDX_3B978F9FF675F31B (author_id), INDEX IDX_3B978F9F166D1F9C (project_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526C427EB8A5 FOREIGN KEY (request_id) REFERENCES request (id)');
+ $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526CF675F31B FOREIGN KEY (author_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE project_user ADD CONSTRAINT FK_B4021E51166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE');
+ $this->addSql('ALTER TABLE project_user ADD CONSTRAINT FK_B4021E51A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
+ $this->addSql('ALTER TABLE request ADD CONSTRAINT FK_3B978F9FF675F31B FOREIGN KEY (author_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE request ADD CONSTRAINT FK_3B978F9F166D1F9C FOREIGN KEY (project_id) REFERENCES project (id)');
+ }
+
+ public function down(Schema $schema) : void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
+
+ $this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526CF675F31B');
+ $this->addSql('ALTER TABLE project_user DROP FOREIGN KEY FK_B4021E51A76ED395');
+ $this->addSql('ALTER TABLE request DROP FOREIGN KEY FK_3B978F9FF675F31B');
+ $this->addSql('ALTER TABLE project_user DROP FOREIGN KEY FK_B4021E51166D1F9C');
+ $this->addSql('ALTER TABLE request DROP FOREIGN KEY FK_3B978F9F166D1F9C');
+ $this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526C427EB8A5');
+ $this->addSql('DROP TABLE user');
+ $this->addSql('DROP TABLE request_status');
+ $this->addSql('DROP TABLE comment');
+ $this->addSql('DROP TABLE project');
+ $this->addSql('DROP TABLE project_user');
+ $this->addSql('DROP TABLE request');
+ }
+}
diff --git a/backend/src/Migrations/Version20200217211954.php b/backend/src/Migrations/Version20200217211954.php
new file mode 100644
index 0000000..1a72a3b
--- /dev/null
+++ b/backend/src/Migrations/Version20200217211954.php
@@ -0,0 +1,39 @@
+abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
+
+ $this->addSql('ALTER TABLE request ADD status_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE request ADD CONSTRAINT FK_3B978F9F6BF700BD FOREIGN KEY (status_id) REFERENCES request_status (id)');
+ $this->addSql('CREATE INDEX IDX_3B978F9F6BF700BD ON request (status_id)');
+ }
+
+ public function down(Schema $schema) : void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
+
+ $this->addSql('ALTER TABLE request DROP FOREIGN KEY FK_3B978F9F6BF700BD');
+ $this->addSql('DROP INDEX IDX_3B978F9F6BF700BD ON request');
+ $this->addSql('ALTER TABLE request DROP status_id');
+ }
+}
diff --git a/backend/src/Repository/CommentRepository.php b/backend/src/Repository/CommentRepository.php
new file mode 100644
index 0000000..cddf55d
--- /dev/null
+++ b/backend/src/Repository/CommentRepository.php
@@ -0,0 +1,50 @@
+createQueryBuilder('c')
+ ->andWhere('c.exampleField = :val')
+ ->setParameter('val', $value)
+ ->orderBy('c.id', 'ASC')
+ ->setMaxResults(10)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+ */
+
+ /*
+ public function findOneBySomeField($value): ?Comment
+ {
+ return $this->createQueryBuilder('c')
+ ->andWhere('c.exampleField = :val')
+ ->setParameter('val', $value)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+ */
+}
diff --git a/backend/src/Repository/ProjectRepository.php b/backend/src/Repository/ProjectRepository.php
new file mode 100644
index 0000000..50da37f
--- /dev/null
+++ b/backend/src/Repository/ProjectRepository.php
@@ -0,0 +1,50 @@
+createQueryBuilder('p')
+ ->andWhere('p.exampleField = :val')
+ ->setParameter('val', $value)
+ ->orderBy('p.id', 'ASC')
+ ->setMaxResults(10)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+ */
+
+ /*
+ public function findOneBySomeField($value): ?Project
+ {
+ return $this->createQueryBuilder('p')
+ ->andWhere('p.exampleField = :val')
+ ->setParameter('val', $value)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+ */
+}
diff --git a/backend/src/Repository/RequestRepository.php b/backend/src/Repository/RequestRepository.php
new file mode 100644
index 0000000..6047434
--- /dev/null
+++ b/backend/src/Repository/RequestRepository.php
@@ -0,0 +1,50 @@
+createQueryBuilder('r')
+ ->andWhere('r.exampleField = :val')
+ ->setParameter('val', $value)
+ ->orderBy('r.id', 'ASC')
+ ->setMaxResults(10)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+ */
+
+ /*
+ public function findOneBySomeField($value): ?Request
+ {
+ return $this->createQueryBuilder('r')
+ ->andWhere('r.exampleField = :val')
+ ->setParameter('val', $value)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+ */
+}
diff --git a/backend/src/Repository/RequestStatusRepository.php b/backend/src/Repository/RequestStatusRepository.php
new file mode 100644
index 0000000..be45c5e
--- /dev/null
+++ b/backend/src/Repository/RequestStatusRepository.php
@@ -0,0 +1,50 @@
+createQueryBuilder('r')
+ ->andWhere('r.exampleField = :val')
+ ->setParameter('val', $value)
+ ->orderBy('r.id', 'ASC')
+ ->setMaxResults(10)
+ ->getQuery()
+ ->getResult()
+ ;
+ }
+ */
+
+ /*
+ public function findOneBySomeField($value): ?RequestStatus
+ {
+ return $this->createQueryBuilder('r')
+ ->andWhere('r.exampleField = :val')
+ ->setParameter('val', $value)
+ ->getQuery()
+ ->getOneOrNullResult()
+ ;
+ }
+ */
+}
diff --git a/backend/src/Repository/UserRepository.php b/backend/src/Repository/UserRepository.php
new file mode 100644
index 0000000..b2bdfd6
--- /dev/null
+++ b/backend/src/Repository/UserRepository.php
@@ -0,0 +1,39 @@
+setPassword($newEncodedPassword);
+ $this->_em->persist($user);
+ $this->_em->flush();
+ }
+
+}
diff --git a/backend/symfony.lock b/backend/symfony.lock
index d455b1c..aeacb52 100644
--- a/backend/symfony.lock
+++ b/backend/symfony.lock
@@ -20,6 +20,9 @@
"doctrine/common": {
"version": "2.12.0"
},
+ "doctrine/data-fixtures": {
+ "version": "1.4.2"
+ },
"doctrine/dbal": {
"version": "v2.10.1"
},
@@ -38,6 +41,18 @@
"src/Repository/.gitignore"
]
},
+ "doctrine/doctrine-fixtures-bundle": {
+ "version": "3.0",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "master",
+ "version": "3.0",
+ "ref": "fc52d86631a6dfd9fdf3381d0b7e3df2069e51b3"
+ },
+ "files": [
+ "src/DataFixtures/AppFixtures.php"
+ ]
+ },
"doctrine/doctrine-migrations-bundle": {
"version": "1.2",
"recipe": {
@@ -87,6 +102,18 @@
"laminas/laminas-zendframework-bridge": {
"version": "1.0.1"
},
+ "nelmio/cors-bundle": {
+ "version": "1.5",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "master",
+ "version": "1.5",
+ "ref": "6388de23860284db9acce0a7a5d9d13153bcb571"
+ },
+ "files": [
+ "config/packages/nelmio_cors.yaml"
+ ]
+ },
"nikic/php-parser": {
"version": "v4.3.0"
},
@@ -108,6 +135,18 @@
"psr/log": {
"version": "1.1.2"
},
+ "sensio/framework-extra-bundle": {
+ "version": "5.2",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "master",
+ "version": "5.2",
+ "ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b"
+ },
+ "files": [
+ "config/packages/sensio_framework_extra.yaml"
+ ]
+ },
"symfony/cache": {
"version": "v4.4.4"
},
diff --git a/docker-compose.yml b/docker-compose.yml
index fafa672..56890ff 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -9,6 +9,9 @@ services:
MYSQL_PASSWORD: logo
ports:
- 3306:3306
+ command:
+ - "--character-set-server=utf8mb4"
+ - "--collation-server=utf8mb4_unicode_ci"
volumes:
- db_data:/var/lib/mysql
diff --git a/frontend/src/actions/.gitkeep b/frontend/src/actions/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/actions/chat.js b/frontend/src/actions/chat.js
deleted file mode 100644
index c2b5742..0000000
--- a/frontend/src/actions/chat.js
+++ /dev/null
@@ -1,20 +0,0 @@
-export const SEND_MESSAGE = 'SEND_MESSAGE'
-export const SEND_MESSAGE_SUCCESS = 'SEND_MESSAGE_SUCCESS';
-export const SEND_MESSAGE_FAILURE = 'SEND_MESSAGE_FAILURE';
-
-export function sendMessage (channel, text) {
- return { type: SEND_MESSAGE, channel, text }
-}
-
-export const FETCH_MESSAGES = 'FETCH_MESSAGES'
-export const FETCH_MESSAGES_SUCCESS = 'FETCH_MESSAGES_SUCCESS';
-export const FETCH_MESSAGES_FAILURE = 'FETCH_MESSAGES_FAILURE';
-
-export function fetchMessages (channel) {
- return { type: FETCH_MESSAGES, channel }
-}
-
-export const STREAM_EVENTS = 'STREAM_EVENTS'
-export function streamEvents (channel) {
- return { type: STREAM_EVENTS, channel }
-}
diff --git a/frontend/src/actions/login.js b/frontend/src/actions/login.js
deleted file mode 100644
index 3718de5..0000000
--- a/frontend/src/actions/login.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export const LOGIN = 'LOGIN'
-export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
-export const LOGIN_FAILURE = 'LOGIN_FAILURE';
-
-export function login (username, password) {
- return { type: LOGIN, username, password }
-}
diff --git a/frontend/src/actions/products.js b/frontend/src/actions/products.js
deleted file mode 100644
index c915260..0000000
--- a/frontend/src/actions/products.js
+++ /dev/null
@@ -1,11 +0,0 @@
-export const ADD_PRODUCT = 'ADD_PRODUCT'
-
-export function addProduct (name, price) {
- return {type: ADD_PRODUCT, product: {name, price}}
-}
-
-export const REMOVE_PRODUCT = 'REMOVE_PRODUCT'
-
-export function removeProduct (name) {
- return {type: REMOVE_PRODUCT, productName: name}
-}
\ No newline at end of file
diff --git a/frontend/src/app.js b/frontend/src/app.js
index 4a3fd6c..886df5a 100644
--- a/frontend/src/app.js
+++ b/frontend/src/app.js
@@ -1,12 +1,8 @@
-
import { Component, Fragment } from 'react'
import { hot } from 'react-hot-loader'
import { HashRouter } from 'react-router-dom' // ou BrowserRouter
import { Route, Switch, Redirect } from 'react-router'
-import LoginPage from './pages/login';
-import ChatPage from './pages/chat';
-
-require('bulma/css/bulma.min.css')
+import HomePage from './pages/home';
class App extends Component {
render () {
@@ -14,10 +10,8 @@ class App extends Component {