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
31 changes: 31 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
APP_NAME=Lumen
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=UTC

LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=test_backend_picpay
DB_USERNAME=picpay
DB_PASSWORD=123mudar

DB_HOST2=127.0.0.1
DB_PORT2=3322
DB_DATABASE2=test_backend_picpay
DB_USERNAME2=picpay
DB_PASSWORD2=123mudar

ELASTIC_HOST=elasticsearch
ELASTIC_PORT=9200
ELASTIC_USER=
ELASTIC_PASS=
ELASTIC_SCHEME=http

CACHE_DRIVER=file
QUEUE_CONNECTION=sync
25 changes: 25 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
APP_NAME=Lumen
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=UTC

LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

ELASTIC_HOST=127.0.0.1
ELASTIC_PORT=9200
ELASTIC_USER=
ELASTIC_PASS=
ELASTIC_SCHEME=http

CACHE_DRIVER=file
QUEUE_CONNECTION=sync
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor
/.idea
57 changes: 37 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
![PicPay](https://user-images.githubusercontent.com/1765696/26998603-711fcf30-4d5c-11e7-9281-0d9eb20337ad.png)

# Teste Backend
# Requisitos iniciais da aplicação.
Ter instalado o docker, docker-compose e composer

O desafio é criar uma API REST que busca usuarios pelo nome e username a partir de uma palavra chave. Faça o download do arquivo [users.csv.gz](https://s3.amazonaws.com/careers-picpay/users.csv.gz) que contém o banco de dados que deve ser usado na busca. Ele contém os IDs, nomes e usernames dos usuários.
* https://docs.docker.com/install/
* https://docs.docker.com/compose/install/
* https://getcomposer.org/download/

###### Exemplo
| ID | Nome | Username |
|--------------------------------------|-------------------|----------------------|
| 065d8403-8a8f-484d-b602-9138ff7dedcf | Wadson marcia | wadson.marcia |
| 5761be9e-3e27-4be8-87bc-5455db08408 | Kylton Saura | kylton.saura |
| ef735189-105d-4784-8e2d-c8abb07e72d3 | Edmundo Cassemiro | edmundo.cassemiro |
| aaa40f4e-da26-42ee-b707-cb81e00610d5 | Raimundira M | raimundiram |
| 51ba0961-8d5b-47be-bcb4-54633a567a99 | Pricila Kilder | pricilakilderitaliani|

### Iniciar aplicação e infraestrutura docker.

Após o clone do projeto entre no diretorio do mesmo (trabalhe-conosco-backend-dev) e execute os comandos abaixo seguindo a sequencia.

Também são fornecidas duas listas de usuários que devem ser utilizadas para priorizar os resultados da busca. A lista 1 tem mais prioridade que a lista 2. Ou seja, se dois usuarios casam com os criterios de busca, aquele que está na lista 1 deverá ser exibido primeiro em relação àquele que está na lista 2. Os que não estão em nenhuma das listas são exibidos em seguida.
- composer install (Responsavél por instalar as dependências do projeto)

As listas podem ser encontradas na raiz deste repositório ([lista_relevancia_1.txt](lista_relevancia_1.txt) e [lista_relevancia_2.txt](lista_relevancia_2.txt)).
Os resultados devem ser retornados paginados de 15 em 15 registros.
- docker-compose up -d (Ele ira subir toda a infraestrutura necessária para o projeto)

Escolha as tecnologias que você vai usar e tente montar uma solução completa para rodar a aplicação.
### Observação.:
##### - Após a execucão do comando (docker-compose up -d) os dados serão updados automaticamente pelo docker, este processo leva em torno de 3~5 minutios até que o mysql fique completamente pronto.

Faça um ***Fork*** deste repositório e abra um ***Pull Request***, **com seu nome na descrição**, para participar. Assim que terminar, envie um e-mail para ***desafio@picpay.com*** com o seu usuário do Github nos avisando.
## Consultando a API - Mysql

Na API é possivel fazer consultas de forma performatica tanto no Mysql como no ElasticSearch através das url abaixo segui.

- http://localhost:8000/api/v1/user/mysql?q=<param-search>

![Consulta_api_mysql](imgs_readme/consulta_api_mysql.png?raw=true "Title")

## Consultando a API - ElasticSearch

###### Para usar a consulta via elasticsearch precisamos enviar os dados da tabela mysql para ser indexado no mesmo.

- php artisan db:seed --class=InsertDataSampleToElasticsearch (Insere os dados que foram updados no MySQL para o ElasticSearch)


- http://localhost:8000/api/v1/user/elasticSearch?q=<param-search> (Url de consulta através do elasticsearch)

![Listar Gasto](imgs_readme/consulta_api_els.png?raw=true "Title")

-----

### Diferenciais

- Criar um frontend para realizar a busca com uma UX elaborada
- Criar uma solução de autenticação entre o frontend e o backend
- Ter um desempenho elevado num conjunto de dados muito grande
- Utilizar o Docker
- Ter um desempenho elevado num conjunto de dados muito grande
- Utilizar o Docker


### Observação.:
<b>Deixei o arquivo .env preenchido para comodidade na hora de testar o ambiente, em um cenario real o .env não deve ficar no github.</b>



Empty file added app/Console/Commands/.gitkeep
Empty file.
31 changes: 31 additions & 0 deletions app/Console/Kernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
use Nord\Lumen\Elasticsearch\Console\CreateCommand;
use Nord\Lumen\Elasticsearch\Console\DeleteCommand;

class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];

/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
//
}
}
10 changes: 10 additions & 0 deletions app/Events/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Events;

use Illuminate\Queue\SerializesModels;

abstract class Event
{
use SerializesModels;
}
16 changes: 16 additions & 0 deletions app/Events/ExampleEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace App\Events;

class ExampleEvent extends Event
{
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
}
50 changes: 50 additions & 0 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;

class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
AuthorizationException::class,
HttpException::class,
ModelNotFoundException::class,
ValidationException::class,
];

/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}

/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
}
10 changes: 10 additions & 0 deletions app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Http\Controllers;

use Laravel\Lumen\Routing\Controller as BaseController;

class Controller extends BaseController
{
//
}
18 changes: 18 additions & 0 deletions app/Http/Controllers/ExampleController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace App\Http\Controllers;

class ExampleController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
//
}

//
}
114 changes: 114 additions & 0 deletions app/Http/Controllers/UsuariosController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace App\Http\Controllers;

use App\Usuarios;
use Basemkhirat\Elasticsearch\Facades\ES;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class UsuariosController extends Controller{

private function execute($commad){

$process = new Process($commad);
$process->run();

// executes after the command finishes
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}

return $process->getOutput() ;
}

// daqui pra baixo são exemplos

public function index()
{
$usuarios = Usuarios::all()->take(20);
return response()->json($usuarios);
}

public function getUserLimitOfset()
{
$usuarios = DB::table('usuarios')->simplePaginate(15);
return response()->json($usuarios);
}

public function getUserSearch(Request $search)
{
$q =(!is_null($search->get('q'))) ? $search->get('q') : 'silca';

if ($q == ""){
return response()->json("Favor fornecer conteúdo para a busca");
}

$usuarios = ES::type("users")->search($q)
->select(
"id",
"name",
"username",
"relevance"
)
->orderBy("relevance")
->paginate(15);

return response()->json($usuarios);
}

public function getUserMysql(Request $search)
{
$q =(!is_null($search->get('q'))) ? $search->get('q') : 'silca';

if ($q == ""){
return response()->json("Favor fornecer conteúdo para a busca");
}

$usuarios = DB::table('users')
->select(
'users.id',
'users.name',
'users.username',
'usr_relevance_list.relevance'
)
->leftJoin('usr_relevance_list', 'users.id', '=', 'usr_relevance_list.id')
->whereRaw(sprintf("MATCH (name,username) AGAINST ('+%s' IN BOOLEAN MODE)", $q))
->orderByRaw('ISNULL(usr_relevance_list.relevance), usr_relevance_list.relevance ASC')
->simplePaginate(15);
return response()->json($usuarios);
}

public function getUser($id)
{
$usuarios = Usuarios::find($id);
return response()->json($usuarios);
}

public function createUser(Request $request)
{
$usuarios = Usuarios::create($request->all());
return response()->json($usuarios);
}

public function deleteUser($id)
{
$usuarios = Usuarios::find($id);
$usuarios->delete();
return response()->json('deleted');
}

public function updateUser(Request $request,$id)
{
$usuarios = Usuarios::find($id);
$usuarios->name = $request->input('name');
$usuarios->username = $request->input('username');
$usuarios->save();

return response()->json($usuarios);
}

}
?>
Loading