Atualizacao
This commit is contained in:
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
|||||||
use App\Models\turmas;
|
use App\Models\turmas;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use App\Jobs\Envio_Mensagem_Whatsapp;
|
||||||
|
|
||||||
class EnvioWhatsap extends Controller
|
class EnvioWhatsap extends Controller
|
||||||
{
|
{
|
||||||
@@ -14,48 +15,17 @@ class EnvioWhatsap extends Controller
|
|||||||
'id_turma' => 'required|exists:turmas,id',
|
'id_turma' => 'required|exists:turmas,id',
|
||||||
'tipo_envio' => 'required|in:texto,imagem',
|
'tipo_envio' => 'required|in:texto,imagem',
|
||||||
'mensagem' => 'nullable|string',
|
'mensagem' => 'nullable|string',
|
||||||
'imagem' => 'required_if:tipo_envio,imagem|image|mimes:jpeg,png,webp|max:2048',
|
'imagem' => 'required_if:tipo_envio,imagem|image|mimes:jpeg,png,webp|max:8192',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$turma = turmas::findOrFail($request->id_turma);
|
// 🔥 Apenas coleta os dados brutos
|
||||||
|
Envio_Mensagem_Whatsapp::dispatch(
|
||||||
// Corrigir formatação para WhatsApp
|
$request->id_turma,
|
||||||
$mensagem = $request->mensagem ?? '';
|
$request->tipo_envio,
|
||||||
$mensagem = str_replace(['**', '__', '~~'], ['*', '_', '~'], $mensagem);
|
$request->mensagem,
|
||||||
|
$request->file('imagem')?->store('tmp') // salva temporariamente
|
||||||
$payload = [
|
|
||||||
'chatId' => $turma->id_whatsapp,
|
|
||||||
'mensagem' => $mensagem,
|
|
||||||
];
|
|
||||||
|
|
||||||
// ✅ Se for envio com imagem
|
|
||||||
if ($request->tipo_envio === 'imagem' && $request->hasFile('imagem')) {
|
|
||||||
|
|
||||||
$file = $request->file('imagem');
|
|
||||||
|
|
||||||
$base64 = base64_encode(
|
|
||||||
file_get_contents($file->getRealPath())
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$mime = $file->getMimeType(); // image/png, image/jpeg, etc
|
return back()->with('success', 'Envio colocado na fila com sucesso!');
|
||||||
|
|
||||||
// 🔥 AQUI está o prefixo obrigatório
|
|
||||||
$base64Completo = "data:$mime;base64,$base64";
|
|
||||||
|
|
||||||
$payload['imagem'] = $base64Completo;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Enviar para API
|
|
||||||
$response = Http::withHeaders([
|
|
||||||
'X-API-KEY' => 'UoCkSF4ApgADhpvDkkE5XO1fD761yOZX',
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
])->post('https://n8n.cae.app.br/webhook/envioWpp', $payload);
|
|
||||||
|
|
||||||
// ✅ Retorno amigável
|
|
||||||
if ($response->successful()) {
|
|
||||||
return back()->with('success', 'Mensagem enviada com sucesso!');
|
|
||||||
}
|
|
||||||
|
|
||||||
return back()->with('error', 'Erro ao enviar: ' . $response->body());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
app/Http/Controllers/EnviosWppController.php
Normal file
10
app/Http/Controllers/EnviosWppController.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class EnviosWppController extends Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -49,4 +49,9 @@ class TurmasController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function detalhes ($id) {
|
||||||
|
$turma = turmas::findOrFail($id);
|
||||||
|
return view('escolas.turmas_detalhes', compact('turma'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
270
app/Jobs/Envio_Mensagem_Whatsapp.php
Normal file
270
app/Jobs/Envio_Mensagem_Whatsapp.php
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Models\turmas;
|
||||||
|
use App\Models\envios_wpp;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class Envio_Mensagem_Whatsapp implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $tries = 3;
|
||||||
|
public $timeout = 120;
|
||||||
|
|
||||||
|
public string $jobUuid;
|
||||||
|
|
||||||
|
protected $idTurma;
|
||||||
|
protected $tipoEnvio;
|
||||||
|
protected $mensagem;
|
||||||
|
protected $caminhoImagem;
|
||||||
|
|
||||||
|
public function __construct($idTurma, $tipoEnvio, $mensagem = null, $caminhoImagem = null)
|
||||||
|
{
|
||||||
|
$this->idTurma = $idTurma;
|
||||||
|
$this->tipoEnvio = $tipoEnvio;
|
||||||
|
$this->mensagem = $mensagem;
|
||||||
|
$this->caminhoImagem = $caminhoImagem;
|
||||||
|
$this->jobUuid = str_replace('-', '', Str::uuid()->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$turma = turmas::findOrFail($this->idTurma);
|
||||||
|
$detalhes = [];
|
||||||
|
|
||||||
|
|
||||||
|
// ✅ Corrigir formatação WhatsApp
|
||||||
|
$mensagem = $this->mensagem ?? '';
|
||||||
|
$mensagem = str_replace(['**', '__', '~~'], ['*', '_', '~'], $mensagem);
|
||||||
|
|
||||||
|
if ($this->tipoEnvio === 'imagem' && $this->caminhoImagem) {
|
||||||
|
|
||||||
|
$conteudo = Storage::get($this->caminhoImagem);
|
||||||
|
$mime = Storage::mimeType($this->caminhoImagem);
|
||||||
|
|
||||||
|
$base64 = base64_encode($conteudo);
|
||||||
|
$imagem = "data:$mime;base64,$base64";
|
||||||
|
|
||||||
|
// 🧹 Remove arquivo temporário
|
||||||
|
Storage::delete($this->caminhoImagem);
|
||||||
|
$existeImagem = true;
|
||||||
|
} else {
|
||||||
|
$existeImagem = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$detalhes['etapas'][] = [
|
||||||
|
'tipo de evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'mensagem' => $mensagem,
|
||||||
|
'imagem' => $existeImagem,
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Em andamento',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'mensagem' => $detalhes,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Log::error('Erro, segue: ', [
|
||||||
|
'erro' => $th->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'mensagem' => $detalhes,
|
||||||
|
'Erro: ' => $th->getMessage(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->tipoEnvio) {
|
||||||
|
case 'texto':
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'accept' => 'application/json',
|
||||||
|
'token' => '3aCSVE4jS9h233mNBr1awz3DF0In8CFk',
|
||||||
|
])
|
||||||
|
->post('https://waha.cae.app.br/chat/send/text', [
|
||||||
|
'phone' => $turma->id_whatsapp,
|
||||||
|
'body' => $mensagem,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->json()['code'] == 200) {
|
||||||
|
|
||||||
|
$detalhes['etapas'][] = [
|
||||||
|
'tipo de evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'mensagem' => 'Mensagem enviada com sucessl'
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Concluido',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'mensagem' => $detalhes,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Log::error('Erro, segue: ', [
|
||||||
|
'erro' => $th->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'Erro: ' => $th->getMessage(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$detalhes['etapas'][] = [
|
||||||
|
'tipo de evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'mensagem' => 'Mensagem não enviada'
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'mensagem' => $detalhes,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Log::error('Erro, segue: ', [
|
||||||
|
'erro' => $th->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'Erro: ' => $th->getMessage(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'imagem';
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'accept' => 'application/json',
|
||||||
|
'token' => '3aCSVE4jS9h233mNBr1awz3DF0In8CFk',
|
||||||
|
])
|
||||||
|
->post('https://waha.cae.app.br/chat/send/image', [
|
||||||
|
'phone' => $turma->id_whatsapp,
|
||||||
|
'caption' => $mensagem,
|
||||||
|
'image' => $imagem,
|
||||||
|
]);
|
||||||
|
if ($response->json()['code'] == 200) {
|
||||||
|
|
||||||
|
$detalhes['etapas'][] = [
|
||||||
|
'tipo de evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'mensagem' => 'Mensagem enviada com sucessl'
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Concluido',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'mensagem' => $detalhes,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Log::error('Erro, segue: ', [
|
||||||
|
'erro' => $th->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'Erro: ' => $th->getMessage(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$detalhes['etapas'][] = [
|
||||||
|
'tipo de evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'mensagem' => 'Mensagem não enviada'
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'mensagem' => $detalhes,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Log::error('Erro, segue: ', [
|
||||||
|
'erro' => $th->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
envios_wpp::updateOrCreate(['id_job' => $this->jobUuid], [
|
||||||
|
'id_job' => $this->jobUuid,
|
||||||
|
'status' => 'Erro',
|
||||||
|
'id_turma' => $this->idTurma,
|
||||||
|
'detalhes' => [
|
||||||
|
'tipo_de_evento' => $this->tipoEnvio,
|
||||||
|
'data' => now()->format('d-m-Y H:i:s'),
|
||||||
|
'Erro: ' => $th->getMessage(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
# code...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tags()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'turma: ' . $this->idTurma,
|
||||||
|
'tipo: ' . $this->tipoEnvio,
|
||||||
|
'jobId: ' . $this->jobUuid,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
app/Models/envios_wpp.php
Normal file
20
app/Models/envios_wpp.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class envios_wpp extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'status',
|
||||||
|
'id_turma',
|
||||||
|
'detalhes',
|
||||||
|
'id_job',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'detalhes' => 'array',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -19,4 +19,8 @@ class turmas extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(alunos::class, 'id', 'id_turma');
|
return $this->hasMany(alunos::class, 'id', 'id_turma');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function enviosWpp() {
|
||||||
|
return $this->hasMany(envios_wpp::class, 'id_turma', 'id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
app/Providers/HorizonServiceProvider.php
Normal file
36
app/Providers/HorizonServiceProvider.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Laravel\Horizon\Horizon;
|
||||||
|
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
||||||
|
|
||||||
|
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
// Horizon::routeSmsNotificationsTo('15556667777');
|
||||||
|
// Horizon::routeMailNotificationsTo('example@example.com');
|
||||||
|
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the Horizon gate.
|
||||||
|
*
|
||||||
|
* This gate determines who can access Horizon in non-local environments.
|
||||||
|
*/
|
||||||
|
protected function gate(): void
|
||||||
|
{
|
||||||
|
Gate::define('viewHorizon', function ($user = null) {
|
||||||
|
return in_array(optional($user)->email, [
|
||||||
|
//
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
|
App\Providers\HorizonServiceProvider::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"laravel/breeze": "^2.3",
|
"laravel/breeze": "^2.3",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
|
"laravel/horizon": "^5.44",
|
||||||
"laravel/tinker": "^2.10.1"
|
"laravel/tinker": "^2.10.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|||||||
81
composer.lock
generated
81
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "5932c2eb38775299ed7dde1304f360d8",
|
"content-hash": "9898179818d19ab28a9c001b5b54d46e",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
@@ -1335,6 +1335,85 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-02-04T18:34:13+00:00"
|
"time": "2026-02-04T18:34:13+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "laravel/horizon",
|
||||||
|
"version": "v5.44.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/laravel/horizon.git",
|
||||||
|
"reference": "00c21e4e768112cce3f4fe576d75956dfc423de2"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/laravel/horizon/zipball/00c21e4e768112cce3f4fe576d75956dfc423de2",
|
||||||
|
"reference": "00c21e4e768112cce3f4fe576d75956dfc423de2",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-pcntl": "*",
|
||||||
|
"ext-posix": "*",
|
||||||
|
"illuminate/contracts": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||||
|
"illuminate/queue": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||||
|
"illuminate/support": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||||
|
"nesbot/carbon": "^2.17|^3.0",
|
||||||
|
"php": "^8.0",
|
||||||
|
"ramsey/uuid": "^4.0",
|
||||||
|
"symfony/console": "^6.0|^7.0|^8.0",
|
||||||
|
"symfony/error-handler": "^6.0|^7.0|^8.0",
|
||||||
|
"symfony/polyfill-php83": "^1.28",
|
||||||
|
"symfony/process": "^6.0|^7.0|^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mockery/mockery": "^1.0",
|
||||||
|
"orchestra/testbench": "^7.55|^8.36|^9.15|^10.8|^11.0",
|
||||||
|
"phpstan/phpstan": "^1.10|^2.0",
|
||||||
|
"predis/predis": "^1.1|^2.0|^3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-redis": "Required to use the Redis PHP driver.",
|
||||||
|
"predis/predis": "Required when not using the Redis PHP driver (^1.1|^2.0|^3.0)."
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"aliases": {
|
||||||
|
"Horizon": "Laravel\\Horizon\\Horizon"
|
||||||
|
},
|
||||||
|
"providers": [
|
||||||
|
"Laravel\\Horizon\\HorizonServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "6.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Laravel\\Horizon\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Otwell",
|
||||||
|
"email": "taylor@laravel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Dashboard and code-driven configuration for Laravel queues.",
|
||||||
|
"keywords": [
|
||||||
|
"laravel",
|
||||||
|
"queue"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/horizon/issues",
|
||||||
|
"source": "https://github.com/laravel/horizon/tree/v5.44.0"
|
||||||
|
},
|
||||||
|
"time": "2026-02-10T18:18:08+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/prompts",
|
"name": "laravel/prompts",
|
||||||
"version": "v0.3.12",
|
"version": "v0.3.12",
|
||||||
|
|||||||
254
config/horizon.php
Normal file
254
config/horizon.php
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This name appears in notifications and in the Horizon UI. Unique names
|
||||||
|
| can be useful while running multiple instances of Horizon within an
|
||||||
|
| application, allowing you to identify the Horizon you're viewing.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'name' => env('HORIZON_NAME'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the subdomain where Horizon will be accessible from. If this
|
||||||
|
| setting is null, Horizon will reside under the same domain as the
|
||||||
|
| application. Otherwise, this value will serve as the subdomain.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'domain' => env('HORIZON_DOMAIN'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the URI path where Horizon will be accessible from. Feel free
|
||||||
|
| to change this path to anything you like. Note that the URI will not
|
||||||
|
| affect the paths of its internal API that aren't exposed to users.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'path' => env('HORIZON_PATH', 'horizon'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Redis Connection
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the name of the Redis connection where Horizon will store the
|
||||||
|
| meta information required for it to function. It includes the list
|
||||||
|
| of supervisors, failed jobs, job metrics, and other information.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use' => 'default',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Redis Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This prefix will be used when storing all Horizon data in Redis. You
|
||||||
|
| may modify the prefix when you are running multiple installations
|
||||||
|
| of Horizon on the same server so that they don't have problems.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env(
|
||||||
|
'HORIZON_PREFIX',
|
||||||
|
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
|
||||||
|
),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Route Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These middleware will get attached onto each Horizon route, giving you
|
||||||
|
| the chance to add your own middleware to this list or change any of
|
||||||
|
| the existing middleware. Or, you can simply stick with this list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => ['web'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Wait Time Thresholds
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to configure when the LongWaitDetected event
|
||||||
|
| will be fired. Every connection / queue combination may have its
|
||||||
|
| own, unique threshold (in seconds) before this event is fired.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'waits' => [
|
||||||
|
'redis:default' => 60,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Job Trimming Times
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you can configure for how long (in minutes) you desire Horizon to
|
||||||
|
| persist the recent and failed jobs. Typically, recent jobs are kept
|
||||||
|
| for one hour while all failed jobs are stored for an entire week.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'recent' => 60,
|
||||||
|
'pending' => 60,
|
||||||
|
'completed' => 60,
|
||||||
|
'recent_failed' => 10080,
|
||||||
|
'failed' => 10080,
|
||||||
|
'monitored' => 10080,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Silenced Jobs
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Silencing a job will instruct Horizon to not place the job in the list
|
||||||
|
| of completed jobs within the Horizon dashboard. This setting may be
|
||||||
|
| used to fully remove any noisy jobs from the completed jobs list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'silenced' => [
|
||||||
|
// App\Jobs\ExampleJob::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'silenced_tags' => [
|
||||||
|
// 'notifications',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Metrics
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you can configure how many snapshots should be kept to display in
|
||||||
|
| the metrics graph. This will get used in combination with Horizon's
|
||||||
|
| `horizon:snapshot` schedule to define how long to retain metrics.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'metrics' => [
|
||||||
|
'trim_snapshots' => [
|
||||||
|
'job' => 24,
|
||||||
|
'queue' => 24,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Fast Termination
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When this option is enabled, Horizon's "terminate" command will not
|
||||||
|
| wait on all of the workers to terminate unless the --wait option
|
||||||
|
| is provided. Fast termination can shorten deployment delay by
|
||||||
|
| allowing a new instance of Horizon to start while the last
|
||||||
|
| instance will continue to terminate each of its workers.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'fast_termination' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Memory Limit (MB)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value describes the maximum amount of memory the Horizon master
|
||||||
|
| supervisor may consume before it is terminated and restarted. For
|
||||||
|
| configuring these limits on your workers, see the next section.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'memory_limit' => 64,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Worker Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define the queue worker settings used by your application
|
||||||
|
| in all environments. These supervisors and settings handle all your
|
||||||
|
| queued jobs and will be provisioned by Horizon during deployment.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'defaults' => [
|
||||||
|
'supervisor-1' => [
|
||||||
|
'connection' => 'redis',
|
||||||
|
'queue' => ['default'],
|
||||||
|
'balance' => 'auto',
|
||||||
|
'autoScalingStrategy' => 'time',
|
||||||
|
'maxProcesses' => 1,
|
||||||
|
'maxTime' => 0,
|
||||||
|
'maxJobs' => 0,
|
||||||
|
'memory' => 128,
|
||||||
|
'tries' => 1,
|
||||||
|
'timeout' => 60,
|
||||||
|
'nice' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'environments' => [
|
||||||
|
'production' => [
|
||||||
|
'supervisor-1' => [
|
||||||
|
'maxProcesses' => 10,
|
||||||
|
'balanceMaxShift' => 1,
|
||||||
|
'balanceCooldown' => 3,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'local' => [
|
||||||
|
'supervisor-1' => [
|
||||||
|
'maxProcesses' => 3,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| File Watcher Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following list of directories and files will be watched when using
|
||||||
|
| the `horizon:listen` command. Whenever any directories or files are
|
||||||
|
| changed, Horizon will automatically restart to apply all changes.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'watch' => [
|
||||||
|
'app',
|
||||||
|
'bootstrap',
|
||||||
|
'config/**/*.php',
|
||||||
|
'database/**/*.php',
|
||||||
|
'public/**/*.php',
|
||||||
|
'resources/**/*.php',
|
||||||
|
'routes',
|
||||||
|
'composer.lock',
|
||||||
|
'composer.json',
|
||||||
|
'.env',
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -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::create('envios_wpps', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->integer('id_turma');
|
||||||
|
$table->string('status');
|
||||||
|
$table->json('detalhes');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('envios_wpps');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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('envios_wpps', function (Blueprint $table) {
|
||||||
|
$table->string('id_job')->after('id_turma');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('envios_wpp', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($turmas as $turma)
|
@foreach ($turmas as $turma)
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{{ $turma->id }}</th>
|
<th scope="row"><a href="{{ route('turmas.detalhes', $turma->id) }}">{{ $turma->id }}</a></th>
|
||||||
<td>{{ $turma->escola->nome }}</td>
|
<td>{{ $turma->escola->nome }}</td>
|
||||||
<td>{{ $turma->nome }}</td>
|
<td>{{ $turma->nome }}</td>
|
||||||
<td>{{ $turma->descricao }}</td>
|
<td>{{ $turma->descricao }}</td>
|
||||||
|
|||||||
1029
resources/views/escolas/turmas_detalhes.blade.php
Normal file
1029
resources/views/escolas/turmas_detalhes.blade.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@ Route::middleware('auth')->group(function () {
|
|||||||
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');
|
||||||
|
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');
|
||||||
Route::post('/envio-wpp', [EnvioWhatsap::class, 'envio'])->name('envio.wpp');
|
Route::post('/envio-wpp', [EnvioWhatsap::class, 'envio'])->name('envio.wpp');
|
||||||
|
|||||||
Reference in New Issue
Block a user