Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vendor/
node_modules/
*.clpprj
68 changes: 41 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
# Desafio Celso Lisboa para FullStack

### Cenário

**Como** Coordenador Acadêmico de uma Instituição de Ensino
**Eu preciso** realizar a gestão dos cursos oferecidos pela Instituição, com seus respectivos professores, salas e horários
**Para** que o setor de Marketing possa vender os cursos online.

### Segue instruções para realizar o desafio

1. Faça um fork deste repositório.
2. Baseado no cenário acima, modele e crie o esquema do banco de dados para armazenar as informações normalizadas.
* Comite a imagem em jpg ou png do DER e o script do DDL.
3. Desenvolva uma API REST para realizar as operações necessárias com o banco de dados criado.
4. Baseado nas imagens `wireframe/1-login-mobile.png` e `wireframe/2-login-desktop.png`, crie a tela de login da aplicação.
* Considere apenas uma validação simples por e-mail e senha.
* Não existe a necessidade de CRUD de usuário, recuperação de senha ou outra operação mais complexa.
5. Baseado nas imagens `wireframe/3-cursos-mobile.png` e `wireframe/4-cursos-desktop.png`, crie a tela de visualização e deleção de cursos.
* Deve conter as informações de horário, professor e sala.
6. Baseado nas imagens `wireframe/5-detalhe-mobile.png` e `wireframe/6-detalhe-desktop.png`, crie a tela de criação e alteração de cursos.
* Os campos de professor e sala deverão ser um multi-select.
* Não existe a necessidade de CRUD de professor e sala.
7. Realizar um Pull Request para este repositório, com instruções necessárias para instalação e instânciação dos sistemas.

### O que será avaliado

1. Fidelidade às instruções e ao cenário.
2. Clean Code e boas práticas.
3. Boas práticas de versionamento.
### Instalação

1. Na pasta **/scripts/SQL/**, você encontrará o arquivo **desafiofullstack.sql** para criar e popular o banco de dados MySql. Caso deseje, você pode visualizar o DER no arquivo localizado na pasta **/scrits/DER/**.

2. Caso seja necessário alterar os dados de acesso ao banco, abra o arquivo **/api/app/src/settings.php** e encontre o seguinte trecho de código:
>'db' => [
> 'driver' => 'mysql',
> 'host' => 'localhost',
> 'database' => 'celsolisboa',
> 'username' => 'root',
> 'password' => '',
> 'charset' => 'utf8',
> 'collation' => 'utf8_unicode_ci',
> 'prefix' => '',
> ]

3. Na raiz do projeto, execute o comando:
```sh
$ npm install
```

4. Navegue até a pasta **/api/** e execute o comando:
```sh
$ composer install
```

5. No terminal, navegue até a raiz do projeto e execute o comando:
```sh
$ php -S localhost:8080
```

6. No navegador, acesse a url **localhost:8080** para iniciar o sistema.



### Dados para login no sistema

**email**: desafio@celsolisboa.edu.br
**senha**: celsolisboa


16 changes: 16 additions & 0 deletions api/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# For production, put your rewrite rules directly into your VirtualHost
# directive and turn off AllowOverride.

<IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]


RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
</IfModule>
53 changes: 53 additions & 0 deletions api/app/dependencies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
// DIC configuration

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Cache\FilesystemCache;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\ORM\Tools\Setup;
use Slim\Container;

require_once __DIR__ . '/../vendor/autoload.php';

$container = $app->getContainer();

// -----------------------------------------------------------------------------
// Service providers
// -----------------------------------------------------------------------------
// Service factory for the ORM
$container['db'] = function ($container) {
$capsule = new \Illuminate\Database\Capsule\Manager;
$capsule->addConnection($container['settings']['db']);

$capsule->setAsGlobal();
$capsule->bootEloquent();

return $capsule;
};

// -----------------------------------------------------------------------------
// Action factories
// -----------------------------------------------------------------------------


$container[AutenticacaoTokenMiddleware::class] = function ($container) {
return new AutenticacaoTokenMiddleware($container['db']);
};


$container[App\Action\UsuarioLogar::class] = function ($container) {
return new App\Action\UsuarioLogar($container['db']);
};

$container[App\Action\CursoListar::class] = function ($container) {
return new App\Action\CursoListar($container['db']);
};

$container[App\Action\VerificarToken::class] = function ($container) {
return new App\Action\VerificarToken($container['db']);
};

$container[App\Action\CursoExcluir::class] = function ($container) {
return new App\Action\CursoExcluir($container['db']);
};
43 changes: 43 additions & 0 deletions api/app/middleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

use App\Entity\Usuario;
use App\Service\UsuarioService;
use App\Helper\FuncoesHelper;

class AutenticacaoTokenMiddleware
{
/**
* Example middleware invokable class
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/


public function __invoke($request, $response, $next)
{
try{
$tokenHeader = $request->getHeader('token');
$emailHeader = $request->getHeader('email');

$usuario = new Usuario();
$usuario->email = $emailHeader;
$usuario->token = $tokenHeader;


$uS = new UsuarioService( $usuario );
$verificado = $uS->verificarToken();

$status = $response->getStatusCode();

}catch( \Exception $e ){
$msg = $e->getMessage();
die( FuncoesHelper::formatarSaidaJson(401,"Requisição não autorizada! Token Inválido!",[],1));
}

return $next($request, $response);
}
}
11 changes: 11 additions & 0 deletions api/app/routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
// Routes

$app->get('/usuario/logar', App\Action\UsuarioLogar::class);
$app->get('/usuario/verificarToken', App\Action\VerificarToken::class);
$app->get('/cursos', App\Action\CursoListar::class)->add( AutenticacaoTokenMiddleware::class );
$app->get('/curso/{id}', App\Action\CursoListar::class)->add( AutenticacaoTokenMiddleware::class );
$app->delete('/curso/{id}', App\Action\CursoExcluir::class)->add( AutenticacaoTokenMiddleware::class );
$app->get('/professores', App\Action\ProfessorListar::class)->add( AutenticacaoTokenMiddleware::class );
$app->get('/salas', App\Action\SalaListar::class)->add( AutenticacaoTokenMiddleware::class );
$app->post('/curso', App\Action\CursoSalvar::class)->add( AutenticacaoTokenMiddleware::class );
37 changes: 37 additions & 0 deletions api/app/settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
return [
'settings' => [
// Slim Settings
'determineRouteBeforeAppMiddleware' => false,
'displayErrorDetails' => true,

// View settings
'view' => [
'template_path' => __DIR__ . '/templates',
'twig' => [
'cache' => __DIR__ . '/../cache/twig',
'debug' => true,
'auto_reload' => true,
],
],

// monolog settings
'logger' => [
'name' => 'app',
'path' => __DIR__ . '/../log/app.log',
],

'db' => [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'celsolisboa',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
]


],
];
40 changes: 40 additions & 0 deletions api/app/src/Action/CursoExcluir.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
namespace App\Action;

use Slim\Http\Request;
use Slim\Http\Response;
use Illuminate\Database\Query\Builder;
use \App\Helper\FuncoesHelper;
use \App\Entity\Curso;
use \App\Entity\CursoProfessor;
use \App\Service\CursoService;

class CursoExcluir
{


public function __invoke(Request $request, Response $response, $args)
{
try{

$id = isset($args['id']) ? $args['id'] : null;
$curso = new Curso();

$cursoService = new CursoService($curso);
$retorno = $cursoService->excluir($id);

$erro = 0;
$msg = "Curso Excluído com sucesso!";
$dados = [];

}catch( \Exception $e ){
$erro = 1;
$msg = $e->getMessage();
$dados = [];
}

$status = $response->getStatusCode();

return FuncoesHelper::formatarSaidaJson($status, $msg, $dados, $erro);
}
}
49 changes: 49 additions & 0 deletions api/app/src/Action/CursoListar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
namespace App\Action;

use Slim\Http\Request;
use Slim\Http\Response;
use Illuminate\Database\Query\Builder;
use \App\Helper\FuncoesHelper;
use \App\Entity\Curso;
use \App\Entity\CursoProfessor;
use \App\Service\CursoService;

class CursoListar
{


public function __invoke(Request $request, Response $response, $args)
{
try{

$id = isset($args['id']) ? $args['id'] : null;
$curso = new Curso();

$cursoService = new CursoService($curso);
$cursos = $cursoService->listar($id);

$listaCursos = [];
foreach($cursos as $curso){
$listaCursos[] = array(
'curso' => $curso->toArray(),
'professores' => $curso->professores->toArray(),
'salas' => $curso->salas->toArray()
);
}

$erro = 0;
$msg = "Lista de Cursos";
$dados = $listaCursos;

}catch( \Exception $e ){
$erro = 1;
$msg = $e->getMessage();
$dados = [];
}

$status = $response->getStatusCode();

return FuncoesHelper::formatarSaidaJson($status, $msg, $dados, $erro);
}
}
Loading