<repo_name>robmoraes/essentia-teste-fullstack<file_sep>/frontend/src/store/admin/security/users/actions.js
import Vue from 'vue'

const USERS_ROUTE = '/security/users'

export function list (context) {
  const p = new Promise((resolve, reject) => {
    return Vue.prototype.$axios
      .get(`${USERS_ROUTE}`)
      .then(res => resolve(res.data))
      .catch(err => reject(err.response))
  })
  return p
}

export function insert (context, payload) {
  const p = new Promise((resolve, reject) => {
    return Vue.prototype.$axios
      .post(`${USERS_ROUTE}`, payload, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      })
      .then(res => resolve(res.data))
      .catch(err => reject(err.response))
  })
  return p
}

export function show (context, id) {
  const p = new Promise((resolve, reject) => {
    return Vue.prototype.$axios
      .get(`${USERS_ROUTE}/${id}`)
      .then(res => resolve(res.data))
      .catch(err => reject(err.response))
  })
  return p
}

export function update (context, payload) {
  const formData = new FormData()
  formData.append('name', payload.name)
  formData.append('email', payload.email)
  formData.append('phone', payload.phone)
  formData.append('photo', payload.photo)
  formData.append('photo_upload', payload.photo_upload)
  formData.append('password', payload.password)

  const p = new Promise((resolve, reject) => {
    return Vue.prototype.$axios
      .post(`${USERS_ROUTE}/${payload.id}`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      })
      .then(res => resolve(res.data))
      .catch(err => reject(err.response))
  })
  return p
}

export function destroy (context, id) {
  const p = new Promise((resolve, reject) => {
    return Vue.prototype.$axios
      .delete(`${USERS_ROUTE}/${id}`)
      .then(res => resolve(res.data))
      .catch(err => reject(err.response))
  })
  return p
}
<file_sep>/backend/routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

// Authentication
Route::post('/login', 'Api\AuthController@login');

// Access by permission
Route::middleware('auth:api')->get('/user', 'Api\Security\UserController@getAuthUser');
Route::middleware('auth:api')->apiResource('/security/users', 'Api\Security\UserController');
Route::middleware('auth:api')->apiResource('/security/permissions', 'Api\Security\PermissionController');
Route::middleware('auth:api')->apiResource('/security/roles', 'Api\Security\RoleController');

Route::middleware('auth:api')->post('/security/users/{user}', 'Api\Security\UserController@update');
<file_sep>/frontend/src/store/admin/security/permissions/actions.js
import Vue from 'vue'

const PERMISSIONS_ROUTE = 'security/permissions'

export function setList (context, obj) {
  const p = new Promise(function (resolve, reject) {
    return Vue.prototype.$axios
      .get(PERMISSIONS_ROUTE)
      .then(res => {
        const payload = res.data
        context.commit('SET_PERMISSIONS', payload)
        resolve(res)
      })
      .catch(err => {
        reject(err.response)
      })
  })
  return p
}

export function post (context, payload) {
  const p = new Promise(function (resolve, reject) {
    return Vue.prototype.$axios
      .post(PERMISSIONS_ROUTE, payload)
      .then(res => {
        resolve(res)
      })
      .catch(err => {
        reject(err.response)
      })
  })
  return p
}

export function put (context, payload) {
  const p = new Promise(function (resolve, reject) {
    return Vue.prototype.$axios
      .put(`${PERMISSIONS_ROUTE}/${payload.id}`, payload)
      .then(res => {
        resolve(res)
      })
      .catch(err => {
        reject(err.response)
      })
  })
  return p
}

export function destroy (context, payload) {
  const p = new Promise(function (resolve, reject) {
    return Vue.prototype.$axios
      .delete(`${PERMISSIONS_ROUTE}/${payload}`)
      .then(res => {
        resolve(res)
      })
      .catch(err => {
        reject(err.response)
      })
  })
  return p
}
<file_sep>/README.md
# essentia-teste-fullstack
Teste para vaga de desenvolvedor Full stack da Essentia Group

## Visão Geral

Este é um teste para processo seletivo de full stack, as camadas de backend e frontend foram desenvolvidas em projetos separados, para realizar a instalação de cada uma, é necessário seguir as instruções que estão nas pastas

- /backend
- /frontend

## Back-end

Para o backend foi usado PHP/Laravel com banco de dados sqlite3, foi construída uma API para prover recursos de front-end. Foi implementado sistema de autenticação com oauth2.

## Front-end

Para o front foi usado Vue2/Quasar.dev com o qual foi construída uma SPA para montar as telas, o framework implementa Material Design 2 e possui um robusto pacote de componentes além de uma estrutura de pastas que garante a organização do código e adoção de boas práticas de desenvolvimento.

## Instalação

Acesse cada uma das pastas para ver as instruções de instalação de cada ambiente.

## Playground

Para facilitar a demonstração do sistema rodando, distribuí uma versão no link abaixo:

[Playground do Teste da Essentia](https://essentia.seemann.com.br)

- Login: <EMAIL>
- Senha: <PASSWORD>
<file_sep>/frontend/README.md
# essentia-teste-fulltack Frontend
Projeto de frontend para processo de seleção da empresa Essentia

## Visão Geral

Este é um teste para processo seletivo de full stack, as camadas de backend e frontend foram desenvolvidas em projetos separados, para realizar a instalação de cada uma, é necessário seguir as instruções que estão nas pastas

- /backend
- /frontend

Estas são as instruções para instalação da camada de Front-end.

## Requisitos

- Quasar 1.15
- Node >=10
- NPM >=5

A instalação do quasar pode ser guiada no seguinte link (atenção as recomendações sobre Node e NPM):

- [https://quasar.dev/quasar-cli/installation](https://quasar.dev/quasar-cli/installation)

## Download do projeto

```bash
$ git clone https://github.com/robmoraes/essentia-teste-fullstack.git
```

## Instalação das dependências

Acessar a pasta /frontend:

```bash
cd /pasta/do/projeto/frontend
npm install
```

Após instalar, algumas alterações no arquivo "/quasar.conf.js" podem ser necessárias:

```js
build: {
      env: {
        API: ctx.dev
          ? 'http://localhost:8000/api' // Informar URL da API
          : 'http://localhost:8000/api' // Seria a URL da API de produção
      },

// Caso a aplicação frontend deva rodar na rede,
// deve ser configurado devServer:
devServer: {
      https: false,
      host: '10.0.0.190', // ip para acesso na rede
      port: 8080,         // porta -- o acesso ficará http://10.0.0.190:8080 por exemplo
      open: true // opens browser window automatically
    },

```

### Rodar a aplicação no modo de Desenvolvimento (hot-code reloading, error reporting, etc.)

Depois de instalado com npm, e configurado o arquivo "quasar.conf.js", a aplicação pode ser executada com o comando abaixo:

```bash
cd /pasta/do/projeto/frontend
quasar dev
```

E já pode ser acessado pela URL configurada que é exibida após a conclusão do comando quasar dev.

As credênciais de acesso podem ser obtidas após a instalação da aplicação backend.

## Degustação

Mas como o processo de instalação é relativamente longo, preparei um ambiente de degustação para que possam avaliar. Para isso, publiquei o build do frontend na estrutura de views do laravel e fiz um pequeno ajuste nas rotas do laravel (/routes/web.php) para resolver as uris do front. Sendo assim a API e o Front rodam sob mesmo domínio, mas a construção foi completamente desacoplada.

- [Playground do desafio](https://essentia.seemann.com.br)

Lembrando:

- e-mail: <EMAIL>
- senha: <PASSWORD>

### Build da aplicação para produção

```bash
quasar build
```
<file_sep>/frontend/src/boot/axios.js
import axios from 'axios'
import qs from 'qs'
import auth from '../services/auth'

const axiosInstance = axios.create({
  paramsSerializer: params => {
    return qs.stringify(params, { arrayFormat: 'repeat' })
  },
  // baseURL: 'http://essentia.local/api'
  baseURL: process.env.API
})

const a = auth.get()
if (a) {
  if (a.check) {
    axiosInstance.defaults.headers.common.Authorization = `${a.token.token_type} ${a.token.access_token}`
  }
}

export default ({ Vue }) => {
  Vue.prototype.$axios = axiosInstance
}

export { axiosInstance }
<file_sep>/frontend/src/router/routes.js
const routes = [
  {
    path: '/',
    component: () => import('layouts/DesktopLayout.vue'),
    children: [
      { path: '', component: () => import('pages/Index.vue') },
      { path: 'admin/security/permissions', component: () => import('pages/admin/security/Permissions.vue') },
      { path: 'admin/security/roles', component: () => import('pages/admin/security/roles/List.vue') },
      { path: 'admin/security/roles/create', component: () => import('pages/admin/security/roles/Create.vue') },
      { path: 'admin/security/roles/:id/edit', component: () => import('pages/admin/security/roles/Edit.vue') },
      { path: 'admin/security/users', component: () => import('pages/admin/security/users/List.vue') },
      { path: 'admin/security/users/:id/edit', component: () => import('pages/admin/security/users/Edit.vue') },
      { path: 'admin/security/users/create', component: () => import('pages/admin/security/users/Create.vue') }
    ],
    meta: { requiresAuth: true }
  },

  {
    path: '/login',
    component: () => import('layouts/LoginLayout.vue'),
    meta: { requiresAuth: false }
  },

  // Always leave this as last one,
  // but you can also remove it
  {
    path: '*',
    component: () => import('pages/Error404.vue')
  }
]

export default routes
<file_sep>/frontend/src/store/auth/mutations.js
export function updateAuthState (state, payload) {
  state.auth = payload
  sessionStorage.setItem('auth', JSON.stringify(payload))
}
<file_sep>/frontend/src/store/auth/getters.js
// export function check (state) {
// }
<file_sep>/frontend/src/services/auth.js
const auth = {
  get: function () {
    return JSON.parse(sessionStorage.getItem('auth'))
  }
}

export default auth
<file_sep>/frontend/src/store/auth/actions.js
import Vue from 'vue'
// import { axiosInstance } from 'boot/axios'

const LOGIN_ROUTE = '/login'

export function login (context, credentials) {
  const p = new Promise(function (resolve, reject) {
    return Vue.prototype.$axios
      .post(LOGIN_ROUTE, credentials)
      .then(response => {
        const payload = {
          user: response.data.user,
          token: response.data.token,
          check: true
        }
        context.commit('updateAuthState', payload)
        Vue.prototype.$axios.defaults.headers.common.Authorization =
          `${payload.token.token_type} ${payload.token.access_token}`
        resolve(response)
      })
      .catch(error => {
        console.log(error)
        reject(error)
      })
  })
  return p
}

export function logout (context) {
  Vue.prototype.$axios.defaults.headers.common.Authorization = ''
  context.commit('updateAuthState', {
    user: null,
    token: null,
    check: false
  })
}
<file_sep>/frontend/src/store/admin/security/permissions/mutations.js
export function SET_PERMISSIONS (state, payload) {
  state.list = payload
}
