Skip to content

Commit 26a6d25

Browse files
Implementa liquidação, saldo do cliente e ajustes de admin
1 parent 32f9f9f commit 26a6d25

46 files changed

Lines changed: 2116 additions & 406 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM php:8.2-apache
22

33
# Install PHP extensions required by CodeIgniter 4
44
RUN apt-get update && apt-get install -y libicu-dev \
5-
&& docker-php-ext-install pdo pdo_mysql bcmath intl \
5+
&& docker-php-ext-install pdo pdo_mysql mysqli bcmath intl \
66
&& apt-get clean && rm -rf /var/lib/apt/lists/*
77

88
# Enable Apache mod_rewrite (essential for CI4 routing)

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ Sistema Web para cadastro de campeonatos, times, jogos, clientes e apostas em eS
4848
http://localhost:8080
4949
```
5050

51+
3. **Criar o primeiro admin para testes:**
52+
O cadastro público cria apenas clientes. Para criar um admin inicial, rode o seeder abaixo:
53+
```bash
54+
php spark db:seed AdminSeeder
55+
```
56+
Opcionalmente, defina estas variáveis no ambiente antes de executar o comando:
57+
- `ADMIN_EMAIL`
58+
- `ADMIN_PASSWORD`
59+
60+
Se você não definir nada, o seeder usa `admin@pimbastic.local` e `admin123`.
61+
5162
---
5263

5364
## 🎮 Roteiro de Teste (Como Avaliar)
@@ -56,7 +67,7 @@ O sistema conta com um redirecionamento inteligente na tela de login para facili
5667

5768
1. **Acesso do Administrador (Dashboard & Cadastros):**
5869
- Acesse `http://localhost:8080` (será redirecionado para a tela de login).
59-
- Digite qualquer e-mail que contenha a palavra **`admin`** (ex: `admin@pimbastic.com`) e qualquer senha.
70+
- Digite qualquer e-mail que contenha a palavra **`admin`** (ex: `admin@pimbastic.local`) e qualquer senha.
6071
- Clique em **Entrar no Sistema**.
6172
- Você será levado ao **Painel Administrativo** exibindo métricas do sistema e status online.
6273
- Navegue pelo menu lateral para acessar as listagens de **Campeonatos**, **Times** e **Usuários**.
@@ -68,6 +79,7 @@ O sistema conta com um redirecionamento inteligente na tela de login para facili
6879
- Clique em **Entrar no Sistema**.
6980
- Você será levado ao **Mercado de Apostas (Sportsbook)** do cliente.
7081
- O sportsbook exibe o saldo do usuário (R$ 1.500,50) e cards interativos com jogos de eSports.
82+
- **Adicionar saldo (teste):** O cliente pode creditar saldo manualmente pelo dashboard em "Adicionar Saldo" para testar apostas — esse fluxo é simulado e não processa pagamentos reais.
7183
- **Interatividade das Odds**: Clique em um dos botões de odd ("Casa", "Empate" ou "Fora") de um jogo. O botão correspondente ficará marcado com brilho ciano, e um painel de cálculo aparecerá mostrando o retorno estimado da aposta em tempo real ao digitar um valor.
7284
- Insira um valor no input e clique em **Apostar** para registrar a aposta (mensagem de sucesso de mock é exibida).
7385
- Abaixo dos jogos, visualize a tabela com o histórico de apostas realizadas.

app/Config/Database.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ class Database extends Config
2626
*/
2727
public array $default = [
2828
'DSN' => '',
29-
'hostname' => 'localhost',
29+
'hostname' => '',
3030
'username' => '',
3131
'password' => '',
3232
'database' => '',
33-
'DBDriver' => 'MySQLi',
33+
'DBDriver' => '',
3434
'DBPrefix' => '',
3535
'pConnect' => false,
3636
'DBDebug' => true,
@@ -194,6 +194,13 @@ public function __construct()
194194
{
195195
parent::__construct();
196196

197+
$this->default['hostname'] = env('DB_HOST', '127.0.0.1');
198+
$this->default['username'] = env('DB_USER', 'root');
199+
$this->default['password'] = env('DB_PASS', 'root');
200+
$this->default['database'] = env('DB_NAME', 'pimbastic_esports');
201+
$this->default['DBDriver'] = env('DB_DRIVER', 'MySQLi');
202+
$this->default['port'] = (int) env('DB_PORT', 3306);
203+
197204
// Ensure that we always set the database group to 'tests' if
198205
// we are currently running an automated test suite, so that
199206
// we don't overwrite live data on accident.

app/Config/Routes.php

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* @var RouteCollection $routes
77
*/
88

9+
$routes->setAutoRoute(false);
10+
911
// ── Auth (público) ──────────────────────────────────────────
1012
$routes->get('/', 'AuthController::login');
1113
$routes->get('login', 'AuthController::login');
@@ -15,40 +17,61 @@
1517
$routes->get('logout', 'AuthController::logout');
1618

1719
// ── Cliente (protegido por AuthFilter + ClienteFilter) ──────
18-
$routes->group('cliente', static function ($routes) {
20+
$routes->group('cliente', ['filter' => 'cliente'], static function ($routes) {
21+
$routes->get('/', 'ClienteController::dashboard');
22+
$routes->get('dashboard', 'ClienteController::dashboard');
1923
$routes->get('sportsbook', 'ClienteController::sportsbook');
24+
$routes->get('carteira/adicionar', 'ClienteController::showAdicionarSaldo');
2025
$routes->post('apostar', 'ClienteController::apostar');
26+
$routes->post('carteira/adicionar', 'ClienteController::adicionarSaldo');
27+
$routes->put('atualizar-aposta/(:num)', 'ClienteController::atualizarAposta/$1');
28+
$routes->post('atualizar-aposta/(:num)', 'ClienteController::atualizarAposta/$1');
29+
$routes->delete('cancelar-aposta/(:num)', 'ClienteController::cancelarAposta/$1');
30+
$routes->post('cancelar-aposta/(:num)', 'ClienteController::cancelarAposta/$1');
31+
$routes->get('carteira', 'ClienteController::carteira');
2132
});
2233

2334
// ── Admin (protegido por AuthFilter + AdminFilter) ──────────
24-
$routes->group('admin', static function ($routes) {
35+
$routes->group('admin', ['filter' => 'admin'], static function ($routes) {
36+
$routes->get('/', 'AdminController::dashboard');
2537
$routes->get('dashboard', 'AdminController::dashboard');
38+
$routes->get('jogos', 'AdminController::indexJogos');
39+
$routes->get('liquidacao', 'LiquidacaoController::index');
40+
$routes->get('liquidacao/debug', 'LiquidacaoController::debug');
41+
$routes->post('liquidacao/processar/(:num)', 'LiquidacaoController::processar/$1');
2642

2743
// Campeonatos CRUD
2844
$routes->get('campeonatos', 'CampeonatoController::index');
2945
$routes->get('campeonatos/create', 'CampeonatoController::create');
3046
$routes->post('campeonatos/store', 'CampeonatoController::store');
3147
$routes->get('campeonatos/edit/(:num)', 'CampeonatoController::edit/$1');
3248
$routes->post('campeonatos/update/(:num)', 'CampeonatoController::update/$1');
49+
$routes->put('campeonatos/update/(:num)', 'CampeonatoController::update/$1');
50+
$routes->delete('campeonatos/delete/(:num)', 'CampeonatoController::delete/$1');
3351

3452
// Times CRUD
3553
$routes->get('times', 'TimeController::index');
3654
$routes->get('times/create', 'TimeController::create');
3755
$routes->post('times/store', 'TimeController::store');
3856
$routes->get('times/edit/(:num)', 'TimeController::edit/$1');
3957
$routes->post('times/update/(:num)', 'TimeController::update/$1');
58+
$routes->put('times/update/(:num)', 'TimeController::update/$1');
59+
$routes->delete('times/delete/(:num)', 'TimeController::delete/$1');
4060

4161
// Jogos CRUD
42-
$routes->get('jogos', 'JogoController::index');
4362
$routes->get('jogos/create', 'JogoController::create');
4463
$routes->post('jogos/store', 'JogoController::store');
4564
$routes->get('jogos/edit/(:num)', 'JogoController::edit/$1');
4665
$routes->post('jogos/update/(:num)', 'JogoController::update/$1');
66+
$routes->put('jogos/update/(:num)', 'JogoController::update/$1');
67+
$routes->delete('jogos/delete/(:num)', 'JogoController::delete/$1');
4768

4869
// Usuários CRUD
4970
$routes->get('usuarios', 'UsuarioController::index');
5071
$routes->get('usuarios/create', 'UsuarioController::create');
5172
$routes->post('usuarios/store', 'UsuarioController::store');
5273
$routes->get('usuarios/edit/(:num)', 'UsuarioController::edit/$1');
5374
$routes->post('usuarios/update/(:num)', 'UsuarioController::update/$1');
75+
$routes->put('usuarios/update/(:num)', 'UsuarioController::update/$1');
76+
$routes->delete('usuarios/delete/(:num)', 'UsuarioController::delete/$1');
5477
});

app/Controllers/AdminController.php

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,83 @@
22

33
namespace App\Controllers;
44

5+
use App\Models\CampeonatoModel;
6+
use App\Models\ClienteModel;
7+
use App\Models\JogoModel;
8+
use App\Models\ResolucaoModel;
9+
use App\Models\TimeModel;
10+
use App\Models\UsuarioModel;
11+
use Config\Database;
12+
513
class AdminController extends BaseController
614
{
715
public function dashboard()
816
{
17+
$db = Database::connect();
18+
$campeonatoModel = new CampeonatoModel();
19+
$timeModel = new TimeModel();
20+
$jogoModel = new JogoModel();
21+
$resolucaoModel = new ResolucaoModel();
22+
$usuarioModel = new UsuarioModel();
23+
$clienteModel = new ClienteModel();
24+
$jogosPendentes = $resolucaoModel->getJogosPendentes();
25+
26+
$ultimosJogos = $jogoModel
27+
->select('jogo.*, campeonato.nome as campeonato, tc.nome as casa, tf.nome as fora')
28+
->join('campeonato', 'campeonato.id = jogo.campeonato_id')
29+
->join('time as tc', 'tc.id = jogo.time_casa_id')
30+
->join('time as tf', 'tf.id = jogo.time_fora_id')
31+
->orderBy('jogo.id', 'DESC')
32+
->findAll(5);
33+
34+
$ultimosUsuarios = $usuarioModel
35+
->orderBy('id', 'DESC')
36+
->findAll(5);
37+
938
$dados = [
1039
'title' => 'Dashboard Admin - Pimbastic',
1140
'server_status' => 'ONLINE',
1241
'metricas' => [
13-
'usuarios_ativos' => 124,
14-
'apostas_pendentes' => 45,
15-
'volume_financeiro' => 12500.00
16-
],
17-
'campeonatos' => [
18-
['id' => 1, 'nome' => 'CBLOL Split 2', 'pais' => 'Brasil'],
19-
['id' => 2, 'nome' => 'VCT Américas', 'pais' => 'EUA']
20-
],
21-
'times' => [
22-
['id' => 1, 'nome' => 'LOUD', 'sigla' => 'LLL'],
23-
['id' => 2, 'nome' => 'Furia', 'sigla' => 'FUR']
42+
'campeonatos_total' => $db->table('campeonato')->countAllResults(),
43+
'times_total' => $db->table('time')->countAllResults(),
44+
'jogos_total' => $db->table('jogo')->countAllResults(),
45+
'usuarios_total' => $db->table('usuario')->countAllResults(),
46+
'liquidacoes_pendentes' => count($jogosPendentes),
2447
],
25-
'ultimos_cadastros' => [
26-
['tipo' => 'Campeonato', 'nome' => 'Major 2026', 'data' => 'Hoje'],
27-
['tipo' => 'Time', 'nome' => 'Sentinels', 'data' => 'Ontem'],
28-
['tipo' => 'Usuário', 'nome' => 'João Apostador', 'data' => 'Ontem'],
29-
]
48+
'campeonatos' => $campeonatoModel->orderBy('id', 'DESC')->findAll(5),
49+
'times' => $timeModel->orderBy('id', 'DESC')->findAll(5),
50+
'usuarios' => $ultimosUsuarios,
51+
'clientes' => $clienteModel->orderBy('id', 'DESC')->findAll(5),
52+
'jogos' => $ultimosJogos,
53+
'jogos_pendentes' => $jogosPendentes,
54+
'ultimos_cadastros' => array_map(static function (array $jogo) {
55+
return [
56+
'tipo' => 'Jogo',
57+
'nome' => $jogo['campeonato'] . ' - ' . $jogo['casa'] . ' vs ' . $jogo['fora'],
58+
'data' => $jogo['data_horario'],
59+
];
60+
}, $ultimosJogos),
3061
];
3162

3263
return $this->renderView('admin/dashboard', $dados);
3364
}
65+
66+
public function indexJogos()
67+
{
68+
$jogoModel = new JogoModel();
69+
70+
$jogos = $jogoModel
71+
->select('jogo.*, campeonato.nome as campeonato, tc.nome as casa, tf.nome as fora')
72+
->join('campeonato', 'campeonato.id = jogo.campeonato_id')
73+
->join('time as tc', 'tc.id = jogo.time_casa_id')
74+
->join('time as tf', 'tf.id = jogo.time_fora_id')
75+
->orderBy('jogo.id', 'DESC')
76+
->paginate(10);
77+
78+
return $this->renderView('admin/jogos/index', [
79+
'title' => 'Gerenciar Jogos - Pimbastic',
80+
'jogos' => $jogos,
81+
'pager' => $jogoModel->pager,
82+
]);
83+
}
3484
}

app/Controllers/AuthController.php

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,64 @@
22

33
namespace App\Controllers;
44

5+
use App\Models\UsuarioModel;
6+
use App\Services\AuthService;
7+
58
class AuthController extends BaseController
69
{
10+
public function __construct(private readonly AuthService $authService = new AuthService())
11+
{
12+
}
13+
714
public function login()
815
{
16+
$this->ensureBootstrapAdmin();
17+
918
return view('auth/login', ['title' => 'Login - Pimbastic Esports']);
1019
}
1120

1221
public function autenticar()
1322
{
23+
$regras = [
24+
'email' => 'required|valid_email',
25+
'senha' => 'required|min_length[6]',
26+
];
27+
28+
if (!$this->validate($regras)) {
29+
return redirect()->back()->withInput()->with('error', $this->validator->getErrors());
30+
}
31+
1432
$email = $this->request->getPost('email');
1533
$senha = $this->request->getPost('senha');
1634

17-
if (empty($email) || empty($senha)) {
18-
return redirect()->back()->with('error', 'Preencha todos os campos.');
35+
$resultado = $this->authService->autenticar($email, $senha);
36+
37+
if (!$resultado['success']) {
38+
return redirect()->back()->withInput()->with('error', $resultado['message']);
1939
}
2040

21-
// Mock check: any email containing 'admin' gets admin, others get client sportsbook
22-
if (strpos(strtolower($email), 'admin') !== false) {
23-
$sessionData = [
24-
'usuario_id' => 1,
25-
'usuario_nome' => 'Admin Pimbastic',
26-
'usuario_email' => $email,
27-
'usuario_perfil' => 'admin',
28-
'logged_in' => true
29-
];
30-
$this->session->set($sessionData);
31-
return redirect()->to('/admin/dashboard')->with('success', 'Bem-vindo ao Painel Administrativo!');
32-
} else {
33-
$sessionData = [
34-
'usuario_id' => 2,
35-
'usuario_nome' => 'Jogador Pimbastic',
36-
'usuario_email' => $email,
37-
'usuario_perfil' => 'cliente',
38-
'logged_in' => true
39-
];
40-
$this->session->set($sessionData);
41-
return redirect()->to('/cliente/sportsbook')->with('success', 'Login realizado com sucesso!');
41+
$usuario = $resultado['usuario'];
42+
43+
// Normaliza perfil para evitar problemas de capitalização/espacos
44+
$perfilNormalizado = strtolower(trim((string) ($usuario['perfil'] ?? '')));
45+
46+
$this->session->regenerate(true);
47+
$this->session->set([
48+
'logado' => true,
49+
'logged_in' => true,
50+
'usuario_id' => $usuario['id'],
51+
'usuario_nome' => $usuario['nome'],
52+
'usuario_email' => $usuario['email'],
53+
'usuario_perfil' => $perfilNormalizado,
54+
'perfil' => $perfilNormalizado,
55+
'cliente_id' => $usuario['cliente_id'] ?? null,
56+
]);
57+
58+
if ($perfilNormalizado === 'admin') {
59+
return redirect()->to('/admin/dashboard')->with('success', 'Bem-vindo ao painel administrativo.');
4260
}
61+
62+
return redirect()->to('/cliente/dashboard')->with('success', 'Login realizado com sucesso.');
4363
}
4464

4565
public function cadastro()
@@ -51,21 +71,55 @@ public function salvar()
5171
{
5272
$regras = [
5373
'nome' => 'required|min_length[3]',
54-
'email' => 'required|valid_email',
74+
'email' => 'required|valid_email|is_unique[usuario.email]',
5575
'senha' => 'required|min_length[6]',
56-
'perfil' => 'required|in_list[admin,cliente]'
5776
];
5877

5978
if (!$this->validate($regras)) {
6079
return redirect()->back()->withInput()->with('error', $this->validator->getErrors());
6180
}
6281

63-
return redirect()->to('/login')->with('success', 'Cadastro realizado com sucesso! Faça seu login.');
82+
$resultado = $this->authService->registrar([
83+
'nome' => $this->request->getPost('nome'),
84+
'email' => $this->request->getPost('email'),
85+
'senha' => $this->request->getPost('senha'),
86+
'perfil' => 'cliente',
87+
]);
88+
89+
if (!$resultado['success']) {
90+
return redirect()->back()->withInput()->with('error', $resultado['message']);
91+
}
92+
93+
return redirect()->to('/login')->with('success', $resultado['message']);
6494
}
6595

6696
public function logout()
6797
{
6898
$this->session->destroy();
6999
return redirect()->to('/login');
70100
}
101+
102+
private function ensureBootstrapAdmin(): void
103+
{
104+
$usuarioModel = new UsuarioModel();
105+
106+
if ($usuarioModel->where('perfil', 'admin')->first()) {
107+
return;
108+
}
109+
110+
$email = strtolower(trim((string) (env('ADMIN_EMAIL') ?: 'admin@pimbastic.local')));
111+
$senha = (string) (env('ADMIN_PASSWORD') ?: 'admin123');
112+
113+
if ($usuarioModel->findByEmail($email)) {
114+
return;
115+
}
116+
117+
$usuarioModel->insert([
118+
'nome' => 'Administrador',
119+
'email' => $email,
120+
'senha' => password_hash($senha, PASSWORD_DEFAULT),
121+
'perfil' => 'admin',
122+
'cliente_id' => null,
123+
]);
124+
}
71125
}

0 commit comments

Comments
 (0)