First Commit

This commit is contained in:
marco
2026-09-01 10:46:29 -03:00
commit bf96b77e9c
10000 changed files with 3508600 additions and 0 deletions
+692
View File
@@ -0,0 +1,692 @@
<?php
namespace Modules\Company\Controllers;
use App\Controllers\BaseAdminController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Modules\Company\Models\Company;
use App\Models\Module;
use App\Helpers\Log;
use App\Helpers\Crypto;
use Intervention\Image\ImageManagerStatic as Image;
use Kernel\License;
class CompanyController extends BaseAdminController
{
public function index(Request $request): Response
{
$user = $this->getCurrentUser();
// Allow access to SuperAdmin, Admin, or Member with company.view permission
$hasAccess = $user && (
$user->isSuperAdmin() ||
$user->isAdmin() ||
($user->isMember() && $user->hasPermission('company.view'))
);
if (!$hasAccess) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
if ($user->isSuperAdmin()) {
$companies = Company::all();
} else {
$companies = Company::where('bus_id', $user->users_bus_id)->get();
}
return $this->renderAdminView('company/views/admin/index.twig', [
'companies' => $companies,
'title' => 'Companies Management',
'can_create_company' => $user->isSuperAdmin() && License::canCreateCompany()
]);
}
public function settings(Request $request): Response
{
$user = $this->getCurrentUser();
if (!$user) {
return new RedirectResponse(url('login'));
}
if ($user->isSuperAdmin()) {
return new RedirectResponse(url('admin/companies'));
}
return $this->edit($request, $user->users_bus_id);
}
public function create(Request $request): Response
{
$user = $this->getCurrentUser();
if (!$user || !$user->isSuperAdmin()) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
if (!License::canCreateCompany()) {
return new RedirectResponse(url('admin/companies?error=license_limit'));
}
$error = $request->query->get('error');
$errorMessage = $error ? $this->getErrorMessage($error) : null;
$modules = Module::active()->ordered()->get();
return $this->renderAdminView('company/views/admin/form.twig', [
'title' => 'Create Company',
'error' => $errorMessage,
'target_company' => null,
'modules' => $modules
]);
}
public function store(Request $request): Response
{
$user = $this->getCurrentUser();
if (!$user || !$user->isSuperAdmin()) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$currentUserId = $_SESSION['user_id'] ?? null;
$currentUserRole = $_SESSION['user_role'] ?? null;
$currentUserBus = $_SESSION['user_idbus'] ?? null;
$data = $request->request->all();
// Basic validation
if (empty($data['name']) || empty($data['email'])) {
return new RedirectResponse(url('admin/companies/create?error=missing_fields'));
}
// Email format validation
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return new RedirectResponse(url('admin/companies/create?error=invalid_email'));
}
// Check if email exists
if (Company::where('bus_email', $data['email'])->exists()) {
return new RedirectResponse(url('admin/companies/create?error=email_exists'));
}
// Generate slug from name
$slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $data['name'])));
// Check if slug exists
if (Company::where('bus_slug', $slug)->exists()) {
$slug .= '-' . time();
}
$company = new Company();
$company->bus_name = $data['name'];
$company->bus_slug = $slug;
$company->bus_description = $data['description'] ?? '';
$company->bus_email = $data['email'];
$company->bus_phone = $data['phone'] ?? '';
$company->bus_address = $data['address'] ?? '';
$company->bus_city = $data['city'] ?? '';
$company->bus_state = $data['state'] ?? '';
$company->bus_country = $data['country'] ?? '';
$company->bus_postal_code = $data['postal_code'] ?? '';
$company->bus_website = $data['website'] ?? '';
$company->bus_tax_id = $data['tax_id'] ?? '';
$company->bus_type = $data['bus_type'] ?? 'business';
$company->bus_status = $data['status'] ?? 'active';
$company->platform_name = $data['platform_name'] ?? '';
// Encrypt OpenRouter API Key if present
$newApiKey = $data['openrouter_api_key'] ?? '';
if (!empty($newApiKey) && strpos($newApiKey, '***') === false) {
$company->openrouter_api_key = Crypto::encrypt($newApiKey);
}
$company->ai_provider = $data['ai_provider'] ?? 'openrouter';
$company->ai_model = $data['ai_model'] ?? 'google/gemini-2.0-flash-001';
$company->ai_endpoint = $data['ai_endpoint'] ?? '';
// Settings are now handled via modules table
// $company->bus_settings = $data['bus_settings'] ?? [];
$company->save();
// Handle modules - ONLY Super Admin can change which modules a company has access to
if ($user->isSuperAdmin()) {
$modulesData = $request->request->all()['modules'] ?? [];
$syncData = [];
foreach ($modulesData as $moduleId => $settings) {
$syncData[$moduleId] = [
'bus_modules_is_enabled' => isset($settings['enabled']),
'bus_modules_enabled_by' => $currentUserId,
'bus_modules_enabled_at' => \Carbon\Carbon::now(),
'bus_modules_show_public_nav' => isset($settings['public']),
'bus_modules_show_dashboard_nav' => isset($settings['dashboard'])
];
}
if (!empty($syncData)) {
$company->modules()->sync($syncData);
} else {
$company->modules()->detach();
}
}
if ($request->files->has('logo')) {
$file = $request->files->get('logo');
if ($file && $file->isValid()) {
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (in_array($file->getMimeType(), $allowedMimes)) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/logos';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$formatSetting = strtolower((string) get_env('IMG_FORMAT', 'webp'));
$format = $formatSetting === 'auto' ? 'webp' : $formatSetting;
$quality = env_int('IMG_QUALITY', 80);
$resolutionPercent = env_int('IMG_RESOLUTION', 100);
$image = Image::make($file->getPathname());
$width = $image->width();
$height = $image->height();
if ($resolutionPercent > 0 && $resolutionPercent < 100) {
$newW = (int) round($width * $resolutionPercent / 100);
$newH = (int) round($height * $resolutionPercent / 100);
$image->resize($newW, $newH, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
}
$ext = $format === 'jpeg' || $format === 'jpg' ? 'jpg' : ($format === 'png' ? 'png' : ($format === 'gif' ? 'gif' : 'webp'));
$filename = 'logo_' . $company->bus_id . '_' . time() . '.' . $ext;
if ($format === 'jpeg' || $format === 'jpg') {
$image->interlace(true);
$image->encode('jpeg', max(1, min(100, $quality)));
} elseif ($format === 'png') {
$pngCompression = max(0, min(9, (int) round((100 - max(1, min(100, $quality))) / 10)));
$image->encode('png', $pngCompression);
} elseif ($format === 'gif') {
$image->encode('gif');
} else {
$image->encode('webp', max(1, min(100, $quality)));
}
$image->save($uploadDir . '/' . $filename);
// Delete old logo if exists (check both old and new directories)
if ($company->bus_logo) {
$oldDirs = [
dirname(__DIR__, 4) . '/storage/uploads/logos',
dirname(__DIR__, 4) . '/storage/uploads/company/logos'
];
foreach ($oldDirs as $dir) {
$oldFile = $dir . '/' . $company->bus_logo;
if (file_exists($oldFile)) {
unlink($oldFile);
break; // Delete only once
}
}
}
$company->bus_logo = $filename;
}
}
}
// Handle business card upload
if ($request->files->has('business_card')) {
$file = $request->files->get('business_card');
if ($file && $file->isValid()) {
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (in_array($file->getMimeType(), $allowedMimes)) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/business-cards';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$formatSetting = strtolower((string) get_env('IMG_FORMAT', 'webp'));
$format = $formatSetting === 'auto' ? 'webp' : $formatSetting;
$quality = env_int('IMG_QUALITY', 80);
$resolutionPercent = env_int('IMG_RESOLUTION', 100);
$image = Image::make($file->getPathname());
$width = $image->width();
$height = $image->height();
if ($resolutionPercent > 0 && $resolutionPercent < 100) {
$newW = (int) round($width * $resolutionPercent / 100);
$newH = (int) round($height * $resolutionPercent / 100);
$image->resize($newW, $newH, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
}
$ext = $format === 'jpeg' || $format === 'jpg' ? 'jpg' : ($format === 'png' ? 'png' : ($format === 'gif' ? 'gif' : 'webp'));
$filename = 'business_card_' . $company->bus_id . '_' . time() . '.' . $ext;
if ($format === 'jpeg' || $format === 'jpg') {
$image->interlace(true);
$image->encode('jpeg', max(1, min(100, $quality)));
} elseif ($format === 'png') {
$pngCompression = max(0, min(9, (int) round((100 - max(1, min(100, $quality))) / 10)));
$image->encode('png', $pngCompression);
} elseif ($format === 'gif') {
$image->encode('gif');
} else {
$image->encode('webp', max(1, min(100, $quality)));
}
$image->save($uploadDir . '/' . $filename);
// Delete old business card if exists (check both old and new directories)
if ($company->bus_business_card) {
$oldDirs = [
dirname(__DIR__, 4) . '/storage/uploads/business-cards',
dirname(__DIR__, 4) . '/storage/uploads/company/business-cards'
];
foreach ($oldDirs as $dir) {
$oldFile = $dir . '/' . $company->bus_business_card;
if (file_exists($oldFile)) {
unlink($oldFile);
break; // Delete only once
}
}
}
$company->bus_business_card = $filename;
}
}
}
// Handle document upload
if ($request->files->has('document')) {
$file = $request->files->get('document');
if ($file && $file->isValid()) {
$allowedMimes = [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation'
];
if (in_array($file->getMimeType(), $allowedMimes)) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/documents';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$originalName = $file->getClientOriginalName();
$filename = 'document_' . $company->bus_id . '_' . time() . '_' . $originalName;
$file->move($uploadDir, $filename);
// Delete old document if exists (check both old and new directories)
if ($company->bus_document) {
$oldDirs = [
dirname(__DIR__, 4) . '/storage/uploads/documents',
dirname(__DIR__, 4) . '/storage/uploads/company/documents'
];
foreach ($oldDirs as $dir) {
$oldFile = $dir . '/' . $company->bus_document;
if (file_exists($oldFile)) {
unlink($oldFile);
break; // Delete only once
}
}
}
$company->bus_document = $filename;
}
}
}
$company->save();
// Restore session to ensure super_admin remains logged
$_SESSION['user_id'] = $currentUserId;
$_SESSION['user_role'] = $currentUserRole;
$_SESSION['user_idbus'] = $currentUserBus;
return new RedirectResponse(url('admin/companies'));
}
public function show(Request $request, string $id): Response
{
$user = $this->getCurrentUser();
if (!$user || (!$user->isSuperAdmin() && $user->users_bus_id != $id)) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$company = Company::find($id);
if (!$company) {
return new RedirectResponse(url('admin/companies'));
}
return $this->renderAdminView('company/views/admin/show.twig', [
'company' => $company,
'title' => 'Company Details'
]);
}
public function edit(Request $request, string $id): Response
{
$user = $this->getCurrentUser();
if (!$user || (!$user->isSuperAdmin() && $user->users_bus_id != $id)) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$company = Company::find($id);
if (!$company) {
return new RedirectResponse(url('admin/companies'));
}
// Mask the API Key for the view
if ($company->openrouter_api_key) {
$company->openrouter_api_key = substr(Crypto::decrypt($company->openrouter_api_key), 0, 8) . '****************';
}
$error = $request->query->get('error');
$errorMessage = $error ? $this->getErrorMessage($error) : null;
$modules = Module::active()->ordered()->get();
return $this->renderAdminView('company/views/admin/form.twig', [
'target_company' => $company,
'title' => 'Edit Company',
'error' => $errorMessage,
'modules' => $modules
]);
}
public function update(Request $request, string $id): Response
{
$user = $this->getCurrentUser();
if (!$user || (!$user->isSuperAdmin() && $user->users_bus_id != $id)) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$currentUserId = $_SESSION['user_id'] ?? null;
$currentUserRole = $_SESSION['user_role'] ?? null;
$currentUserBus = $_SESSION['user_idbus'] ?? null;
$company = Company::find($id);
if (!$company) {
return new RedirectResponse(url('admin/companies'));
}
$data = $request->request->all();
// Basic validation
if (empty($data['name']) || empty($data['email'])) {
return new RedirectResponse(url('admin/companies/' . $id . '/edit?error=missing_fields'));
}
// Email format validation
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return new RedirectResponse(url('admin/companies/' . $id . '/edit?error=invalid_email'));
}
// Check if email exists (exclude current company)
if ($data['email'] !== $company->bus_email && Company::where('bus_email', $data['email'])->exists()) {
return new RedirectResponse(url('admin/companies/' . $id . '/edit?error=email_exists'));
}
$company->bus_name = $data['name'];
$company->bus_description = $data['description'] ?? '';
$company->bus_email = $data['email'];
$company->bus_phone = $data['phone'] ?? '';
$company->bus_address = $data['address'] ?? '';
$company->bus_city = $data['city'] ?? '';
$company->bus_state = $data['state'] ?? '';
$company->bus_country = $data['country'] ?? '';
$company->bus_postal_code = $data['postal_code'] ?? '';
$company->bus_website = $data['website'] ?? '';
$company->bus_tax_id = $data['tax_id'] ?? '';
$company->bus_type = $data['bus_type'] ?? 'business';
$company->bus_status = $data['status'] ?? 'active';
$company->platform_name = $data['platform_name'] ?? '';
// Encrypt OpenRouter API Key if present
$newApiKey = $data['openrouter_api_key'] ?? '';
if (!empty($newApiKey) && strpos($newApiKey, '***') === false) {
$company->openrouter_api_key = Crypto::encrypt($newApiKey);
}
$company->ai_provider = $data['ai_provider'] ?? 'openrouter';
$company->ai_model = $data['ai_model'] ?? 'google/gemini-2.0-flash-001';
$company->ai_endpoint = $data['ai_endpoint'] ?? '';
// Settings are now handled via modules table
// $company->bus_settings = $data['bus_settings'] ?? [];
// Update slug if name changed
if ($data['name'] !== $company->getOriginal('name')) {
$slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $data['name'])));
// Check if slug exists (exclude current company)
if ($slug !== $company->bus_slug && Company::where('bus_slug', $slug)->exists()) {
$slug .= '-' . time();
}
$company->bus_slug = $slug;
}
$company->save();
// Handle modules - ONLY Super Admin can change which modules a company has access to
if ($user->isSuperAdmin()) {
$modulesData = $request->request->all()['modules'] ?? [];
$syncData = [];
foreach ($modulesData as $moduleId => $settings) {
$syncData[$moduleId] = [
'bus_modules_is_enabled' => isset($settings['enabled']),
'bus_modules_enabled_by' => $currentUserId,
'bus_modules_enabled_at' => \Carbon\Carbon::now(),
'bus_modules_show_public_nav' => isset($settings['public']),
'bus_modules_show_dashboard_nav' => isset($settings['dashboard'])
];
}
if (!empty($syncData)) {
$company->modules()->sync($syncData);
} else {
$company->modules()->detach();
}
}
if ($request->files->has('logo')) {
$file = $request->files->get('logo');
if ($file && $file->isValid()) {
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (in_array($file->getMimeType(), $allowedMimes)) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/logos';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$formatSetting = strtolower((string) get_env('IMG_FORMAT', 'webp'));
$format = $formatSetting === 'auto' ? 'webp' : $formatSetting;
$quality = env_int('IMG_QUALITY', 80);
$resolutionPercent = env_int('IMG_RESOLUTION', 100);
$image = Image::make($file->getPathname());
$width = $image->width();
$height = $image->height();
if ($resolutionPercent > 0 && $resolutionPercent < 100) {
$newW = (int) round($width * $resolutionPercent / 100);
$newH = (int) round($height * $resolutionPercent / 100);
$image->resize($newW, $newH, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
}
$ext = $format === 'jpeg' || $format === 'jpg' ? 'jpg' : ($format === 'png' ? 'png' : ($format === 'gif' ? 'gif' : 'webp'));
$filename = 'logo_' . $company->bus_id . '_' . time() . '.' . $ext;
if ($format === 'jpeg' || $format === 'jpg') {
$image->interlace(true);
$image->encode('jpeg', max(1, min(100, $quality)));
} elseif ($format === 'png') {
$pngCompression = max(0, min(9, (int) round((100 - max(1, min(100, $quality))) / 10)));
$image->encode('png', $pngCompression);
} elseif ($format === 'gif') {
$image->encode('gif');
} else {
$image->encode('webp', max(1, min(100, $quality)));
}
$image->save($uploadDir . '/' . $filename);
if ($company->bus_logo) {
$oldDirs = [
dirname(__DIR__, 4) . '/storage/uploads/logos',
dirname(__DIR__, 4) . '/storage/uploads/company/logos'
];
foreach ($oldDirs as $dir) {
$oldFile = $dir . '/' . $company->bus_logo;
if (file_exists($oldFile)) {
unlink($oldFile);
break;
}
}
}
$company->bus_logo = $filename;
}
}
}
// Handle business card upload
if ($request->files->has('business_card')) {
$file = $request->files->get('business_card');
if ($file && $file->isValid()) {
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (in_array($file->getMimeType(), $allowedMimes)) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/business-cards';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$formatSetting = strtolower((string) get_env('IMG_FORMAT', 'webp'));
$format = $formatSetting === 'auto' ? 'webp' : $formatSetting;
$quality = env_int('IMG_QUALITY', 80);
$resolutionPercent = env_int('IMG_RESOLUTION', 100);
$image = Image::make($file->getPathname());
$width = $image->width();
$height = $image->height();
if ($resolutionPercent > 0 && $resolutionPercent < 100) {
$newW = (int) round($width * $resolutionPercent / 100);
$newH = (int) round($height * $resolutionPercent / 100);
$image->resize($newW, $newH, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
}
$ext = $format === 'jpeg' || $format === 'jpg' ? 'jpg' : ($format === 'png' ? 'png' : ($format === 'gif' ? 'gif' : 'webp'));
$filename = 'business_card_' . $company->bus_id . '_' . time() . '.' . $ext;
if ($format === 'jpeg' || $format === 'jpg') {
$image->interlace(true);
$image->encode('jpeg', max(1, min(100, $quality)));
} elseif ($format === 'png') {
$pngCompression = max(0, min(9, (int) round((100 - max(1, min(100, $quality))) / 10)));
$image->encode('png', $pngCompression);
} elseif ($format === 'gif') {
$image->encode('gif');
} else {
$image->encode('webp', max(1, min(100, $quality)));
}
$image->save($uploadDir . '/' . $filename);
if ($company->bus_business_card) {
$oldDirs = [
dirname(__DIR__, 4) . '/storage/uploads/business-cards',
dirname(__DIR__, 4) . '/storage/uploads/company/business-cards'
];
foreach ($oldDirs as $dir) {
$oldFile = $dir . '/' . $company->bus_business_card;
if (file_exists($oldFile)) {
unlink($oldFile);
break;
}
}
}
$company->bus_business_card = $filename;
}
}
}
// Handle document upload
if ($request->files->has('document')) {
$file = $request->files->get('document');
if ($file && $file->isValid()) {
$allowedMimes = [
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation'
];
if (in_array($file->getMimeType(), $allowedMimes)) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/documents';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$originalName = $file->getClientOriginalName();
$filename = 'document_' . $company->bus_id . '_' . time() . '_' . $originalName;
$file->move($uploadDir, $filename);
if ($company->bus_document) {
$oldDirs = [
dirname(__DIR__, 4) . '/storage/uploads/documents',
dirname(__DIR__, 4) . '/storage/uploads/company/documents'
];
foreach ($oldDirs as $dir) {
$oldFile = $dir . '/' . $company->bus_document;
if (file_exists($oldFile)) {
unlink($oldFile);
break;
}
}
}
$company->bus_document = $filename;
}
}
}
$company->save();
// Restore session to ensure super_admin remains logged
$_SESSION['user_id'] = $currentUserId;
$_SESSION['user_role'] = $currentUserRole;
$_SESSION['user_idbus'] = $currentUserBus;
return new RedirectResponse(url('admin/companies'));
}
private function getErrorMessage(string $error): string
{
$messages = [
'missing_fields' => 'Por favor, preencha todos os campos obrigatórios.',
'email_exists' => 'Este endereço de e-mail já está registrado.',
'invalid_email' => 'Por favor, insira um endereço de e-mail válido.',
];
return $messages[$error] ?? 'Ocorreu um erro.';
}
public function destroy(Request $request, string $id): Response
{
$user = $this->getCurrentUser();
if (!$user || !$user->isSuperAdmin()) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$company = Company::find($id);
if ($company) {
// Delete logo file if exists
if ($company->bus_logo) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/logos';
if (file_exists($uploadDir . '/' . $company->bus_logo)) {
unlink($uploadDir . '/' . $company->bus_logo);
}
}
// Delete business card file if exists
if ($company->bus_business_card) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/business-cards';
if (file_exists($uploadDir . '/' . $company->bus_business_card)) {
unlink($uploadDir . '/' . $company->bus_business_card);
}
}
// Delete document file if exists
if ($company->bus_document) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/company/documents';
if (file_exists($uploadDir . '/' . $company->bus_document)) {
unlink($uploadDir . '/' . $company->bus_document);
}
}
$company->delete();
}
return new RedirectResponse(url('admin/companies'));
}
}