atualizacao
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\alunos;
|
use App\Models\Aluno;
|
||||||
use App\Models\turmas;
|
use App\Models\turmas;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
@@ -11,20 +11,45 @@ class AlunosController extends Controller
|
|||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$escolaId = Auth::user()->id_escola;
|
$user = Auth()->user();
|
||||||
if ($escolaId == 0) {
|
|
||||||
$alunos = alunos::all();
|
|
||||||
} else {
|
|
||||||
$alunos = [];
|
|
||||||
$turmas = turmas::where('id_escola', $escolaId)->get();
|
|
||||||
foreach ($turmas as $turma) {
|
|
||||||
$alunosget = alunos::where('id_turma', $turma->id)->get();
|
|
||||||
|
|
||||||
foreach ($alunosget as $alunosg) {
|
// coordenação/secretaria (ou quem tiver)
|
||||||
$alunos[] = $alunosg;
|
if ($user->can('alunos.ver_todos')) {
|
||||||
}
|
$alunos = Aluno::query()->get();
|
||||||
}
|
return view('escolas.alunos', compact('alunos'));
|
||||||
}
|
}
|
||||||
return view('escolas.alunos', compact('alunos'));
|
|
||||||
|
// aluno/responsável
|
||||||
|
if ($user->can('alunos.ver_meus')) {
|
||||||
|
$alunos = Aluno::query()
|
||||||
|
->where(function ($q) use ($user) {
|
||||||
|
$q->where('user_id', $user->id)
|
||||||
|
->orWhereHas('responsaveis', fn($r) => $r->where('users.id', $user->id));
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('alunos.index', compact('alunos'));
|
||||||
|
}
|
||||||
|
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateOrCreate(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$aluno = Aluno::updateOrCreate(
|
||||||
|
['cpf' => $request->cpf],
|
||||||
|
[
|
||||||
|
'nome' => $request->nome,
|
||||||
|
'id_turma' => $request->id_turma,
|
||||||
|
'id_escola' => $request->id_escola,
|
||||||
|
'data_nascimento' => $request->data_nascimento,
|
||||||
|
'data_inscricao' => $request->data_inscricao,
|
||||||
|
'cpf' => $request->cpf,
|
||||||
|
'user_id' => $request->user_id,
|
||||||
|
'responsavel_user_id' => $request->responsavel_user_id,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return redirect()->route('alunos')->with('success', 'Aluno Criado|Atualizado com sucesso.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
app/Http/Controllers/ConfigsController.php
Normal file
10
app/Http/Controllers/ConfigsController.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ConfigsController extends Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -2,36 +2,186 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\escolas;
|
use App\Models\Escola;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
use Spatie\Permission\Models\Permission;
|
||||||
|
use Spatie\Permission\PermissionRegistrar;
|
||||||
|
|
||||||
|
|
||||||
class EscolasController extends Controller
|
class EscolasController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
$escolas = Escola::all();
|
||||||
if (Auth::user()->id_escola == 0) {
|
|
||||||
$escolas = escolas::all();
|
|
||||||
} else {
|
|
||||||
$escolas = escolas::where('id', Auth::user()->id_escola)->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('escolas.index', compact('escolas'));
|
return view('escolas.index', compact('escolas'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function createOrUpdate(Request $request)
|
public function createOrUpdate(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
DB::beginTransaction();
|
||||||
escolas::updateOrCreate([
|
|
||||||
'cnpj' => $request->cnpj,
|
try {
|
||||||
],[
|
|
||||||
|
$escola = Escola::updateOrCreate(
|
||||||
|
['cnpj' => $request->cnpj],
|
||||||
|
[
|
||||||
'nome' => $request->razaosocial,
|
'nome' => $request->razaosocial,
|
||||||
'endereco' => json_decode($request->address, true),
|
'endereco' => json_decode($request->address, true),
|
||||||
]);
|
]
|
||||||
return redirect()->route('escolas')->with('success', 'Escola Criada|Atualizada com sucesso');
|
);
|
||||||
} catch (\Throwable $th) {
|
|
||||||
dd($th);
|
if ($escola->wasRecentlyCreated) {
|
||||||
|
|
||||||
|
// 🔥 Limpa cache ANTES
|
||||||
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||||
|
|
||||||
|
// Define tenant (team)
|
||||||
|
setPermissionsTeamId($escola->id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ROLES (POR ESCOLA)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
$roles = [
|
||||||
|
'coordenacao',
|
||||||
|
'secretaria',
|
||||||
|
'responsavel',
|
||||||
|
'aluno',
|
||||||
|
'representante_de_turma',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($roles as $r) {
|
||||||
|
Role::firstOrCreate([
|
||||||
|
'name' => $r,
|
||||||
|
'guard_name' => 'web',
|
||||||
|
'id_escola' => $escola->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| PERMISSIONS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
$permissions = [
|
||||||
|
// escolas
|
||||||
|
'escolas.ver',
|
||||||
|
'escolas.criar',
|
||||||
|
'escolas.editar',
|
||||||
|
'escolas.deletar',
|
||||||
|
|
||||||
|
// turmas
|
||||||
|
'turmas.ver',
|
||||||
|
'turmas.detalhes',
|
||||||
|
'turmas.criar',
|
||||||
|
'turmas.editar',
|
||||||
|
'turmas.deletar',
|
||||||
|
|
||||||
|
// alunos
|
||||||
|
'alunos.ver_todos',
|
||||||
|
'alunos.ver_meus',
|
||||||
|
'alunos.criar',
|
||||||
|
'alunos.editar',
|
||||||
|
'alunos.deletar',
|
||||||
|
|
||||||
|
// whatsapp
|
||||||
|
'wpp.enviar',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($permissions as $p) {
|
||||||
|
Permission::firstOrCreate([
|
||||||
|
'name' => $p,
|
||||||
|
'guard_name' => 'web',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| MAPEAR ROLE -> PERMISSIONS (CORRIGIDO)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
$rolePermissions = [
|
||||||
|
|
||||||
|
// Coordenação: vê todos os alunos
|
||||||
|
'coordenacao' => [
|
||||||
|
'turmas.ver',
|
||||||
|
'turmas.detalhes',
|
||||||
|
'turmas.criar',
|
||||||
|
'turmas.editar',
|
||||||
|
'turmas.deletar',
|
||||||
|
|
||||||
|
'alunos.ver_todos',
|
||||||
|
'alunos.criar',
|
||||||
|
'alunos.editar',
|
||||||
|
'alunos.deletar',
|
||||||
|
|
||||||
|
'wpp.enviar',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Secretaria: vê todos os alunos
|
||||||
|
'secretaria' => [
|
||||||
|
'turmas.ver',
|
||||||
|
'turmas.detalhes',
|
||||||
|
|
||||||
|
'alunos.ver_todos',
|
||||||
|
'alunos.criar',
|
||||||
|
'alunos.editar',
|
||||||
|
|
||||||
|
'wpp.enviar',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Responsável: vê somente os "meus"
|
||||||
|
'responsavel' => [
|
||||||
|
'alunos.ver_meus',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Aluno: vê somente os "meus"
|
||||||
|
'aluno' => [
|
||||||
|
'alunos.ver_meus',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Representante: vê os "meus" + detalhes da turma (e wpp se você quiser)
|
||||||
|
'representante_de_turma' => [
|
||||||
|
'alunos.ver_meus',
|
||||||
|
'turmas.detalhes',
|
||||||
|
'wpp.enviar',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($rolePermissions as $roleName => $perms) {
|
||||||
|
|
||||||
|
$role = Role::query()
|
||||||
|
->where('name', $roleName)
|
||||||
|
->where('guard_name', 'web')
|
||||||
|
->where('id_escola', $escola->id)
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
$role->syncPermissions($perms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔥 Limpa cache DEPOIS
|
||||||
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||||
|
|
||||||
|
// opcional: volta contexto global
|
||||||
|
setPermissionsTeamId(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('escolas')
|
||||||
|
->with('success', 'Escola Criada|Atualizada com sucesso');
|
||||||
|
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
DB::rollBack();
|
||||||
|
throw $th;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\turmas;
|
use App\Models\Turma;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
@@ -11,21 +11,17 @@ class TurmasController extends Controller
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Auth::user()->id_escola == 0) {
|
$turmas = Turma::all();
|
||||||
$turmas = turmas::all();
|
|
||||||
} else {
|
|
||||||
$turmas = turmas::where('id_escola', Auth::user()->id_escola)->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('escolas.turmas', compact('turmas'));
|
return view('escolas.turmas', compact('turmas'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createOrUpdate(Request $request)
|
public function createOrUpdate(Request $request)
|
||||||
{
|
{
|
||||||
$turma = turmas::where('nome', '=', $request->turma_nome)->count();
|
$turma = Turma::where('nome', '=', $request->turma_nome)->count();
|
||||||
if ($turma == 0) {
|
if ($turma == 0) {
|
||||||
try {
|
try {
|
||||||
$turma = new turmas();
|
$turma = new Turma();
|
||||||
$turma->id_escola = $request->id_escola;
|
$turma->id_escola = $request->id_escola;
|
||||||
$turma->nome = $request->turma_nome;
|
$turma->nome = $request->turma_nome;
|
||||||
$turma->descricao = $request->turma_descricao;
|
$turma->descricao = $request->turma_descricao;
|
||||||
@@ -37,7 +33,7 @@ class TurmasController extends Controller
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
turmas::where('nome', $request->turma_nome)->update([
|
Turma::where('nome', $request->turma_nome)->update([
|
||||||
'nome' => $request->turma_nome,
|
'nome' => $request->turma_nome,
|
||||||
'descricao' => $request->turma_descricao,
|
'descricao' => $request->turma_descricao,
|
||||||
'id_escola' => $request->id_escola,
|
'id_escola' => $request->id_escola,
|
||||||
@@ -50,8 +46,31 @@ class TurmasController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function detalhes ($id) {
|
public function detalhes($id)
|
||||||
$turma = turmas::findOrFail($id);
|
{
|
||||||
return view('escolas.turmas_detalhes', compact('turma'));
|
$turma = Turma::findOrFail($id);
|
||||||
|
return view('escolas.Turma_detalhes', compact('turma'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function byEscola(Request $request, $escolaId)
|
||||||
|
{
|
||||||
|
// Se você tem multi-tenant e o usuário NÃO é super admin,
|
||||||
|
// é boa prática garantir que ele só consulte escola permitida.
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user->is_super_admin) {
|
||||||
|
// se você usa pivot user_escolas:
|
||||||
|
$allowed = $user->escolas()->where('escolas.id', $escolaId)->exists();
|
||||||
|
if (!$allowed) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$turmas = Turma::query()
|
||||||
|
->where('id_escola', $escolaId)
|
||||||
|
->orderBy('nome')
|
||||||
|
->get(['id', 'nome']);
|
||||||
|
|
||||||
|
return response()->json($turmas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
157
app/Http/Controllers/UsersController.php
Normal file
157
app/Http/Controllers/UsersController.php
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Escola;
|
||||||
|
use App\Models\Aluno;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
use Spatie\Permission\PermissionRegistrar;
|
||||||
|
|
||||||
|
|
||||||
|
class UsersController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$usuarios = User::all();
|
||||||
|
return view('usuarios.index', compact('usuarios'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function rolesByEscola(Request $request, $escolaId)
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user->is_super_admin) {
|
||||||
|
$allowed = $user->escolas()->where('escolas.id', $escolaId)->exists();
|
||||||
|
abort_if(!$allowed, 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// roles por escola
|
||||||
|
$roles = Role::query()
|
||||||
|
->where('id_escola', $escolaId)
|
||||||
|
->orderBy('name')
|
||||||
|
->get(['id', 'name']);
|
||||||
|
|
||||||
|
return response()->json($roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alunosByEscola(Request $request, $escolaId)
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user->is_super_admin) {
|
||||||
|
$allowed = $user->escolas()->where('escolas.id', $escolaId)->exists();
|
||||||
|
abort_if(!$allowed, 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// alunos por escola (sem global scope, se necessário)
|
||||||
|
$alunos = Aluno::query()
|
||||||
|
->withoutGlobalScope('escola') // se seu Aluno usa BelongsToEscola, isso evita filtrar errado
|
||||||
|
->where('id_escola', $escolaId)
|
||||||
|
->orderBy('nome')
|
||||||
|
->get(['id', 'nome']);
|
||||||
|
|
||||||
|
return response()->json($alunos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
// validação base
|
||||||
|
$data = $request->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
|
||||||
|
'password' => ['required', 'string', 'min:6', 'confirmed'],
|
||||||
|
|
||||||
|
'escola_id' => ['nullable', 'integer', 'exists:escolas,id'],
|
||||||
|
'role_name' => ['nullable', 'string'], // coordenacao/secretaria/responsavel/aluno/representante_de_turma
|
||||||
|
'is_super_admin' => ['nullable', 'boolean'],
|
||||||
|
|
||||||
|
// usado quando role for aluno/responsavel
|
||||||
|
'aluno_id' => ['nullable', 'integer', 'exists:alunos,id'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// super admin não precisa escola/role
|
||||||
|
$isSuper = (bool)($data['is_super_admin'] ?? false);
|
||||||
|
if ($isSuper) {
|
||||||
|
$data['escola_id'] = null;
|
||||||
|
$data['role_name'] = null;
|
||||||
|
$data['aluno_id'] = null;
|
||||||
|
} else {
|
||||||
|
// usuário comum precisa escola + role
|
||||||
|
if (empty($data['escola_id']) || empty($data['role_name'])) {
|
||||||
|
return back()->withErrors(['escola_id' => 'Selecione escola e cargo.'])->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se for responsável/aluno, aluno_id é obrigatório
|
||||||
|
if (!$isSuper && in_array($data['role_name'], ['responsavel', 'aluno'], true)) {
|
||||||
|
if (empty($data['aluno_id'])) {
|
||||||
|
return back()->withErrors(['aluno_id' => 'Selecione o aluno para vincular.'])->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// valida se o aluno pertence à escola selecionada
|
||||||
|
$ok = Aluno::query()
|
||||||
|
->withoutGlobalScope('escola')
|
||||||
|
->where('id', $data['aluno_id'])
|
||||||
|
->where('id_escola', $data['escola_id'])
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if (!$ok) {
|
||||||
|
return back()->withErrors(['aluno_id' => 'Aluno não pertence à escola selecionada.'])->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||||
|
|
||||||
|
// cria usuário
|
||||||
|
$user = User::create([
|
||||||
|
'name' => $data['name'],
|
||||||
|
'email' => $data['email'],
|
||||||
|
'password' => Hash::make($data['password']),
|
||||||
|
'is_super_admin' => $isSuper,
|
||||||
|
'current_escola_id' => $data['escola_id'] ?? null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// vincula à escola (pivot)
|
||||||
|
if (!$isSuper && $user->current_escola_id) {
|
||||||
|
$user->escolas()->syncWithoutDetaching([$user->current_escola_id]);
|
||||||
|
|
||||||
|
// seta team e atribui role da escola
|
||||||
|
setPermissionsTeamId($user->current_escola_id);
|
||||||
|
|
||||||
|
$role = Role::query()
|
||||||
|
->where('name', $data['role_name'])
|
||||||
|
->where('guard_name', 'web')
|
||||||
|
->where('id_escola', $user->current_escola_id)
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
$user->syncRoles([$role]);
|
||||||
|
|
||||||
|
// associações automáticas com aluno
|
||||||
|
if ($data['role_name'] === 'responsavel') {
|
||||||
|
Aluno::query()
|
||||||
|
->withoutGlobalScope('escola')
|
||||||
|
->where('id', $data['aluno_id'])
|
||||||
|
->update(['responsavel_user_id' => $user->id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data['role_name'] === 'aluno') {
|
||||||
|
Aluno::query()
|
||||||
|
->withoutGlobalScope('escola')
|
||||||
|
->where('id', $data['aluno_id'])
|
||||||
|
->update(['user_id' => $user->id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||||
|
setPermissionsTeamId(null);
|
||||||
|
|
||||||
|
return back()->with('success', 'Usuário criado com sucesso!');
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Http/Middleware/SetTenantMiddleware.php
Normal file
20
app/Http/Middleware/SetTenantMiddleware.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class SetTenantMiddleware
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if (auth()->check()) {
|
||||||
|
setPermissionsTeamId(auth()->user()->current_escola_id);
|
||||||
|
} else {
|
||||||
|
setPermissionsTeamId(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\configs;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use App\Models\turmas;
|
use App\Models\Turma;
|
||||||
use App\Models\envios_wpp;
|
use App\Models\envios_wpp;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@@ -38,7 +39,8 @@ class Envio_Mensagem_Whatsapp implements ShouldQueue
|
|||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$turma = turmas::findOrFail($this->idTurma);
|
$turma = Turma::findOrFail($this->idTurma);
|
||||||
|
$token = configs::where('nome', '=', 'wuzapi_token')->first();
|
||||||
$detalhes = [];
|
$detalhes = [];
|
||||||
|
|
||||||
|
|
||||||
@@ -99,7 +101,7 @@ class Envio_Mensagem_Whatsapp implements ShouldQueue
|
|||||||
case 'texto':
|
case 'texto':
|
||||||
$response = Http::withHeaders([
|
$response = Http::withHeaders([
|
||||||
'accept' => 'application/json',
|
'accept' => 'application/json',
|
||||||
'token' => '3aCSVE4jS9h233mNBr1awz3DF0In8CFk',
|
'token' => $token->valor,
|
||||||
])
|
])
|
||||||
->post('https://waha.cae.app.br/chat/send/text', [
|
->post('https://waha.cae.app.br/chat/send/text', [
|
||||||
'phone' => $turma->id_whatsapp,
|
'phone' => $turma->id_whatsapp,
|
||||||
@@ -177,7 +179,7 @@ class Envio_Mensagem_Whatsapp implements ShouldQueue
|
|||||||
case 'imagem';
|
case 'imagem';
|
||||||
$response = Http::withHeaders([
|
$response = Http::withHeaders([
|
||||||
'accept' => 'application/json',
|
'accept' => 'application/json',
|
||||||
'token' => '3aCSVE4jS9h233mNBr1awz3DF0In8CFk',
|
'token' => $token->valor,
|
||||||
])
|
])
|
||||||
->post('https://waha.cae.app.br/chat/send/image', [
|
->post('https://waha.cae.app.br/chat/send/image', [
|
||||||
'phone' => $turma->id_whatsapp,
|
'phone' => $turma->id_whatsapp,
|
||||||
|
|||||||
62
app/Models/Aluno.php
Normal file
62
app/Models/Aluno.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Traits\BelongsToEscola;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Aluno extends Model
|
||||||
|
{
|
||||||
|
use BelongsToEscola;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_escola',
|
||||||
|
'id_turma',
|
||||||
|
'nome',
|
||||||
|
'cpf',
|
||||||
|
'data_nascimento',
|
||||||
|
'data_inscricao',
|
||||||
|
'user_id', // usuário do aluno (portal), opcional
|
||||||
|
// 'responsavel_user_id' // ❌ removido (agora é pivot)
|
||||||
|
];
|
||||||
|
|
||||||
|
public function turma()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Turma::class,
|
||||||
|
'id_turma'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function escola()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Escola::class,
|
||||||
|
'id_escola'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usuário do aluno (se o aluno tiver login no portal)
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
User::class,
|
||||||
|
'user_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsáveis do aluno (N:N via pivot aluno_responsaveis)
|
||||||
|
*/
|
||||||
|
public function responsaveis()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(
|
||||||
|
User::class,
|
||||||
|
'aluno_responsaveis',
|
||||||
|
'aluno_id',
|
||||||
|
'user_id'
|
||||||
|
)->withTimestamps();
|
||||||
|
}
|
||||||
|
}
|
||||||
66
app/Models/Escola.php
Normal file
66
app/Models/Escola.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class Escola extends Model
|
||||||
|
{
|
||||||
|
protected $casts = [
|
||||||
|
'endereco' => 'array',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'cnpj',
|
||||||
|
'endereco',
|
||||||
|
'nome',
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| GLOBAL SCOPE MULTI-TENANT
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::addGlobalScope('user_escolas', function (Builder $builder) {
|
||||||
|
|
||||||
|
if (Auth::check() && !Auth::user()->is_super_admin) {
|
||||||
|
|
||||||
|
$builder->whereIn('id', function ($query) {
|
||||||
|
|
||||||
|
$query->select('escola_id')
|
||||||
|
->from('user_escolas')
|
||||||
|
->where('user_id', Auth::id());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| RELACIONAMENTOS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function turmas()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Turma::class, 'id_escola');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(
|
||||||
|
User::class,
|
||||||
|
'user_escolas',
|
||||||
|
'escola_id',
|
||||||
|
'user_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
app/Models/Traits/BelongsToEscola.php
Normal file
50
app/Models/Traits/BelongsToEscola.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Traits;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
trait BelongsToEscola
|
||||||
|
{
|
||||||
|
protected static function bootBelongsToEscola()
|
||||||
|
{
|
||||||
|
static::addGlobalScope('escola', function (Builder $builder) {
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
// Sem usuário logado: não filtra
|
||||||
|
if (!$user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Super admin: vê tudo (não filtra por escola)
|
||||||
|
if ($user->is_super_admin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usuário comum: filtra pela escola atual
|
||||||
|
if ($user->current_escola_id) {
|
||||||
|
$builder->where('id_escola', $user->current_escola_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static::creating(function ($model) {
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Super admin: não força id_escola automaticamente
|
||||||
|
if ($user->is_super_admin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se não veio id_escola, seta pela escola atual do usuário
|
||||||
|
if (!$model->id_escola) {
|
||||||
|
$model->id_escola = $user->current_escola_id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Models/Turma.php
Normal file
24
app/Models/Turma.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
use App\Models\Traits\BelongsToEscola;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Turma extends Model
|
||||||
|
{
|
||||||
|
use BelongsToEscola;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_escola',
|
||||||
|
'nome'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function escola()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Escola::class,
|
||||||
|
'id_escola'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,47 +2,131 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Spatie\Permission\Traits\HasRoles;
|
||||||
|
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
use HasRoles;
|
||||||
use HasFactory, Notifiable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
|
'is_super_admin',
|
||||||
|
'current_escola_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be hidden for serialization.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'password',
|
'password',
|
||||||
'remember_token',
|
'remember_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Get the attributes that should be cast.
|
|--------------------------------------------------------------------------
|
||||||
*
|
| RELACIONAMENTOS
|
||||||
* @return array<string, string>
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
protected function casts(): array
|
|
||||||
|
public function escolas()
|
||||||
{
|
{
|
||||||
return [
|
return $this->belongsToMany(
|
||||||
'email_verified_at' => 'datetime',
|
Escola::class,
|
||||||
'password' => 'hashed',
|
'user_escolas',
|
||||||
|
'user_id',
|
||||||
|
'escola_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function escolaAtual()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(
|
||||||
|
Escola::class,
|
||||||
|
'current_escola_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alunos pelos quais este usuário é responsável (N:N via pivot)
|
||||||
|
*/
|
||||||
|
public function alunosComoResponsavel()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(
|
||||||
|
Aluno::class,
|
||||||
|
'aluno_responsaveis',
|
||||||
|
'user_id',
|
||||||
|
'aluno_id'
|
||||||
|
)->withTimestamps();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Se você quiser acessar o "aluno" do próprio usuário (portal do aluno),
|
||||||
|
* dá pra ter 1:1 (um usuário pode ser o aluno).
|
||||||
|
*/
|
||||||
|
public function aluno()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Aluno::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| SUPER ADMIN
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function isSuperAdmin(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->is_super_admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| FUNÇÃO / CARGO DO USUÁRIO (ROLE)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function funcao(): ?string
|
||||||
|
{
|
||||||
|
if ($this->isSuperAdmin()) {
|
||||||
|
return 'Super Admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->current_escola_id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPermissionsTeamId($this->current_escola_id);
|
||||||
|
|
||||||
|
$role = $this->roles()->value('name');
|
||||||
|
|
||||||
|
if (!$role) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = [
|
||||||
|
'coordenacao' => 'Coordenação',
|
||||||
|
'secretaria' => 'Secretaria',
|
||||||
|
'responsavel' => 'Responsável',
|
||||||
|
'aluno' => 'Aluno',
|
||||||
|
'representante_de_turma' => 'Representante de Turma',
|
||||||
|
'super_admin' => 'Super Admin',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
return $map[$role] ?? ucfirst(str_replace('_', ' ', $role));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasFuncao(string $funcao): bool
|
||||||
|
{
|
||||||
|
if ($funcao === 'super_admin') {
|
||||||
|
return $this->isSuperAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->current_escola_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPermissionsTeamId($this->current_escola_id);
|
||||||
|
|
||||||
|
return $this->hasRole($funcao);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class alunos extends Model
|
|
||||||
{
|
|
||||||
public function turma()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(turmas::class, 'id_turma', 'id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function responsaveis() {
|
|
||||||
return $this->hasMany(User::class, 'id', 'id_responsavel');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
app/Models/configs.php
Normal file
10
app/Models/configs.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class configs extends Model
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class escolas extends Model
|
|
||||||
{
|
|
||||||
protected $casts = [
|
|
||||||
'endereco' => 'array',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'cnpj',
|
|
||||||
'endereco',
|
|
||||||
'nome',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function turmas()
|
|
||||||
{
|
|
||||||
return $this->hasMany(turmas::class, 'id_escola', 'id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class turmas extends Model
|
|
||||||
{
|
|
||||||
protected $fillable = [
|
|
||||||
'nome',
|
|
||||||
'descricao',
|
|
||||||
];
|
|
||||||
public function escola()
|
|
||||||
{
|
|
||||||
return $this->hasOne(escolas::class, 'id', 'id_escola');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function alunos()
|
|
||||||
{
|
|
||||||
return $this->hasMany(alunos::class, 'id', 'id_turma');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function enviosWpp() {
|
|
||||||
return $this->hasMany(envios_wpp::class, 'id_turma', 'id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,22 +3,20 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Register any application services.
|
|
||||||
*/
|
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstrap any application services.
|
|
||||||
*/
|
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
//
|
// 🔥 Super Admin ignora todas as permissões
|
||||||
|
Gate::before(function ($user, $ability) {
|
||||||
|
return $user->is_super_admin ? true : null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
use Illuminate\Foundation\Application;
|
use Illuminate\Foundation\Application;
|
||||||
use Illuminate\Foundation\Configuration\Exceptions;
|
use Illuminate\Foundation\Configuration\Exceptions;
|
||||||
use Illuminate\Foundation\Configuration\Middleware;
|
use Illuminate\Foundation\Configuration\Middleware;
|
||||||
|
use Sentry\Laravel\Integration;
|
||||||
|
|
||||||
return Application::configure(basePath: dirname(__DIR__))
|
return Application::configure(basePath: dirname(__DIR__))
|
||||||
->withRouting(
|
->withRouting(
|
||||||
@@ -11,8 +12,17 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
//
|
|
||||||
|
// Aliases do Spatie (atenção: namespace é Middleware, singular)
|
||||||
|
$middleware->alias([
|
||||||
|
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
|
||||||
|
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
|
||||||
|
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ✅ Setar o "team" (id_escola) automaticamente em toda request autenticada
|
||||||
|
$middleware->append(\App\Http\Middleware\SetTenantMiddleware::class);
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions): void {
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
//
|
Integration::handles($exceptions);
|
||||||
})->create();
|
})->create();
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
"laravel/breeze": "^2.3",
|
"laravel/breeze": "^2.3",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/horizon": "^5.44",
|
"laravel/horizon": "^5.44",
|
||||||
"laravel/tinker": "^2.10.1"
|
"laravel/tinker": "^2.10.1",
|
||||||
|
"league/flysystem-aws-s3-v3": "^3.31",
|
||||||
|
"sentry/sentry-laravel": "^4.20",
|
||||||
|
"spatie/laravel-permission": "^7.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.23",
|
"fakerphp/faker": "^1.23",
|
||||||
|
|||||||
967
composer.lock
generated
967
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ return [
|
|||||||
'public' => [
|
'public' => [
|
||||||
'driver' => 'local',
|
'driver' => 'local',
|
||||||
'root' => storage_path('app/public'),
|
'root' => storage_path('app/public'),
|
||||||
'url' => rtrim(env('APP_URL', 'http://localhost'), '/').'/storage',
|
'url' => rtrim(env('APP_URL', 'http://localhost'), '/') . '/storage',
|
||||||
'visibility' => 'public',
|
'visibility' => 'public',
|
||||||
'throw' => false,
|
'throw' => false,
|
||||||
'report' => false,
|
'report' => false,
|
||||||
@@ -51,13 +51,12 @@ return [
|
|||||||
'driver' => 's3',
|
'driver' => 's3',
|
||||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
'region' => env('AWS_DEFAULT_REGION'),
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||||
'bucket' => env('AWS_BUCKET'),
|
'bucket' => env('AWS_BUCKET'),
|
||||||
'url' => env('AWS_URL'),
|
'url' => env('AWS_URL'),
|
||||||
'endpoint' => env('AWS_ENDPOINT'),
|
'endpoint' => env('AWS_ENDPOINT'),
|
||||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true),
|
||||||
'throw' => false,
|
'throw' => false,
|
||||||
'report' => false,
|
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'channels' => [
|
'channels' => [
|
||||||
|
'sentry_logs' => [
|
||||||
|
'driver' => 'sentry_logs',
|
||||||
|
// The minimum logging level at which this handler will be triggered
|
||||||
|
// Available levels: debug, info, notice, warning, error, critical, alert, emergency
|
||||||
|
'level' => env('LOG_LEVEL', 'info'), // defaults to `debug` if not set
|
||||||
|
],
|
||||||
|
|
||||||
'stack' => [
|
'stack' => [
|
||||||
'driver' => 'stack',
|
'driver' => 'stack',
|
||||||
@@ -89,7 +95,7 @@ return [
|
|||||||
'handler_with' => [
|
'handler_with' => [
|
||||||
'host' => env('PAPERTRAIL_URL'),
|
'host' => env('PAPERTRAIL_URL'),
|
||||||
'port' => env('PAPERTRAIL_PORT'),
|
'port' => env('PAPERTRAIL_PORT'),
|
||||||
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
|
'connectionString' => 'tls://' . env('PAPERTRAIL_URL') . ':' . env('PAPERTRAIL_PORT'),
|
||||||
],
|
],
|
||||||
'processors' => [PsrLogMessageProcessor::class],
|
'processors' => [PsrLogMessageProcessor::class],
|
||||||
],
|
],
|
||||||
|
|||||||
202
config/permission.php
Normal file
202
config/permission.php
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'models' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasPermissions" trait from this package, we need to know which
|
||||||
|
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||||
|
* is often just the "Permission" model but you may use whatever you like.
|
||||||
|
*
|
||||||
|
* The model you want to use as a Permission model needs to implement the
|
||||||
|
* `Spatie\Permission\Contracts\Permission` contract.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'permission' => Spatie\Permission\Models\Permission::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasRoles" trait from this package, we need to know which
|
||||||
|
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||||
|
* is often just the "Role" model but you may use whatever you like.
|
||||||
|
*
|
||||||
|
* The model you want to use as a Role model needs to implement the
|
||||||
|
* `Spatie\Permission\Contracts\Role` contract.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'role' => Spatie\Permission\Models\Role::class,
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
'table_names' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasRoles" trait from this package, we need to know which
|
||||||
|
* table should be used to retrieve your roles. We have chosen a basic
|
||||||
|
* default value but you may easily change it to any table you like.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'roles' => 'roles',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasPermissions" trait from this package, we need to know which
|
||||||
|
* table should be used to retrieve your permissions. We have chosen a basic
|
||||||
|
* default value but you may easily change it to any table you like.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'permissions' => 'permissions',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasPermissions" trait from this package, we need to know which
|
||||||
|
* table should be used to retrieve your models permissions. We have chosen a
|
||||||
|
* basic default value but you may easily change it to any table you like.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'model_has_permissions' => 'model_has_permissions',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasRoles" trait from this package, we need to know which
|
||||||
|
* table should be used to retrieve your models roles. We have chosen a
|
||||||
|
* basic default value but you may easily change it to any table you like.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'model_has_roles' => 'model_has_roles',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When using the "HasRoles" trait from this package, we need to know which
|
||||||
|
* table should be used to retrieve your roles permissions. We have chosen a
|
||||||
|
* basic default value but you may easily change it to any table you like.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'role_has_permissions' => 'role_has_permissions',
|
||||||
|
],
|
||||||
|
|
||||||
|
'column_names' => [
|
||||||
|
/*
|
||||||
|
* Change this if you want to name the related pivots other than defaults
|
||||||
|
*/
|
||||||
|
'role_pivot_key' => null, // default 'role_id',
|
||||||
|
'permission_pivot_key' => null, // default 'permission_id',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change this if you want to name the related model primary key other than
|
||||||
|
* `model_id`.
|
||||||
|
*
|
||||||
|
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||||
|
* that case, name this `model_uuid`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'model_morph_key' => 'model_id',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change this if you want to use the teams feature and your related model's
|
||||||
|
* foreign key is other than `team_id`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'team_foreign_key' => 'id_escola',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When set to true, the method for checking permissions will be registered on the gate.
|
||||||
|
* Set this to false if you want to implement custom logic for checking permissions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'register_permission_check_method' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
|
||||||
|
* this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
|
||||||
|
* NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
|
||||||
|
*/
|
||||||
|
'register_octane_reset_listener' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Events will fire when a role or permission is assigned/unassigned:
|
||||||
|
* \Spatie\Permission\Events\RoleAttached
|
||||||
|
* \Spatie\Permission\Events\RoleDetached
|
||||||
|
* \Spatie\Permission\Events\PermissionAttached
|
||||||
|
* \Spatie\Permission\Events\PermissionDetached
|
||||||
|
*
|
||||||
|
* To enable, set to true, and then create listeners to watch these events.
|
||||||
|
*/
|
||||||
|
'events_enabled' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Teams Feature.
|
||||||
|
* When set to true the package implements teams using the 'team_foreign_key'.
|
||||||
|
* If you want the migrations to register the 'team_foreign_key', you must
|
||||||
|
* set this to true before doing the migration.
|
||||||
|
* If you already did the migration then you must make a new migration to also
|
||||||
|
* add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
|
||||||
|
* (view the latest version of this package's migration file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
'teams' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The class to use to resolve the permissions team id
|
||||||
|
*/
|
||||||
|
'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Passport Client Credentials Grant
|
||||||
|
* When set to true the package will use Passports Client to check permissions
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use_passport_client_credentials' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When set to true, the required permission names are added to exception messages.
|
||||||
|
* This could be considered an information leak in some contexts, so the default
|
||||||
|
* setting is false here for optimum safety.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'display_permission_in_exception' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When set to true, the required role names are added to exception messages.
|
||||||
|
* This could be considered an information leak in some contexts, so the default
|
||||||
|
* setting is false here for optimum safety.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'display_role_in_exception' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* By default wildcard permission lookups are disabled.
|
||||||
|
* See documentation to understand supported syntax.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'enable_wildcard_permission' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The class to use for interpreting wildcard permissions.
|
||||||
|
* If you need to modify delimiters, override the class and specify its name here.
|
||||||
|
*/
|
||||||
|
// 'wildcard_permission' => Spatie\Permission\WildcardPermission::class,
|
||||||
|
|
||||||
|
/* Cache-specific settings */
|
||||||
|
|
||||||
|
'cache' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
* By default all permissions are cached for 24 hours to speed up performance.
|
||||||
|
* When permissions or roles are updated the cache is flushed automatically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cache key used to store all permissions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'key' => 'spatie.permission.cache',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You may optionally indicate a specific cache driver to use for permission and
|
||||||
|
* role caching using any of the `store` drivers listed in the cache.php config
|
||||||
|
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'store' => 'default',
|
||||||
|
],
|
||||||
|
];
|
||||||
135
config/sentry.php
Normal file
135
config/sentry.php
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sentry Laravel SDK configuration file.
|
||||||
|
*
|
||||||
|
* @see https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
|
||||||
|
// @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
||||||
|
'dsn' => env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
|
||||||
|
|
||||||
|
// @see https://spotlightjs.com/
|
||||||
|
// 'spotlight' => env('SENTRY_SPOTLIGHT', false),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#logger
|
||||||
|
// 'logger' => Sentry\Logger\DebugFileLogger::class, // By default this will log to `storage_path('logs/sentry.log')`
|
||||||
|
|
||||||
|
// The release version of your application
|
||||||
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
|
'release' => env('SENTRY_RELEASE'),
|
||||||
|
|
||||||
|
// When left empty or `null` the Laravel environment will be used (usually discovered from `APP_ENV` in your `.env`)
|
||||||
|
'environment' => env('SENTRY_ENVIRONMENT'),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#sample_rate
|
||||||
|
'sample_rate' => env('SENTRY_SAMPLE_RATE') === null ? 1.0 : (float) env('SENTRY_SAMPLE_RATE'),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces_sample_rate
|
||||||
|
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_TRACES_SAMPLE_RATE'),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#profiles-sample-rate
|
||||||
|
'profiles_sample_rate' => env('SENTRY_PROFILES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_PROFILES_SAMPLE_RATE'),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#enable_logs
|
||||||
|
'enable_logs' => env('SENTRY_ENABLE_LOGS', false),
|
||||||
|
|
||||||
|
// The minimum log level that will be sent to Sentry as logs using the `sentry_logs` logging channel
|
||||||
|
'logs_channel_level' => env('SENTRY_LOG_LEVEL', env('SENTRY_LOGS_LEVEL', env('LOG_LEVEL', 'debug'))),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send_default_pii
|
||||||
|
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore_exceptions
|
||||||
|
// 'ignore_exceptions' => [],
|
||||||
|
|
||||||
|
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore_transactions
|
||||||
|
'ignore_transactions' => [
|
||||||
|
// Ignore Laravel's default health URL
|
||||||
|
'/up',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Breadcrumb specific configuration
|
||||||
|
'breadcrumbs' => [
|
||||||
|
// Capture Laravel logs as breadcrumbs
|
||||||
|
'logs' => env('SENTRY_BREADCRUMBS_LOGS_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture Laravel cache events (hits, writes etc.) as breadcrumbs
|
||||||
|
'cache' => env('SENTRY_BREADCRUMBS_CACHE_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture Livewire components like routes as breadcrumbs
|
||||||
|
'livewire' => env('SENTRY_BREADCRUMBS_LIVEWIRE_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture SQL queries as breadcrumbs
|
||||||
|
'sql_queries' => env('SENTRY_BREADCRUMBS_SQL_QUERIES_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture SQL query bindings (parameters) in SQL query breadcrumbs
|
||||||
|
'sql_bindings' => env('SENTRY_BREADCRUMBS_SQL_BINDINGS_ENABLED', false),
|
||||||
|
|
||||||
|
// Capture queue job information as breadcrumbs
|
||||||
|
'queue_info' => env('SENTRY_BREADCRUMBS_QUEUE_INFO_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture command information as breadcrumbs
|
||||||
|
'command_info' => env('SENTRY_BREADCRUMBS_COMMAND_JOBS_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture HTTP client request information as breadcrumbs
|
||||||
|
'http_client_requests' => env('SENTRY_BREADCRUMBS_HTTP_CLIENT_REQUESTS_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture send notifications as breadcrumbs
|
||||||
|
'notifications' => env('SENTRY_BREADCRUMBS_NOTIFICATIONS_ENABLED', true),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Performance monitoring specific configuration
|
||||||
|
'tracing' => [
|
||||||
|
// Trace queue jobs as their own transactions (this enables tracing for queue jobs)
|
||||||
|
'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture queue jobs as spans when executed on the sync driver
|
||||||
|
'queue_jobs' => env('SENTRY_TRACE_QUEUE_JOBS_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture SQL queries as spans
|
||||||
|
'sql_queries' => env('SENTRY_TRACE_SQL_QUERIES_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture SQL query bindings (parameters) in SQL query spans
|
||||||
|
'sql_bindings' => env('SENTRY_TRACE_SQL_BINDINGS_ENABLED', false),
|
||||||
|
|
||||||
|
// Capture where the SQL query originated from on the SQL query spans
|
||||||
|
'sql_origin' => env('SENTRY_TRACE_SQL_ORIGIN_ENABLED', true),
|
||||||
|
|
||||||
|
// Define a threshold in milliseconds for SQL queries to resolve their origin
|
||||||
|
'sql_origin_threshold_ms' => env('SENTRY_TRACE_SQL_ORIGIN_THRESHOLD_MS', 100),
|
||||||
|
|
||||||
|
// Capture views rendered as spans
|
||||||
|
'views' => env('SENTRY_TRACE_VIEWS_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture Livewire components as spans
|
||||||
|
'livewire' => env('SENTRY_TRACE_LIVEWIRE_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture HTTP client requests as spans
|
||||||
|
'http_client_requests' => env('SENTRY_TRACE_HTTP_CLIENT_REQUESTS_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture Laravel cache events (hits, writes etc.) as spans
|
||||||
|
'cache' => env('SENTRY_TRACE_CACHE_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture Redis operations as spans (this enables Redis events in Laravel)
|
||||||
|
'redis_commands' => env('SENTRY_TRACE_REDIS_COMMANDS', false),
|
||||||
|
|
||||||
|
// Capture where the Redis command originated from on the Redis command spans
|
||||||
|
'redis_origin' => env('SENTRY_TRACE_REDIS_ORIGIN_ENABLED', true),
|
||||||
|
|
||||||
|
// Capture send notifications as spans
|
||||||
|
'notifications' => env('SENTRY_TRACE_NOTIFICATIONS_ENABLED', true),
|
||||||
|
|
||||||
|
// Enable tracing for requests without a matching route (404's)
|
||||||
|
'missing_routes' => env('SENTRY_TRACE_MISSING_ROUTES_ENABLED', false),
|
||||||
|
|
||||||
|
// Configures if the performance trace should continue after the response has been sent to the user until the application terminates
|
||||||
|
// This is required to capture any spans that are created after the response has been sent like queue jobs dispatched using `dispatch(...)->afterResponse()` for example
|
||||||
|
'continue_after_response' => env('SENTRY_TRACE_CONTINUE_AFTER_RESPONSE', true),
|
||||||
|
|
||||||
|
// Enable the tracing integrations supplied by Sentry (recommended)
|
||||||
|
'default_integrations' => env('SENTRY_TRACE_DEFAULT_INTEGRATIONS_ENABLED', true),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// apagar tabelas antigas
|
||||||
|
Schema::dropIfExists('model_has_permissions');
|
||||||
|
Schema::dropIfExists('model_has_roles');
|
||||||
|
Schema::dropIfExists('role_has_permissions');
|
||||||
|
Schema::dropIfExists('permissions');
|
||||||
|
Schema::dropIfExists('roles');
|
||||||
|
|
||||||
|
Schema::dropIfExists('alunos');
|
||||||
|
Schema::dropIfExists('turmas');
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
Schema::dropIfExists('escolas');
|
||||||
|
|
||||||
|
// escolas
|
||||||
|
Schema::create('escolas', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('cnpj', 18)->unique();
|
||||||
|
|
||||||
|
$table->string('nome');
|
||||||
|
|
||||||
|
$table->string('endereco')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// users
|
||||||
|
Schema::create('users', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('id_escola')
|
||||||
|
->nullable()
|
||||||
|
->constrained('escolas')
|
||||||
|
->nullOnDelete();
|
||||||
|
|
||||||
|
$table->string('name');
|
||||||
|
|
||||||
|
$table->string('email')->unique();
|
||||||
|
|
||||||
|
$table->string('password');
|
||||||
|
|
||||||
|
$table->boolean('is_super_admin')->default(false);
|
||||||
|
|
||||||
|
$table->rememberToken();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// turmas
|
||||||
|
Schema::create('turmas', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('id_escola')
|
||||||
|
->constrained('escolas')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->string('nome');
|
||||||
|
|
||||||
|
$table->text('descricao')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// alunos
|
||||||
|
Schema::create('alunos', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('id_escola')
|
||||||
|
->constrained('escolas')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->foreignId('id_turma')
|
||||||
|
->constrained('turmas')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->string('nome');
|
||||||
|
|
||||||
|
$table->string('cpf', 14)->nullable();
|
||||||
|
|
||||||
|
$table->date('data_nascimento')->nullable();
|
||||||
|
|
||||||
|
$table->date('data_inscricao')->nullable();
|
||||||
|
|
||||||
|
$table->date('data_encerramento')->nullable();
|
||||||
|
|
||||||
|
$table->string('endereco')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('alunos');
|
||||||
|
Schema::dropIfExists('turmas');
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
Schema::dropIfExists('escolas');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$teams = config('permission.teams');
|
||||||
|
$tableNames = config('permission.table_names');
|
||||||
|
$columnNames = config('permission.column_names');
|
||||||
|
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||||
|
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||||
|
$teamKey = $columnNames['team_foreign_key'];
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| PERMISSIONS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create($tableNames['permissions'], function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('guard_name');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['name', 'guard_name']);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ROLES
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $teamKey) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
if ($teams) {
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($teamKey)
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->index($teamKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->string('name');
|
||||||
|
|
||||||
|
$table->string('guard_name');
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
if ($teams) {
|
||||||
|
|
||||||
|
$table->unique([$teamKey, 'name', 'guard_name']);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$table->unique(['name', 'guard_name']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| MODEL HAS PERMISSIONS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table)
|
||||||
|
use ($tableNames, $columnNames, $pivotPermission, $teams, $teamKey)
|
||||||
|
{
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($pivotPermission);
|
||||||
|
|
||||||
|
$table->string('model_type');
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||||
|
|
||||||
|
if ($teams) {
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($teamKey)
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->index($teamKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->foreign($pivotPermission)
|
||||||
|
->references('id')
|
||||||
|
->on($tableNames['permissions'])
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
// primary SEM team_key
|
||||||
|
$table->primary([
|
||||||
|
$pivotPermission,
|
||||||
|
$columnNames['model_morph_key'],
|
||||||
|
'model_type'
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| MODEL HAS ROLES
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create($tableNames['model_has_roles'], function (Blueprint $table)
|
||||||
|
use ($tableNames, $columnNames, $pivotRole, $teams, $teamKey)
|
||||||
|
{
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($pivotRole);
|
||||||
|
|
||||||
|
$table->string('model_type');
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||||
|
|
||||||
|
if ($teams) {
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($teamKey)
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->index($teamKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$table->foreign($pivotRole)
|
||||||
|
->references('id')
|
||||||
|
->on($tableNames['roles'])
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
// primary SEM team_key
|
||||||
|
$table->primary([
|
||||||
|
$pivotRole,
|
||||||
|
$columnNames['model_morph_key'],
|
||||||
|
'model_type'
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| ROLE HAS PERMISSIONS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table)
|
||||||
|
use ($tableNames, $pivotRole, $pivotPermission)
|
||||||
|
{
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($pivotPermission);
|
||||||
|
|
||||||
|
$table->unsignedBigInteger($pivotRole);
|
||||||
|
|
||||||
|
$table->foreign($pivotPermission)
|
||||||
|
->references('id')
|
||||||
|
->on($tableNames['permissions'])
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->foreign($pivotRole)
|
||||||
|
->references('id')
|
||||||
|
->on($tableNames['roles'])
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->primary([
|
||||||
|
$pivotPermission,
|
||||||
|
$pivotRole
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app('cache')
|
||||||
|
->store(config('permission.cache.store') != 'default'
|
||||||
|
? config('permission.cache.store')
|
||||||
|
: null)
|
||||||
|
->forget(config('permission.cache.key'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$tableNames = config('permission.table_names');
|
||||||
|
|
||||||
|
Schema::dropIfExists($tableNames['role_has_permissions']);
|
||||||
|
Schema::dropIfExists($tableNames['model_has_roles']);
|
||||||
|
Schema::dropIfExists($tableNames['model_has_permissions']);
|
||||||
|
Schema::dropIfExists($tableNames['roles']);
|
||||||
|
Schema::dropIfExists($tableNames['permissions']);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('user_escolas', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('user_id')
|
||||||
|
->constrained()
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->foreignId('escola_id')
|
||||||
|
->constrained()
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_escolas');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->dropConstrainedForeignId('id_escola');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->foreignId('current_escola_id')
|
||||||
|
->nullable()
|
||||||
|
->constrained('escolas');
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| APAGAR TODAS AS TABELAS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::disableForeignKeyConstraints();
|
||||||
|
|
||||||
|
Schema::dropIfExists('alunos');
|
||||||
|
Schema::dropIfExists('turmas');
|
||||||
|
Schema::dropIfExists('user_escolas');
|
||||||
|
Schema::dropIfExists('escolas');
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
|
||||||
|
Schema::enableForeignKeyConstraints();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CRIAR TABELA ESCOLAS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create('escolas', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('cnpj')->unique();
|
||||||
|
|
||||||
|
$table->string('nome');
|
||||||
|
|
||||||
|
$table->json('endereco')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CRIAR USERS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create('users', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('name');
|
||||||
|
|
||||||
|
$table->string('email')->unique();
|
||||||
|
|
||||||
|
$table->string('password');
|
||||||
|
|
||||||
|
$table->boolean('is_super_admin')
|
||||||
|
->default(false);
|
||||||
|
|
||||||
|
$table->foreignId('current_escola_id')
|
||||||
|
->nullable()
|
||||||
|
->constrained('escolas')
|
||||||
|
->nullOnDelete();
|
||||||
|
|
||||||
|
$table->rememberToken();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TABELA PIVOT USER_ESCOLAS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create('user_escolas', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('user_id')
|
||||||
|
->constrained()
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->foreignId('escola_id')
|
||||||
|
->constrained()
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TABELA TURMAS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create('turmas', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('id_escola')
|
||||||
|
->constrained('escolas')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->string('nome');
|
||||||
|
|
||||||
|
$table->text('descricao')
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| TABELA ALUNOS
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Schema::create('alunos', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('id_escola')
|
||||||
|
->constrained('escolas')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->foreignId('id_turma')
|
||||||
|
->constrained('turmas')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->string('nome');
|
||||||
|
|
||||||
|
$table->string('cpf')
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->date('data_nascimento')
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->date('data_inscricao')
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->date('data_encerramento')
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->json('endereco')
|
||||||
|
->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
Schema::disableForeignKeyConstraints();
|
||||||
|
|
||||||
|
Schema::dropIfExists('alunos');
|
||||||
|
Schema::dropIfExists('turmas');
|
||||||
|
Schema::dropIfExists('user_escolas');
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
Schema::dropIfExists('escolas');
|
||||||
|
|
||||||
|
Schema::enableForeignKeyConstraints();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
28
database/migrations/2026_02_18_141220_add_wpp_turmas.php
Normal file
28
database/migrations/2026_02_18_141220_add_wpp_turmas.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('turmas', function (Blueprint $table) {
|
||||||
|
$table->string('id_whatsapp')->unique()->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('turmas', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('configs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nome')->unique();
|
||||||
|
$table->string('valor')->unique();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('configs');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('alunos', function (Blueprint $table) {
|
||||||
|
|
||||||
|
$table->foreignId('user_id')
|
||||||
|
->nullable()
|
||||||
|
->after('id_turma')
|
||||||
|
->constrained('users')
|
||||||
|
->nullOnDelete();
|
||||||
|
|
||||||
|
$table->foreignId('responsavel_user_id')
|
||||||
|
->nullable()
|
||||||
|
->after('user_id')
|
||||||
|
->constrained('users')
|
||||||
|
->nullOnDelete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('alunos', function (Blueprint $table) {
|
||||||
|
$table->dropConstrainedForeignId('responsavel_user_id');
|
||||||
|
$table->dropConstrainedForeignId('user_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('aluno_responsaveis', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->foreignId('aluno_id')
|
||||||
|
->constrained('alunos')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->foreignId('user_id') // responsável (users)
|
||||||
|
->constrained('users')
|
||||||
|
->cascadeOnDelete();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
// impede duplicar o mesmo responsável no mesmo aluno
|
||||||
|
$table->unique(['aluno_id', 'user_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('aluno_responsaveis');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('alunos', function (Blueprint $table) {
|
||||||
|
$table->dropConstrainedForeignId('responsavel_user_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('alunos', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
57
database/seeders/InitialSeeder.php
Normal file
57
database/seeders/InitialSeeder.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use App\Models\User;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
use Spatie\Permission\PermissionRegistrar;
|
||||||
|
|
||||||
|
class InitialSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// Limpa cache do Spatie
|
||||||
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||||
|
|
||||||
|
// Garante contexto GLOBAL (team = null)
|
||||||
|
setPermissionsTeamId(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1) CRIA ROLE GLOBAL super_admin (id_escola = NULL)
|
||||||
|
* OBS: como você está com teams/id_escola, deixamos explícito.
|
||||||
|
*/
|
||||||
|
$role = Role::firstOrCreate([
|
||||||
|
'name' => 'super_admin',
|
||||||
|
'guard_name' => 'web',
|
||||||
|
'id_escola' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2) CRIA USUÁRIO SUPER ADMIN
|
||||||
|
*/
|
||||||
|
$user = User::firstOrCreate(
|
||||||
|
['email' => 'admin@admin.com'],
|
||||||
|
[
|
||||||
|
'name' => 'Super Admin',
|
||||||
|
'password' => bcrypt('123456'),
|
||||||
|
'is_super_admin' => true,
|
||||||
|
'current_escola_id' => null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3) ATRIBUI A ROLE (GLOBAL) AO USUÁRIO
|
||||||
|
* Garante team = null novamente antes de gravar pivot.
|
||||||
|
*/
|
||||||
|
setPermissionsTeamId(null);
|
||||||
|
$user->syncRoles([$role]);
|
||||||
|
|
||||||
|
// Limpa cache de novo por segurança
|
||||||
|
app(PermissionRegistrar::class)->forgetCachedPermissions();
|
||||||
|
|
||||||
|
$this->command->info('Super Admin + role super_admin criados e associados com sucesso!');
|
||||||
|
$this->command->info('Email: admin@admin.com');
|
||||||
|
$this->command->info('Senha: 123456');
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/assets/images/user-card/banner_user.png
Normal file
BIN
public/assets/images/user-card/banner_user.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 MiB |
215
python.py
Normal file
215
python.py
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
from reportlab.lib import colors
|
||||||
|
from reportlab.lib.pagesizes import A4, landscape
|
||||||
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||||
|
from reportlab.lib.units import cm
|
||||||
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak
|
||||||
|
from reportlab.lib.enums import TA_CENTER, TA_LEFT
|
||||||
|
|
||||||
|
# 1. Configuração do Arquivo
|
||||||
|
pdf_filename = "Apresentacao_Executiva_FGCOOP.pdf"
|
||||||
|
doc = SimpleDocTemplate(pdf_filename, pagesize=landscape(A4),
|
||||||
|
rightMargin=1*cm, leftMargin=1*cm,
|
||||||
|
topMargin=3.5*cm, bottomMargin=1.5*cm)
|
||||||
|
|
||||||
|
# 2. Estilos
|
||||||
|
styles = getSampleStyleSheet()
|
||||||
|
|
||||||
|
# Estilo de Título do Slide
|
||||||
|
style_slide_title = ParagraphStyle(
|
||||||
|
'SlideTitle',
|
||||||
|
parent=styles['Heading1'],
|
||||||
|
fontSize=24,
|
||||||
|
textColor=colors.HexColor("#003366"), # Azul Corporativo
|
||||||
|
spaceAfter=20,
|
||||||
|
alignment=TA_LEFT
|
||||||
|
)
|
||||||
|
|
||||||
|
# Estilo de Corpo do Slide
|
||||||
|
style_body = ParagraphStyle(
|
||||||
|
'SlideBody',
|
||||||
|
parent=styles['Normal'],
|
||||||
|
fontSize=14,
|
||||||
|
leading=18,
|
||||||
|
spaceAfter=12,
|
||||||
|
textColor=colors.HexColor("#333333")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Estilo de Bullet Point
|
||||||
|
style_bullet = ParagraphStyle(
|
||||||
|
'SlideBullet',
|
||||||
|
parent=style_body,
|
||||||
|
leftIndent=20,
|
||||||
|
bulletIndent=10,
|
||||||
|
firstLineIndent=0,
|
||||||
|
spaceAfter=8
|
||||||
|
)
|
||||||
|
|
||||||
|
# Estilo da Capa (Título Gigante)
|
||||||
|
style_cover_title = ParagraphStyle(
|
||||||
|
'CoverTitle',
|
||||||
|
parent=styles['Title'],
|
||||||
|
fontSize=36,
|
||||||
|
textColor=colors.white,
|
||||||
|
alignment=TA_CENTER,
|
||||||
|
spaceAfter=20,
|
||||||
|
leading=40
|
||||||
|
)
|
||||||
|
|
||||||
|
style_cover_sub = ParagraphStyle(
|
||||||
|
'CoverSub',
|
||||||
|
parent=styles['Normal'],
|
||||||
|
fontSize=18,
|
||||||
|
textColor=colors.lightgrey,
|
||||||
|
alignment=TA_CENTER
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. Funções de Layout (Background)
|
||||||
|
|
||||||
|
def draw_background(canvas, doc):
|
||||||
|
""" Fundo padrão dos slides (Barra azul no topo e rodapé) """
|
||||||
|
width, height = landscape(A4)
|
||||||
|
|
||||||
|
# Faixa Azul no Topo
|
||||||
|
canvas.saveState()
|
||||||
|
canvas.setFillColor(colors.HexColor("#003366"))
|
||||||
|
canvas.rect(0, height - 2.5*cm, width, 2.5*cm, fill=1, stroke=0)
|
||||||
|
|
||||||
|
# Texto do Header (na faixa azul)
|
||||||
|
canvas.setFont("Helvetica-Bold", 16)
|
||||||
|
canvas.setFillColor(colors.white)
|
||||||
|
canvas.drawString(1*cm, height - 1.8*cm, "CLOUD ESSENTIAL | Assessment de Segurança")
|
||||||
|
|
||||||
|
# Rodapé
|
||||||
|
canvas.setStrokeColor(colors.HexColor("#CCCCCC"))
|
||||||
|
canvas.setLineWidth(1)
|
||||||
|
canvas.line(1*cm, 1*cm, width-1*cm, 1*cm)
|
||||||
|
|
||||||
|
# Texto do Rodapé
|
||||||
|
canvas.setFont("Helvetica", 10)
|
||||||
|
canvas.setFillColor(colors.gray)
|
||||||
|
canvas.drawString(1*cm, 0.5*cm, "Cliente: FGCOOP")
|
||||||
|
page_num = canvas.getPageNumber()
|
||||||
|
canvas.drawRightString(width-1*cm, 0.5*cm, f"Slide {page_num}")
|
||||||
|
|
||||||
|
canvas.restoreState()
|
||||||
|
|
||||||
|
def draw_cover_background(canvas, doc):
|
||||||
|
""" Fundo exclusivo da capa (Azul Total) """
|
||||||
|
width, height = landscape(A4)
|
||||||
|
canvas.saveState()
|
||||||
|
|
||||||
|
# Fundo Azul Sólido
|
||||||
|
canvas.setFillColor(colors.HexColor("#003366"))
|
||||||
|
canvas.rect(0, 0, width, height, fill=1, stroke=0)
|
||||||
|
|
||||||
|
# Elemento decorativo (Círculo sutil)
|
||||||
|
canvas.setFillColor(colors.HexColor("#004080"))
|
||||||
|
canvas.circle(width/2, height/2, 12*cm, fill=1, stroke=0)
|
||||||
|
|
||||||
|
# Logo simulado no centro inferior
|
||||||
|
canvas.setFont("Helvetica-Bold", 14)
|
||||||
|
canvas.setFillColor(colors.white)
|
||||||
|
canvas.drawCentredString(width/2, 2*cm, "CLOUD ESSENTIAL TECH")
|
||||||
|
|
||||||
|
canvas.restoreState()
|
||||||
|
|
||||||
|
# 4. Construção do Conteúdo (Story)
|
||||||
|
story = []
|
||||||
|
|
||||||
|
# --- SLIDE 1: CAPA ---
|
||||||
|
story.append(Spacer(1, 4*cm))
|
||||||
|
story.append(Paragraph("Assessment de Infraestrutura<br/>& Segurança Microsoft", style_cover_title))
|
||||||
|
story.append(Spacer(1, 1.5*cm))
|
||||||
|
story.append(Paragraph("<b>Cliente:</b> FGCOOP", style_cover_sub))
|
||||||
|
story.append(Paragraph("Janeiro 2026", style_cover_sub))
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- SLIDE 2: RESUMO EXECUTIVO ---
|
||||||
|
story.append(Paragraph("Resumo Executivo", style_slide_title))
|
||||||
|
|
||||||
|
# Texto com destaque
|
||||||
|
story.append(Paragraph("<b>1. Visão Geral:</b> Avaliação técnica dos ambientes On-Premises, Azure e M365 realizada em 19/01/2026.", style_body))
|
||||||
|
story.append(Paragraph("<b>2. Ponto Forte (Cloud):</b> O ambiente possui um <b>Microsoft Secure Score de 82,13%</b>, superior à média de mercado (43%), indicando excelente maturidade em nuvem.", style_body))
|
||||||
|
story.append(Paragraph("<b>3. Ponto de Atenção (On-Prem):</b> A infraestrutura local (AD e Servidores) apresenta riscos críticos que podem comprometer a segurança da nuvem se não tratados.", style_body))
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- SLIDE 3: OTIMIZAÇÃO FINANCEIRA ---
|
||||||
|
story.append(Paragraph("Otimização de Custos (Licenciamento)", style_slide_title))
|
||||||
|
story.append(Paragraph("Identificamos licenças ativas sem uso ou subutilizadas. Ação imediata recomendada:", style_body))
|
||||||
|
|
||||||
|
data_cost = [
|
||||||
|
['Produto / Licença', 'Situação Identificada', 'Recomendação'],
|
||||||
|
['Microsoft 365 Business Basic', '44 Licenças não utilizadas', 'Cancelar ou realocar'],
|
||||||
|
['Power BI Premium', 'Subutilização de recursos', 'Downgrade para versão Pro'],
|
||||||
|
['Licenças F1', 'Baixo consumo', 'Revisar necessidade']
|
||||||
|
]
|
||||||
|
|
||||||
|
t_cost = Table(data_cost, colWidths=[7*cm, 8*cm, 8*cm])
|
||||||
|
t_cost.setStyle(TableStyle([
|
||||||
|
('BACKGROUND', (0,0), (-1,0), colors.HexColor("#004080")),
|
||||||
|
('TEXTCOLOR', (0,0), (-1,0), colors.white),
|
||||||
|
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
|
||||||
|
('BOTTOMPADDING', (0,0), (-1,0), 12),
|
||||||
|
('BACKGROUND', (0,1), (-1,-1), colors.whitesmoke),
|
||||||
|
('GRID', (0,0), (-1,-1), 1, colors.white),
|
||||||
|
('ALIGN', (0,0), (-1,-1), 'LEFT'),
|
||||||
|
('PADDING', (0,0), (-1,-1), 8),
|
||||||
|
]))
|
||||||
|
story.append(t_cost)
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- SLIDE 4: PONTOS FORTES ---
|
||||||
|
story.append(Paragraph("Destaques de Segurança (Pontos Fortes)", style_slide_title))
|
||||||
|
story.append(Paragraph("A FGCOOP já implementou controles avançados de identidade:", style_body))
|
||||||
|
|
||||||
|
story.append(Paragraph("• <b>Autenticação Passwordless:</b> Uso de FIDO2 e Windows Hello, eliminando vetores de ataque baseados em senha.", style_bullet))
|
||||||
|
story.append(Paragraph("• <b>Proteção de Identidade:</b> Bloqueio de senhas fracas no AD Local e proteção contra força bruta ativos.", style_bullet))
|
||||||
|
story.append(Paragraph("• <b>Acesso Condicional:</b> Políticas maduras que bloqueiam autenticação legada e validam o risco do login.", style_bullet))
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- SLIDE 5: RISCOS CRÍTICOS ---
|
||||||
|
story.append(Paragraph("Riscos Críticos Identificados", style_slide_title))
|
||||||
|
story.append(Paragraph("Ativos que requerem intervenção imediata para evitar incidentes:", style_body))
|
||||||
|
|
||||||
|
data_risk = [
|
||||||
|
['Ativo', 'Nível', 'Impacto Técnico'],
|
||||||
|
['Servidor SVM42000', 'CRÍTICO 🔴', 'Falha em Replicação, Sites e Certificados KDC'],
|
||||||
|
['SVMAZDC01 / SVMAWSAD1', 'ALTO 🟠', 'Instabilidade de conectividade e sub-redes'],
|
||||||
|
['Conta KRBTGT', 'ALTO 🟠', 'Senha nunca rotacionada (Risco de Golden Ticket)'],
|
||||||
|
['Protocolo NTLM', 'MÉDIO 🟡', 'Protocolo vulnerável ativo na rede interna']
|
||||||
|
]
|
||||||
|
|
||||||
|
t_risk = Table(data_risk, colWidths=[6*cm, 3*cm, 14*cm])
|
||||||
|
t_risk.setStyle(TableStyle([
|
||||||
|
('BACKGROUND', (0,0), (-1,0), colors.HexColor("#CC0000")),
|
||||||
|
('TEXTCOLOR', (0,0), (-1,0), colors.white),
|
||||||
|
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
|
||||||
|
('ALIGN', (0,0), (-1,-1), 'LEFT'),
|
||||||
|
('GRID', (0,0), (-1,-1), 0.5, colors.grey),
|
||||||
|
('PADDING', (0,0), (-1,-1), 10),
|
||||||
|
('BACKGROUND', (0,1), (-1,-1), colors.white),
|
||||||
|
]))
|
||||||
|
story.append(t_risk)
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- SLIDE 6: PLANO DE AÇÃO ---
|
||||||
|
story.append(Paragraph("Plano de Ação: Quick Wins (0-30 Dias)", style_slide_title))
|
||||||
|
story.append(Paragraph("Ações prioritárias de baixo esforço e alto impacto:", style_body))
|
||||||
|
|
||||||
|
story.append(Paragraph("1. <b>Saneamento do AD:</b> Rotacionar senha da conta KRBTGT e corrigir delegações Kerberos.", style_bullet))
|
||||||
|
story.append(Paragraph("2. <b>Hardening de Servidores:</b> Resolver erros de replicação no SVM42000 e habilitar assinatura LDAP.", style_bullet))
|
||||||
|
story.append(Paragraph("3. <b>Proteção de Endpoints:</b> Aplicar regras de redução de superfície de ataque (ASR) via Intune.", style_bullet))
|
||||||
|
story.append(Paragraph("4. <b>Limpeza Financeira:</b> Remover licenças Business Basic ociosas identificadas.", style_bullet))
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- SLIDE 7: CONCLUSÃO ---
|
||||||
|
story.append(Paragraph("Conclusão e Próximos Passos", style_slide_title))
|
||||||
|
|
||||||
|
story.append(Paragraph("A FGCOOP está bem posicionada na nuvem (Score 82%), mas possui um 'débito técnico' perigoso na infraestrutura base (On-Premises).", style_body))
|
||||||
|
story.append(Spacer(1, 1*cm))
|
||||||
|
story.append(Paragraph("<b>Recomendação Final:</b> Priorizar a estabilização dos servidores de identidade (SVM42000) antes de iniciar novos projetos de inovação.", style_body))
|
||||||
|
story.append(Spacer(1, 2*cm))
|
||||||
|
story.append(Paragraph("Documento gerado por Cloud Essential Tech", style_body))
|
||||||
|
|
||||||
|
# 5. Gerar PDF
|
||||||
|
doc.build(story, onFirstPage=draw_cover_background, onLaterPages=draw_background)
|
||||||
131
resources/views/errors/403.blade.php
Normal file
131
resources/views/errors/403.blade.php
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="viho admin is super flexible, powerful, clean & modern responsive bootstrap 4 admin template with unlimited possibilities.">
|
||||||
|
<meta name="keywords" content="admin template, viho admin template, dashboard template, flat admin template, responsive admin template, web app">
|
||||||
|
<meta name="author" content="pixelstrap">
|
||||||
|
<link rel="icon" href="{{ asset('assets/images/favicon.png" type="image/x-icon')}}">
|
||||||
|
<link rel="shortcut icon" href="{{ asset('assets/images/favicon.png')}}" type="image/x-icon">
|
||||||
|
<title>{{env('APP_NAME')}}</title>
|
||||||
|
<!-- Google font-->
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||||
|
<!-- Font Awesome-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/fontawesome.css')}}">
|
||||||
|
<!-- ico-font-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/icofont.css')}}">
|
||||||
|
<!-- Themify icon-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/themify.css')}}">
|
||||||
|
<!-- Flag icon-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/flag-icon.css')}}">
|
||||||
|
<!-- Feather icon-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/feather-icon.css')}}">
|
||||||
|
<!-- Plugins css start-->
|
||||||
|
<!-- Plugins css Ends-->
|
||||||
|
<!-- Bootstrap css-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/bootstrap.css')}}">
|
||||||
|
<!-- App css-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/style.css')}}">
|
||||||
|
<link id="color" rel="stylesheet" href="{{ asset('assets/css/color-1.css" media="screen')}}">
|
||||||
|
<!-- Responsive css-->
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/responsive.css')}}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Loader starts-->
|
||||||
|
<div class="loader-wrapper">
|
||||||
|
<div class="theme-loader">
|
||||||
|
<div class="loader-p"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Loader ends-->
|
||||||
|
<!-- error page start //-->
|
||||||
|
<div class="page-wrapper" id="pageWrapper">
|
||||||
|
<div class="error-wrapper">
|
||||||
|
<div class="container">
|
||||||
|
<div class="error-page1">
|
||||||
|
<div class="svg-wrraper mb-0">
|
||||||
|
<svg class="svg-60" viewbox="0 0 1920 1080" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g>
|
||||||
|
<path class="warning-color" d="M600.87,872H156a4,4,0,0,0-3.78,4.19h0a4,4,0,0,0,3.78,4.19H600.87a4,4,0,0,0,3.78-4.19h0A4,4,0,0,0,600.87,872Z"></path>
|
||||||
|
<rect class="warning-color" height="8.39" rx="4.19" ry="4.19" width="513.38" x="680.91" y="871.98"></rect>
|
||||||
|
<path class="warning-color" d="M1480,876.17h0c0,2.32,2.37,4.19,5.3,4.19h350.61c2.93,0,5.3-1.88,5.3-4.19h0c0-2.32-2.37-4.19-5.3-4.19H1485.26C1482.33,872,1480,873.86,1480,876.17Z"></path>
|
||||||
|
<rect class="warning-color" height="8.39" rx="4.19" ry="4.19" width="249.8" x="492.21" y="920.64"></rect>
|
||||||
|
<path class="warning-color" d="M1549.14,924.84h0a4.19,4.19,0,0,0-4.19-4.19H1067.46a14.66,14.66,0,0,1,.35,3.21v1A4.19,4.19,0,0,0,1072,929h472.94A4.19,4.19,0,0,0,1549.14,924.84Z"></path>
|
||||||
|
<path class="warning-color" d="M865.5,924.84h0a4.19,4.19,0,0,0,4.19,4.19h82.37a12.28,12.28,0,0,1-.19-2v-2.17a4.19,4.19,0,0,0-4.19-4.19h-78A4.19,4.19,0,0,0,865.5,924.84Z"></path>
|
||||||
|
<rect class="warning-color" height="8.39" rx="4.19" ry="4.19" width="54.72" x="915.6" y="981.47"></rect>
|
||||||
|
<path class="warning-color" d="M730.33,985.67h0c0,2.32,4.23,4.19,9.44,4.19h104.3c5.22,0,9.44-1.88,9.44-4.19h0c0-2.32-4.23-4.19-9.44-4.19H739.78C734.56,981.47,730.33,983.35,730.33,985.67Z"></path>
|
||||||
|
<rect class="warning-color" height="8.39" rx="4.19" ry="4.19" width="78.11" x="997.06" y="981.47"></rect>
|
||||||
|
<g id="round-conf">
|
||||||
|
<path class="warning-color circle c1" d="M536.41,155.14a17.77,17.77,0,1,0,17.77,17.77A17.77,17.77,0,0,0,536.41,155.14Zm0,28.68a10.9,10.9,0,1,1,10.9-10.9A10.9,10.9,0,0,1,536.41,183.81Z"></path>
|
||||||
|
<path class="warning-color circle c1" d="M1345.09,82.44a17.77,17.77,0,1,0,17.77,17.77A17.77,17.77,0,0,0,1345.09,82.44Zm0,28.68a10.9,10.9,0,1,1,10.9-10.9A10.9,10.9,0,0,1,1345.09,111.12Z"></path>
|
||||||
|
<path class="warning-color circle c1" d="M70.12,363A17.77,17.77,0,1,0,87.89,380.8,17.77,17.77,0,0,0,70.12,363Zm0,28.68A10.9,10.9,0,1,1,81,380.8,10.9,10.9,0,0,1,70.12,391.7Z"></path>
|
||||||
|
<path class="warning-color circle c1" d="M170.47,751.82a17.77,17.77,0,1,0,17.77,17.77A17.77,17.77,0,0,0,170.47,751.82Zm0,28.68a10.9,10.9,0,1,1,10.9-10.9A10.9,10.9,0,0,1,170.47,780.5Z"></path>
|
||||||
|
<path class="warning-color circle c1" d="M1457.34,762.73a17.77,17.77,0,1,0,17.77,17.77A17.77,17.77,0,0,0,1457.34,762.73Zm0,28.68a10.9,10.9,0,1,1,10.9-10.9A10.9,10.9,0,0,1,1457.34,791.4Z"></path>
|
||||||
|
<path class="warning-color circle c1" d="M1829.15,407.49a17.77,17.77,0,1,0,17.77,17.77A17.77,17.77,0,0,0,1829.15,407.49Zm0,28.68a10.9,10.9,0,1,1,10.9-10.9A10.9,10.9,0,0,1,1829.15,436.17Z"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="fortyfour" data-name="Layer 2">
|
||||||
|
<g class="four a">
|
||||||
|
<rect class="primary-color" height="466.29" rx="57.1" ry="57.1" transform="translate(918.39 330.19) rotate(90)" width="120.71" x="233.74" y="391.14"></rect>
|
||||||
|
<rect class="primary-color" height="396.88" rx="60.36" ry="60.36" width="120.71" x="333.83" y="475.1"></rect>
|
||||||
|
<rect class="primary-color" height="604.75" rx="60.36" ry="60.36" transform="translate(290.49 -70.78) rotate(35)" width="120.71" x="197.13" y="122.89"></rect>
|
||||||
|
</g>
|
||||||
|
<g class="four b">
|
||||||
|
<rect class="primary-color" height="466.29" rx="57.1" ry="57.1" transform="translate(2244.26 -994.14) rotate(90)" width="120.71" x="1558.84" y="391.91"></rect>
|
||||||
|
<rect class="primary-color" height="396.88" rx="60.36" ry="60.36" width="120.71" x="1658.92" y="475.87"></rect>
|
||||||
|
<rect class="primary-color" height="604.75" rx="60.36" ry="60.36" transform="translate(530.57 -830.68) rotate(35)" width="120.71" x="1522.22" y="123.66"></rect>
|
||||||
|
</g>
|
||||||
|
<path class="primary-color" id="ou" d="M956.54,168.2c-194.34,0-351.89,157.55-351.89,351.89S762.19,872,956.54,872s351.89-157.55,351.89-351.89S1150.88,168.2,956.54,168.2Zm0,584.49c-128.46,0-232.6-104.14-232.6-232.6s104.14-232.6,232.6-232.6,232.6,104.14,232.6,232.6S1085,752.69,956.54,752.69Z"></path>
|
||||||
|
</g>
|
||||||
|
<g class="bicycle" data-name="Layer 5">
|
||||||
|
<path class="warning-color wheel" d="M1139.82,780.44a76.59,76.59,0,1,0-57.9,91.53A76.59,76.59,0,0,0,1139.82,780.44Zm-28.12,6.33a47.59,47.59,0,0,1,.83,15.8c-30.14-6.28-47.68-21.65-54.39-52.52A47.73,47.73,0,0,1,1111.69,786.77Zm-70.46-30.9c10.35,26.88,10.14,50.4-13.73,70.77a47.67,47.67,0,0,1,13.73-70.77Zm34.35,88a47.55,47.55,0,0,1-34.94-5.62c16.8-20.36,41.71-25.94,67.09-19.46A47.66,47.66,0,0,1,1075.58,843.85Z"></path>
|
||||||
|
<path class="warning-color wheel" d="M864.89,789.69a76.59,76.59,0,1,0-66.13,85.78A76.59,76.59,0,0,0,864.89,789.69Zm-28.59,3.7a47.59,47.59,0,0,1-.64,15.81c-29.43-9-45.47-26-49.3-57.33A47.73,47.73,0,0,1,836.3,793.39ZM769,756.1c7.82,27.72,5.43,51.12-20.22,69.2A47.67,47.67,0,0,1,769,756.1Zm26.06,90.78a47.55,47.55,0,0,1-34.27-8.83c18.61-18.72,43.93-22,68.6-13.16A47.66,47.66,0,0,1,795.06,846.88Z"></path>
|
||||||
|
<g>
|
||||||
|
<rect class="warning-color" height="53.21" transform="translate(-165.97 273.38) rotate(-16.19)" width="12.87" x="871.39" y="693.37"></rect>
|
||||||
|
<path class="secondary-color lighten-5" d="M813.93,679.35c-3.72-5.2,2.24-18.5,9.16-16.13,33.43,11.46,73.85,10.45,73.85,10.45,8.84.15,14.44,10.34,7.27,15.48-14.36,8.79-33.13,17-56.35,9.76C830.17,693.41,819.83,687.6,813.93,679.35Z"></path>
|
||||||
|
<path class="secondary-color opacity-o4" d="M813.93,679.35c-3.72-5.2,2.24-18.5,9.16-16.13,33.43,11.46,73.85,10.45,73.85,10.45,8.84.15,14.44,10.34,7.27,15.48-14.36,8.79-33.13,17-56.35,9.76C830.17,693.41,819.83,687.6,813.93,679.35Z"></path>
|
||||||
|
<path class="secondary-color lighten-5" d="M817.15,680.06c-3.59-5,1.69-16.51,8.37-14.22,32.3,11.09,71.41,7.83,71.41,7.83,8.54.14,17.45,9.94,7.43,15.88-13.87,8.51-32,16.44-54.44,9.44C832.84,693.67,822.85,688,817.15,680.06Z"></path>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<circle class="warning-color" cx="1022.66" cy="599.55" r="11.57" transform="translate(-4.86 8.38) rotate(-0.47)"></circle>
|
||||||
|
<path class="warning-color" d="M1069.76,792.37l-34.89-96.74,1.93-.8-1.71-4.15-1.74.72-13.26-36.76,1.27-.42-2.25-6.76,5.94-2-2.57-7.72-9.7,3.22c-11.55-22.55,2-36.33,15-41.86l-5.57-8.81c-23,10.29-29.61,28.75-19.53,54l-9.38,3.12,2.56,7.72,5.47-1.82,2.25,6.76,2.36-.78,13.62,37.76-2.35,1,1.71,4.15,2.16-.89,34.65,96.09a7.47,7.47,0,0,0,9.56,4.49h0A7.47,7.47,0,0,0,1069.76,792.37Z"></path>
|
||||||
|
<circle class="secondary-color lighten-5" cx="1027.9" cy="587.94" r="12.99" transform="translate(-4.77 8.42) rotate(-0.47)"></circle>
|
||||||
|
</g>
|
||||||
|
<path class="secondary-color lighten-5" d="M1021.29,654l-17.73,6.15,1.72,5.59-31.41,82.36c-19.35,32.53-66.3,36.72-75.56,16.68l-7.09-21.5L879,747.1l3.28,10.09-94.65,33.95c-11.49,2.29-11.85,15.79-2.61,17.84,0,0,39.11,3.66,103,9.5a92.75,92.75,0,0,0,40.89-5.29c44.32-16.56,57.73-50.67,57.73-50.67l26.82-67.26a1.37,1.37,0,0,1,2.53,0l1.42,3.33,17.75-7.62Z"></path>
|
||||||
|
<path class="secondary-color opacity-o4" d="M1021.29,654l-17.73,6.15,1.72,5.59-31.41,82.36c-19.35,32.53-66.3,36.72-75.56,16.68l-7.09-21.5L879,747.1l3.28,10.09-94.65,33.95c-11.49,2.29-11.85,15.79-2.61,17.84,0,0,39.11,3.66,103,9.5a92.75,92.75,0,0,0,40.89-5.29c44.32-16.56,57.73-50.67,57.73-50.67l26.82-67.26a1.37,1.37,0,0,1,2.53,0l1.42,3.33,17.75-7.62Z"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8 offset-md-2">
|
||||||
|
<h3>Oops! Parece que você não tem permissão de acesso.</h3>
|
||||||
|
<p class="sub-content">Você está tentando acessar uma página que você não tem acesso, foi movida ou não existe mais. Entre em contato com suporte.</p><a class="btn btn-primary btn-lg" href="{{ route('dashboard') }}">Voltar para o sistema</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- error page end //-->
|
||||||
|
<!-- latest jquery-->
|
||||||
|
<script src="{{ asset('assets/js/jquery-3.5.1.min.js')}}"></script>
|
||||||
|
<!-- feather icon js-->
|
||||||
|
<script src="{{ asset('assets/js/icons/feather-icon/feather.min.js')}}"></script>
|
||||||
|
<script src="{{ asset('assets/js/icons/feather-icon/feather-icon.js')}}"></script>
|
||||||
|
<!-- Sidebar jquery-->
|
||||||
|
<script src="{{ asset('assets/js/sidebar-menu.js')}}"></script>
|
||||||
|
<script src="{{ asset('assets/js/config.js')}}"></script>
|
||||||
|
<!-- Bootstrap js-->
|
||||||
|
<script src="{{ asset('assets/js/bootstrap/popper.min.js')}}"></script>
|
||||||
|
<script src="{{ asset('assets/js/bootstrap/bootstrap.min.js')}}"></script>
|
||||||
|
<!-- Plugins JS start-->
|
||||||
|
<!-- Plugins JS Ends-->
|
||||||
|
<!-- Theme js-->
|
||||||
|
<script src="{{ asset('assets/js/script.js')}}"></script>
|
||||||
|
<!-- login js-->
|
||||||
|
<!-- Plugin used-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
resources/views/escolas/escola.detalhes.blade.php
Normal file
6
resources/views/escolas/escola.detalhes.blade.php
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@extends('theme.default')
|
||||||
|
@section('title', 'Alunos')
|
||||||
|
@section('title.page', 'Alunos')
|
||||||
|
@section('title.page1', 'CAE')
|
||||||
|
@section('title.page2', 'Alunos')
|
||||||
|
@section('title.page3', 'Lista de alunos')
|
||||||
@@ -30,19 +30,27 @@
|
|||||||
<td>{{$escola->nome}}</td>
|
<td>{{$escola->nome}}</td>
|
||||||
<td>{{$escola->cnpj}}</td>
|
<td>{{$escola->cnpj}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span>Endereço:</span>
|
@if (isset($escola->endereco))
|
||||||
<p>{{ $escola->endereco['street'] }} {{ $escola->endereco['number'] }}
|
<span>Endereço:</span>
|
||||||
</p>
|
<p>{{ $escola->endereco['street'] }} {{ $escola->endereco['number'] }}</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span>Complemento:</span>
|
@if (isset($escola->endereco))
|
||||||
<p>{{ $escola->endereco['details'] }} </p>
|
<span>Complemento:</span>
|
||||||
|
<p>{{ $escola->endereco['details'] }} </p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span>Cep:</span>
|
@if (isset($escola->endereco))
|
||||||
<p>{{ $escola->endereco['zip'] }}</p>
|
<span>Cep:</span>
|
||||||
|
<p>{{ $escola->endereco['zip'] }}</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" href="{{asset('assets/images/logo3.png')}}" type="image/x-icon">
|
<link rel="icon" href="{{ asset('assets/images/logo3.png') }}" type="image/x-icon">
|
||||||
<link rel="shortcut icon" href="{{asset('assets/images/favicon.jpg')}}" type="image/x-icon">
|
<link rel="shortcut icon" href="{{ asset('assets/images/favicon.jpg') }}" type="image/x-icon">
|
||||||
<title>{{ env('APP_NAME') }} - @yield('title')</title>
|
<title>@yield('title') - {{env('APP_NAME_SHORT')}}</title>
|
||||||
<!-- Google font-->
|
<!-- Google font-->
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||||
<link
|
<link
|
||||||
@@ -20,43 +20,35 @@
|
|||||||
href="https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
<!-- Font Awesome-->
|
<!-- Font Awesome-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/fontawesome.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/fontawesome.css') }}">
|
||||||
<!-- ico-font-->
|
<!-- ico-font-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/icofont.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/icofont.css') }}">
|
||||||
<!-- Themify icon-->
|
<!-- Themify icon-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/themify.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/themify.css') }}">
|
||||||
<!-- Flag icon-->
|
<!-- Flag icon-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/flag-icon.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/flag-icon.css') }}">
|
||||||
<!-- Feather icon-->
|
<!-- Feather icon-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/feather-icon.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/feather-icon.css') }}">
|
||||||
<!-- Plugins css start-->
|
<!-- Plugins css start-->
|
||||||
<!-- Plugins css Ends-->
|
<!-- Plugins css Ends-->
|
||||||
<!-- Bootstrap css-->
|
<!-- Bootstrap css-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/bootstrap.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/bootstrap.css') }}">
|
||||||
<!-- App css-->
|
<!-- App css-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/style.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/style.css') }}">
|
||||||
<link id="color" rel="stylesheet" href="{{ asset('assets/css/color-1.css')}}" media="screen">
|
<link id="color" rel="stylesheet" href="{{ asset('assets/css/color-1.css') }}" media="screen">
|
||||||
<!-- Responsive css-->
|
<!-- Responsive css-->
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/responsive.css')}}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/responsive.css') }}">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/dropzone.css') }}">
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/dropzone.css') }}">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@php
|
@php
|
||||||
use App\Models\escolas;
|
use App\Models\Escola;
|
||||||
use App\Models\turmas;
|
use App\Models\Turma;
|
||||||
if (Auth::user()->id_escola == 0) {
|
|
||||||
$escolas = escolas::all();
|
|
||||||
} else {
|
|
||||||
$escolas = escolas::where('id', Auth::user()->id_escola)->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Auth::user()->id_escola == 0) {
|
$escolas = Escola::all();
|
||||||
$turmas = turmas::all();
|
$turmas = Turma::all();
|
||||||
} else {
|
|
||||||
$turmas = turmas::where('id_escola', Auth::user()->id_escola)->get();
|
|
||||||
}
|
|
||||||
@endphp
|
@endphp
|
||||||
<!-- Loader starts-->
|
<!-- Loader starts-->
|
||||||
<div class="loader-wrapper">
|
<div class="loader-wrapper">
|
||||||
@@ -89,26 +81,36 @@
|
|||||||
<ul class="nav-menus">
|
<ul class="nav-menus">
|
||||||
<li><a class="text-dark" href="#!" onclick="javascript:toggleFullScreen()"><i
|
<li><a class="text-dark" href="#!" onclick="javascript:toggleFullScreen()"><i
|
||||||
data-feather="maximize"></i></a></li>
|
data-feather="maximize"></i></a></li>
|
||||||
<li>
|
@role('super_admin')
|
||||||
<div class="dropdown-basic">
|
<li>
|
||||||
<div class="dropdown">
|
<div class="dropdown-basic">
|
||||||
<div class="btn-group mb-0">
|
<div class="dropdown">
|
||||||
<button class="dropbtn btn-primary btn-round" type="button">
|
<div class="btn-group mb-0">
|
||||||
Novo <span><i class="icofont icofont-arrow-down"></i></span>
|
<button class="dropbtn btn-primary btn-round" type="button">
|
||||||
</button>
|
Novo <span><i class="icofont icofont-arrow-down"></i></span>
|
||||||
|
</button>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#modalEscola">Escola</a>
|
<a href="#" data-bs-toggle="modal"
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#modalTurma">Turma</a>
|
data-bs-target="#modalEscola">Escola</a>
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#modalAluno">Aluno</a>
|
<a href="#" data-bs-toggle="modal"
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#modalEnvio">Envio de
|
data-bs-target="#modalTurma">Turma</a>
|
||||||
Mensagem</a>
|
<a href="#" data-bs-toggle="modal"
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#modalEvento">Evento</a>
|
data-bs-target="#modalAluno">Aluno</a>
|
||||||
|
<a href="#" data-bs-toggle="modal" data-bs-target="#modalEnvio">Envio
|
||||||
|
de
|
||||||
|
Mensagem</a>
|
||||||
|
<a href="#" data-bs-toggle="modal"
|
||||||
|
data-bs-target="#modalEvento">Evento</a>
|
||||||
|
<a href="#" data-bs-toggle="modal"
|
||||||
|
data-bs-target="#modalUsuario">Usuário</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
@endrole
|
||||||
|
|
||||||
|
|
||||||
<li class="onhover-dropdown p-0">
|
<li class="onhover-dropdown p-0">
|
||||||
<form method="POST" action="{{ route('logout') }}">
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
@@ -130,8 +132,8 @@
|
|||||||
<header class="main-nav">
|
<header class="main-nav">
|
||||||
<div class="sidebar-user text-center"><a class="setting-primary" href="javascript:void(0)"><i
|
<div class="sidebar-user text-center"><a class="setting-primary" href="javascript:void(0)"><i
|
||||||
data-feather="settings"></i></a><img class="img-90 rounded-circle"
|
data-feather="settings"></i></a><img class="img-90 rounded-circle"
|
||||||
src="{{ asset('assets/images/logo3.png')}}" alt="">
|
src="{{ asset('assets/images/logo3.png') }}" alt="">
|
||||||
<div class="badge-bottom"><span class="badge badge-primary">Responsável</span></div><a
|
<div class="badge-bottom"><span class="badge badge-primary">{{ Auth::user()->funcao() }}</span></div><a
|
||||||
href="user-profile.html">
|
href="user-profile.html">
|
||||||
<h6 class="mt-3 f-14 f-w-600">{{ Auth::user()->name }}</h6>
|
<h6 class="mt-3 f-14 f-w-600">{{ Auth::user()->name }}</h6>
|
||||||
</a>
|
</a>
|
||||||
@@ -142,30 +144,41 @@
|
|||||||
<div id="mainnav">
|
<div id="mainnav">
|
||||||
<ul class="nav-menu custom-scrollbar">
|
<ul class="nav-menu custom-scrollbar">
|
||||||
<li class="back-btn">
|
<li class="back-btn">
|
||||||
<div class="mobile-back text-end"><span>Back</span><i class="fa fa-angle-right ps-2"
|
<div class="mobile-back text-end"><span>Back</span><i
|
||||||
aria-hidden="true"></i></div>
|
class="fa fa-angle-right ps-2" aria-hidden="true"></i></div>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar-main-title">
|
<li class="sidebar-main-title">
|
||||||
<div>
|
<div>
|
||||||
<h6>Geral </h6>
|
<h6>Geral </h6>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown"><a class="nav-link menu-title link-nav" href=""><i
|
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
||||||
|
href="{{ route('dashboard') }}"><i
|
||||||
data-feather="git-pull-request"></i><span>Dashboard</span></a></li>
|
data-feather="git-pull-request"></i><span>Dashboard</span></a></li>
|
||||||
<li class="sidebar-main-title">
|
|
||||||
<div>
|
@role(['admin', 'super_admin'])
|
||||||
<h6>Administração </h6>
|
<li class="sidebar-main-title">
|
||||||
</div>
|
<div>
|
||||||
</li>
|
<h6>Administração </h6>
|
||||||
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
</div>
|
||||||
href="{{ route('escolas') }}"><i
|
</li>
|
||||||
data-feather="award"></i><span>Escolas</span></a></li>
|
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
||||||
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
href="{{ route('escolas') }}"><i
|
||||||
href="{{ route('turmas') }}"><i data-feather="award"></i><span>Turmas</span></a>
|
data-feather="award"></i><span>Escolas</span></a></li>
|
||||||
</li>
|
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
||||||
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
href="{{ route('turmas') }}"><i
|
||||||
href="{{ route('alunos') }}"><i data-feather="award"></i><span>Alunos</span></a>
|
data-feather="award"></i><span>Turmas</span></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
||||||
|
href="{{ route('alunos') }}"><i
|
||||||
|
data-feather="award"></i><span>Alunos</span></a>
|
||||||
|
</li>
|
||||||
|
<li class="dropdown"><a class="nav-link menu-title link-nav"
|
||||||
|
href="{{ route('usuarios') }}"><i
|
||||||
|
data-feather="award"></i><span>Usuários</span></a>
|
||||||
|
</li>
|
||||||
|
@endrole
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-arrow" id="right-arrow"><i data-feather="arrow-right"></i></div>
|
<div class="right-arrow" id="right-arrow"><i data-feather="arrow-right"></i></div>
|
||||||
@@ -213,6 +226,8 @@
|
|||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Escola -->
|
||||||
<div class="modal fade" id="modalEscola" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="modalEscola" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -234,7 +249,8 @@
|
|||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="razao_social">Razão Social</label>
|
<label class="form-label" for="razao_social">Razão Social</label>
|
||||||
<input class="form-control" id="razao_social" name="razaosocial" type="text">
|
<input class="form-control" id="razao_social" name="razaosocial"
|
||||||
|
type="text">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -295,6 +311,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Turma -->
|
||||||
<div class="modal fade" id="modalTurma" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="modalTurma" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -322,7 +339,8 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="turma_nome">Nome</label>
|
<label class="form-label" for="turma_nome">Nome</label>
|
||||||
<input class="form-control" id="turma_nome" name="turma_nome" type="text">
|
<input class="form-control" id="turma_nome" name="turma_nome"
|
||||||
|
type="text">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -335,7 +353,8 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="id_whatsapp">Whatsap Id</label>
|
<label class="form-label" for="id_whatsapp">Whatsap Id</label>
|
||||||
<input class="form-control" id="id_whatsapp" name="id_whatsapp" type="text">
|
<input class="form-control" id="id_whatsapp" name="id_whatsapp"
|
||||||
|
type="text">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -349,21 +368,241 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{-- MODAL NOVO ALUNO --}}
|
||||||
<div class="modal fade" id="modalAluno" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="modalAluno" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title">Novo Aluno</h4>
|
<form class="form theme-form" action="{{ route('alunos.add') }}" method="POST">
|
||||||
<button class="btn-close" data-bs-dismiss="modal"></button>
|
@csrf
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
<div class="modal-header">
|
||||||
<!-- formulário -->
|
<h4 class="modal-title">Novo Aluno</h4>
|
||||||
</div>
|
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
{{-- Escola --}}
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Escola</label>
|
||||||
|
<select class="form-select" name="id_escola" id="id_escola" required>
|
||||||
|
<option value="">Selecione...</option>
|
||||||
|
@foreach ($escolas as $escola)
|
||||||
|
<option value="{{ $escola->id }}" @selected(auth()->user()?->current_escola_id == $escola->id)>
|
||||||
|
{{ $escola->nome }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Turma --}}
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Turma</label>
|
||||||
|
<select class="form-select digits" name="id_turma" id="id_turma" required
|
||||||
|
disabled>
|
||||||
|
<option value="">Selecione uma escola primeiro...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Nome --}}
|
||||||
|
<div class="col-12 col-md-8">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nome do aluno</label>
|
||||||
|
<input type="text" name="nome" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- CPF --}}
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">CPF</label>
|
||||||
|
<input type="text" name="cpf" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Data de nascimento --}}
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Data de nascimento *</label>
|
||||||
|
<input type="date" name="data_nascimento" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Data de inscrição --}}
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Data de inscrição *</label>
|
||||||
|
<input type="date" name="data_inscricao" class="form-control"
|
||||||
|
value="{{ now()->format('Y-m-d') }}" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Usuário do aluno --}}
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Usuário do aluno (opcional)</label>
|
||||||
|
<select class="form-select" name="user_id">
|
||||||
|
<option value="">Não vincular</option>
|
||||||
|
@foreach ($users ?? [] as $u)
|
||||||
|
<option value="{{ $u->id }}">
|
||||||
|
{{ $u->name }} ({{ $u->email }})
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Usuário responsável --}}
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Usuário responsável (opcional)</label>
|
||||||
|
<select class="form-select" name="responsavel_user_id">
|
||||||
|
<option value="">Não vincular</option>
|
||||||
|
@foreach ($users ?? [] as $u)
|
||||||
|
<option value="{{ $u->id }}">
|
||||||
|
{{ $u->name }} ({{ $u->email }})
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-secondary" data-bs-dismiss="modal">
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
Salvar Aluno
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{-- JS carregar turmas --}}
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
|
const modalEl = document.getElementById('modalAluno');
|
||||||
|
const escolaSelect = document.getElementById('id_escola');
|
||||||
|
const turmaSelect = document.getElementById('id_turma');
|
||||||
|
|
||||||
|
if (!modalEl || !escolaSelect || !turmaSelect) return;
|
||||||
|
|
||||||
|
let controller = null; // abort fetch anterior
|
||||||
|
|
||||||
|
function setTurmaOptions({
|
||||||
|
message = null,
|
||||||
|
turmas = []
|
||||||
|
} = {}) {
|
||||||
|
turmaSelect.innerHTML = '';
|
||||||
|
|
||||||
|
if (message) {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = '';
|
||||||
|
opt.textContent = message;
|
||||||
|
turmaSelect.appendChild(opt);
|
||||||
|
turmaSelect.disabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const opt0 = document.createElement('option');
|
||||||
|
opt0.value = '';
|
||||||
|
opt0.textContent = 'Selecione...';
|
||||||
|
turmaSelect.appendChild(opt0);
|
||||||
|
|
||||||
|
turmas.forEach(t => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = t.id;
|
||||||
|
opt.textContent = t.nome;
|
||||||
|
turmaSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
turmaSelect.disabled = turmas.length === 0;
|
||||||
|
if (turmas.length === 0) {
|
||||||
|
setTurmaOptions({
|
||||||
|
message: 'Nenhuma turma encontrada para esta escola.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadTurmas(escolaId) {
|
||||||
|
if (!escolaId) {
|
||||||
|
setTurmaOptions({
|
||||||
|
message: 'Selecione uma escola primeiro...'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancela requisição anterior
|
||||||
|
if (controller) controller.abort();
|
||||||
|
controller = new AbortController();
|
||||||
|
|
||||||
|
setTurmaOptions({
|
||||||
|
message: 'Carregando turmas...'
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await fetch(`/api/escolas/${escolaId}/turmas`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
// se deu redirect/403/500 etc, não tenta parsear json
|
||||||
|
if (!resp.ok) {
|
||||||
|
throw new Error(`HTTP ${resp.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const turmas = await resp.json();
|
||||||
|
setTurmaOptions({
|
||||||
|
turmas
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
if (err.name === 'AbortError') return; // troca rápida de escola
|
||||||
|
console.error('Erro ao carregar turmas:', err);
|
||||||
|
setTurmaOptions({
|
||||||
|
message: 'Erro ao carregar turmas.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) carrega sempre ao abrir o modal (garante estabilidade)
|
||||||
|
modalEl.addEventListener('shown.bs.modal', () => {
|
||||||
|
loadTurmas(escolaSelect.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2) recarrega ao trocar escola
|
||||||
|
escolaSelect.addEventListener('change', () => {
|
||||||
|
loadTurmas(escolaSelect.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3) opcional: ao fechar modal, reseta turmas (evita “ficar antigo”)
|
||||||
|
modalEl.addEventListener('hidden.bs.modal', () => {
|
||||||
|
setTurmaOptions({
|
||||||
|
message: 'Selecione uma escola primeiro...'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="modal fade" id="modalEnvio" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="modalEnvio" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -454,21 +693,267 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="modalUsuario" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">Novo Usuário</h4>
|
||||||
|
<button class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<form action="{{ route('usuarios.add') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nome</label>
|
||||||
|
<input class="form-control" name="name" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Email</label>
|
||||||
|
<input class="form-control" type="email" name="email" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Senha</label>
|
||||||
|
<input class="form-control" type="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Confirmar senha</label>
|
||||||
|
<input class="form-control" type="password" name="password_confirmation" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" value="1" id="is_super_admin" name="is_super_admin">
|
||||||
|
<label class="form-check-label" for="is_super_admin">Super Admin</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Escola</label>
|
||||||
|
<select class="form-select" name="escola_id" id="escola_id_user">
|
||||||
|
<option value="">Selecione...</option>
|
||||||
|
@foreach($escolas as $escola)
|
||||||
|
<option value="{{ $escola->id }}">{{ $escola->nome }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Cargo</label>
|
||||||
|
<select class="form-select" name="role_name" id="role_name" disabled>
|
||||||
|
<option value="">Selecione uma escola primeiro...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- ✅ ALUNO: vínculo 1 aluno --}}
|
||||||
|
<div class="mb-3 d-none" id="box_aluno_unico">
|
||||||
|
<label class="form-label" id="label_aluno_unico">Qual aluno este usuário é?</label>
|
||||||
|
<select class="form-select" name="aluno_id" id="aluno_id" disabled>
|
||||||
|
<option value="">Selecione uma escola primeiro...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- ✅ RESPONSÁVEL: vínculo múltiplos alunos --}}
|
||||||
|
<div class="mb-3 d-none" id="box_alunos_responsavel">
|
||||||
|
<label class="form-label">Quais alunos este responsável representa?</label>
|
||||||
|
<select class="form-select" name="aluno_ids[]" id="aluno_ids" multiple disabled>
|
||||||
|
<option value="">Selecione uma escola primeiro...</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted">
|
||||||
|
Segure <b>Ctrl</b> (Windows) ou <b>Cmd</b> (Mac) para selecionar mais de um.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-primary" type="submit">Criar usuário</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
|
const escolaSelect = document.getElementById('escola_id_user');
|
||||||
|
const roleSelect = document.getElementById('role_name');
|
||||||
|
const superCheck = document.getElementById('is_super_admin');
|
||||||
|
|
||||||
|
const boxAlunoUnico = document.getElementById('box_aluno_unico');
|
||||||
|
const alunoSelect = document.getElementById('aluno_id');
|
||||||
|
const labelAlunoUnico = document.getElementById('label_aluno_unico');
|
||||||
|
|
||||||
|
const boxResp = document.getElementById('box_alunos_responsavel');
|
||||||
|
const alunosMulti = document.getElementById('aluno_ids');
|
||||||
|
|
||||||
|
const roleLabel = {
|
||||||
|
'coordenacao': 'Coordenação',
|
||||||
|
'secretaria': 'Secretaria',
|
||||||
|
'responsavel': 'Responsável',
|
||||||
|
'aluno': 'Aluno',
|
||||||
|
'representante_de_turma': 'Representante de Turma',
|
||||||
|
};
|
||||||
|
|
||||||
|
function resetSelect(select, msg) {
|
||||||
|
select.innerHTML = `<option value="">${msg}</option>`;
|
||||||
|
select.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideAllBindings() {
|
||||||
|
boxAlunoUnico.classList.add('d-none');
|
||||||
|
boxResp.classList.add('d-none');
|
||||||
|
|
||||||
|
alunoSelect.value = '';
|
||||||
|
alunosMulti.value = '';
|
||||||
|
|
||||||
|
resetSelect(alunoSelect, 'Selecione uma escola primeiro...');
|
||||||
|
resetSelect(alunosMulti, 'Selecione uma escola primeiro...');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadRoles(escolaId) {
|
||||||
|
if (!escolaId) {
|
||||||
|
resetSelect(roleSelect, 'Selecione uma escola primeiro...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetSelect(roleSelect, 'Carregando cargos...');
|
||||||
|
|
||||||
|
const resp = await fetch(`/api/escolas/${escolaId}/roles`, {
|
||||||
|
headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!resp.ok) {
|
||||||
|
resetSelect(roleSelect, 'Erro ao carregar cargos');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles = await resp.json();
|
||||||
|
|
||||||
|
roleSelect.innerHTML = `<option value="">Selecione...</option>`;
|
||||||
|
roles.forEach(r => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = r.name;
|
||||||
|
opt.textContent = roleLabel[r.name] ?? r.name;
|
||||||
|
roleSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
roleSelect.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadAlunos(escolaId, targetSelect, multiple = false) {
|
||||||
|
if (!escolaId) {
|
||||||
|
resetSelect(targetSelect, 'Selecione uma escola primeiro...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetSelect(targetSelect, 'Carregando alunos...');
|
||||||
|
|
||||||
|
const resp = await fetch(`/api/escolas/${escolaId}/alunos`, {
|
||||||
|
headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!resp.ok) {
|
||||||
|
resetSelect(targetSelect, 'Erro ao carregar alunos');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const alunos = await resp.json();
|
||||||
|
|
||||||
|
targetSelect.innerHTML = multiple
|
||||||
|
? '' // multi select não precisa placeholder fixo
|
||||||
|
: `<option value="">Selecione...</option>`;
|
||||||
|
|
||||||
|
alunos.forEach(a => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = a.id;
|
||||||
|
opt.textContent = a.nome;
|
||||||
|
targetSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
targetSelect.disabled = alunos.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSuperAdmin(isSuper) {
|
||||||
|
if (isSuper) {
|
||||||
|
escolaSelect.value = '';
|
||||||
|
roleSelect.value = '';
|
||||||
|
resetSelect(roleSelect, 'Super Admin não usa cargo');
|
||||||
|
escolaSelect.disabled = true;
|
||||||
|
roleSelect.disabled = true;
|
||||||
|
|
||||||
|
hideAllBindings();
|
||||||
|
alunoSelect.disabled = true;
|
||||||
|
alunosMulti.disabled = true;
|
||||||
|
} else {
|
||||||
|
escolaSelect.disabled = false;
|
||||||
|
resetSelect(roleSelect, 'Selecione uma escola primeiro...');
|
||||||
|
roleSelect.disabled = true;
|
||||||
|
hideAllBindings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
superCheck.addEventListener('change', () => toggleSuperAdmin(superCheck.checked));
|
||||||
|
|
||||||
|
escolaSelect.addEventListener('change', async () => {
|
||||||
|
await loadRoles(escolaSelect.value);
|
||||||
|
hideAllBindings();
|
||||||
|
});
|
||||||
|
|
||||||
|
roleSelect.addEventListener('change', async () => {
|
||||||
|
const role = roleSelect.value;
|
||||||
|
|
||||||
|
// sempre reseta
|
||||||
|
hideAllBindings();
|
||||||
|
|
||||||
|
if (role === 'responsavel') {
|
||||||
|
boxResp.classList.remove('d-none');
|
||||||
|
await loadAlunos(escolaSelect.value, alunosMulti, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role === 'aluno') {
|
||||||
|
labelAlunoUnico.textContent = 'Qual aluno este usuário é?';
|
||||||
|
boxAlunoUnico.classList.remove('d-none');
|
||||||
|
await loadAlunos(escolaSelect.value, alunoSelect, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (opcional) se representante também tiver vínculo com 1 aluno, habilite:
|
||||||
|
// if (role === 'representante_de_turma') { ... }
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// estado inicial
|
||||||
|
toggleSuperAdmin(superCheck.checked);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- latest jquery-->
|
<!-- latest jquery-->
|
||||||
<script src="{{ asset('assets/js/jquery-3.5.1.min.js')}}"></script>
|
<script src="{{ asset('assets/js/jquery-3.5.1.min.js') }}"></script>
|
||||||
<!-- feather icon js-->
|
<!-- feather icon js-->
|
||||||
<script src="{{ asset('assets/js/icons/feather-icon/feather.min.js')}}"></script>
|
<script src="{{ asset('assets/js/icons/feather-icon/feather.min.js') }}"></script>
|
||||||
<script src="{{ asset('assets/js/icons/feather-icon/feather-icon.js')}}"></script>
|
<script src="{{ asset('assets/js/icons/feather-icon/feather-icon.js') }}"></script>
|
||||||
<!-- Sidebar jquery-->
|
<!-- Sidebar jquery-->
|
||||||
<script src="{{ asset('assets/js/sidebar-menu.js')}}"></script>
|
<script src="{{ asset('assets/js/sidebar-menu.js') }}"></script>
|
||||||
<script src="{{ asset('assets/js/config.js')}}"></script>
|
<script src="{{ asset('assets/js/config.js') }}"></script>
|
||||||
<!-- Bootstrap js-->
|
<!-- Bootstrap js-->
|
||||||
<script src="{{ asset('assets/js/bootstrap/popper.min.js')}}"></script>
|
<script src="{{ asset('assets/js/bootstrap/popper.min.js') }}"></script>
|
||||||
<script src="{{ asset('assets/js/bootstrap/bootstrap.min.js')}}"></script>
|
<script src="{{ asset('assets/js/bootstrap/bootstrap.min.js') }}"></script>
|
||||||
<!-- Plugins JS start-->
|
<!-- Plugins JS start-->
|
||||||
<!-- Plugins JS Ends-->
|
<!-- Plugins JS Ends-->
|
||||||
<!-- Theme js-->
|
<!-- Theme js-->
|
||||||
<script src="{{ asset('assets/js/script.js')}}"></script>
|
<script src="{{ asset('assets/js/script.js') }}"></script>
|
||||||
<!-- login js-->
|
<!-- login js-->
|
||||||
<!-- Plugin used-->
|
<!-- Plugin used-->
|
||||||
<script src="{{ asset('assets/js/icons/icons-notify.js') }}"></script>
|
<script src="{{ asset('assets/js/icons/icons-notify.js') }}"></script>
|
||||||
@@ -486,7 +971,7 @@
|
|||||||
let ultimoCNPJ = '';
|
let ultimoCNPJ = '';
|
||||||
let timeout = null;
|
let timeout = null;
|
||||||
|
|
||||||
document.getElementById('cnpj').addEventListener('input', function () {
|
document.getElementById('cnpj').addEventListener('input', function() {
|
||||||
let cnpj = this.value.replace(/\D/g, '');
|
let cnpj = this.value.replace(/\D/g, '');
|
||||||
|
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
@@ -550,7 +1035,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
document.getElementById('tipo_envio').addEventListener('change', function () {
|
document.getElementById('tipo_envio').addEventListener('change', function() {
|
||||||
const campoImagem = document.getElementById('campoImagem');
|
const campoImagem = document.getElementById('campoImagem');
|
||||||
|
|
||||||
if (this.value === 'imagem') {
|
if (this.value === 'imagem') {
|
||||||
@@ -561,7 +1046,6 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
40
resources/views/usuarios/index.blade.php
Normal file
40
resources/views/usuarios/index.blade.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
@extends('theme.default')
|
||||||
|
@section('title', 'Dashboard')
|
||||||
|
@section('title.page', 'Dashboard')
|
||||||
|
@section('title.page1', 'Escola da árvore')
|
||||||
|
@section('title.page2', 'Home')
|
||||||
|
@section('title.page3', 'Dashboard')
|
||||||
|
@section('content')
|
||||||
|
<div class="container-fluid user-card">
|
||||||
|
<div class="row">
|
||||||
|
@foreach ($usuarios as $usuario)
|
||||||
|
<div class="col-md-6 col-lg-6 col-xl-4 box-col-6">
|
||||||
|
<div class="card custom-card">
|
||||||
|
<div class="card-header"><img class="img-fluid" src="https://bucket.cciti.com.br/cae/images/banner_user.png" alt=""></div>
|
||||||
|
<div class="card-profile"><img class="rounded-circle" src="https://bucket.cciti.com.br/cae/images/logo3.png" alt=""></div>
|
||||||
|
<div class="text-center profile-details"><a href="user-profile.html">
|
||||||
|
<h4>{{ $usuario->name }}</h4>
|
||||||
|
</a>
|
||||||
|
<h6>{{$usuario->funcao()}}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer row">
|
||||||
|
<div class="col-4 col-sm-4">
|
||||||
|
<h6>Follower</h6>
|
||||||
|
<h3 class="counter">9564</h3>
|
||||||
|
</div>
|
||||||
|
<div class="col-4 col-sm-4">
|
||||||
|
<h6>Following</h6>
|
||||||
|
<h3><span class="counter">49</span>K</h3>
|
||||||
|
</div>
|
||||||
|
<div class="col-4 col-sm-4">
|
||||||
|
<h6>Total Post</h6>
|
||||||
|
<h3><span class="counter">96</span>M</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
@@ -5,6 +5,7 @@ use App\Http\Controllers\EnvioWhatsap;
|
|||||||
use App\Http\Controllers\EscolasController;
|
use App\Http\Controllers\EscolasController;
|
||||||
use App\Http\Controllers\ProfileController;
|
use App\Http\Controllers\ProfileController;
|
||||||
use App\Http\Controllers\TurmasController;
|
use App\Http\Controllers\TurmasController;
|
||||||
|
use App\Http\Controllers\UsersController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
|
||||||
@@ -26,11 +27,18 @@ Route::middleware('auth')->group(function () {
|
|||||||
})->name('dashboard');
|
})->name('dashboard');
|
||||||
Route::get('/escolas', [EscolasController::class, 'index'])->name('escolas');
|
Route::get('/escolas', [EscolasController::class, 'index'])->name('escolas');
|
||||||
Route::post('/escolas', [EscolasController::class, 'createOrUpdate'])->name('escola.novo');
|
Route::post('/escolas', [EscolasController::class, 'createOrUpdate'])->name('escola.novo');
|
||||||
Route::get('/turmas', [TurmasController::class, 'index'])->name('turmas');
|
Route::get('/turmas', [TurmasController::class, 'index'])->name('turmas')->middleware('role:admin|super_admin');
|
||||||
Route::get('/turmas/{id}', [TurmasController::class, 'detalhes'])->name('turmas.detalhes');
|
Route::get('/turmas/{id}', [TurmasController::class, 'detalhes'])->name('turmas.detalhes');
|
||||||
Route::post('/turmas', [TurmasController::class, 'createOrUpdate'])->name('turma.novo');
|
Route::post('/turmas', [TurmasController::class, 'createOrUpdate'])->name('turma.novo');
|
||||||
Route::get('/alunos', [AlunosController::class, 'index'])->name('alunos');
|
Route::get('/alunos', [AlunosController::class, 'index'])->name('alunos')->middleware('permission:alunos.ver_todos|alunos.ver_meus');
|
||||||
|
Route::post('/alunos', [AlunosController::class, 'updateOrCreate'])->name('alunos.add')->middleware('role:super_admin');
|
||||||
Route::post('/envio-wpp', [EnvioWhatsap::class, 'envio'])->name('envio.wpp');
|
Route::post('/envio-wpp', [EnvioWhatsap::class, 'envio'])->name('envio.wpp');
|
||||||
|
Route::get('/usuarios', [UsersController::class, 'index'])->name('usuarios')->middleware('role:super_admin');
|
||||||
|
Route::post('/usuarios', [UsersController::class, 'store'])->name('usuarios.add')->middleware('role:super_admin');
|
||||||
|
Route::get('/api/escolas/{escola}/turmas', [TurmasController::class, 'byEscola'])->name('api.escolas.turmas');
|
||||||
|
Route::get('/api/escolas/{escola}/roles', [UsersController::class, 'rolesByEscola'])->name('api.escolas.roles');
|
||||||
|
|
||||||
|
Route::get('/api/escolas/{escola}/alunos', [UsersController::class, 'alunosByEscola'])->name('api.escolas.alunos');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user