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
+418
View File
@@ -0,0 +1,418 @@
<?php
namespace Modules\Users\Controllers;
use App\Controllers\BaseAdminController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Modules\Auth\Models\User;
use App\Models\Module;
use App\Models\UserPermission;
use Intervention\Image\ImageManagerStatic as Image;
class UsersController extends BaseAdminController
{
public function index(Request $request): Response
{
$currentUser = $this->getCurrentUser();
if ($currentUser->isSuperAdmin()) {
$users = User::all();
} else {
// Admins only see users from their company
$users = User::where('users_bus_id', $currentUser->users_bus_id)->get();
}
return $this->renderAdminView('users/views/admin/index.twig', [
'users' => $users,
'title' => __('users.titles.management')
]);
}
public function create(Request $request): Response
{
$error = $request->query->get('error');
$errorMessage = $error ? $this->getErrorMessage($error) : null;
return $this->renderAdminView('users/views/admin/form.twig', [
'title' => __('users.titles.create'),
'error' => $errorMessage,
'target_user' => null
]);
}
public function store(Request $request): Response
{
$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']) || empty($data['password'])) {
return new RedirectResponse(url('admin/users/create?error=missing_fields'));
}
// Email format validation
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return new RedirectResponse(url('admin/users/create?error=invalid_email'));
}
// Check if email exists
if (User::where('users_email', $data['email'])->exists()) {
return new RedirectResponse(url('admin/users/create?error=email_exists'));
}
// Password strength validation
if (strlen($data['password']) < 8 || !preg_match('/[A-Za-z]/', $data['password']) || !preg_match('/[0-9]/', $data['password'])) {
return new RedirectResponse(url('admin/users/create?error=weak_password'));
}
$requestedRole = $data['role'] ?? 'user';
// Prevent non-super_admin from creating super_admin
if ($currentUserRole !== 'super_admin' && $requestedRole === 'super_admin') {
$requestedRole = 'user';
}
$user = new User();
$user->users_name = $data['name'];
$user->users_email = $data['email'];
$user->users_password = $data['password'];
$user->users_role = $requestedRole;
$user->users_status = $data['status'] ?? 'active';
$user->users_bus_id = $currentUserRole === 'super_admin' ? ($data['bus_id'] ?? $currentUserBus) : $currentUserBus;
$user->save();
if ($request->files->has('avatar')) {
$file = $request->files->get('avatar');
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/avatars';
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 = 'avatar_' . $user->users_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);
$user->users_avatar = $filename;
$user->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/users'));
}
public function show(Request $request, string $id): Response
{
$currentUser = $this->getCurrentUser();
$query = User::where('users_id', $id);
if (!$currentUser->isSuperAdmin()) {
$query->where('users_bus_id', $currentUser->users_bus_id);
}
$user = $query->first();
if (!$user) {
return new RedirectResponse(url('admin/users'));
}
return $this->renderAdminView('users/views/admin/show.twig', [
'user' => $user,
'title' => 'User Details'
]);
}
public function edit(Request $request, string $id): Response
{
$currentUser = $this->getCurrentUser();
$query = User::where('users_id', $id);
if (!$currentUser->isSuperAdmin()) {
$query->where('users_bus_id', $currentUser->users_bus_id);
}
$targetUser = $query->first();
if (!$targetUser) {
return new RedirectResponse(url('admin/users'));
}
$error = $request->query->get('error');
$errorMessage = $error ? $this->getErrorMessage($error) : null;
return $this->renderAdminView('users/views/admin/form.twig', [
'target_user' => $targetUser,
'title' => 'Edit User',
'error' => $errorMessage
]);
}
public function update(Request $request, string $id): Response
{
$currentUser = $this->getCurrentUser();
$currentUserId = $_SESSION['user_id'] ?? null;
$currentUserRole = $_SESSION['user_role'] ?? null;
$currentUserBus = $_SESSION['user_idbus'] ?? null;
$query = User::where('users_id', $id);
if (!$currentUser->isSuperAdmin()) {
$query->where('users_bus_id', $currentUser->users_bus_id);
}
$user = $query->first();
if (!$user) {
return new RedirectResponse(url('admin/users'));
}
$data = $request->request->all();
// Basic validation
if (empty($data['name']) || empty($data['email'])) {
return new RedirectResponse(url('admin/users/' . $id . '/edit?error=missing_fields'));
}
// Email format validation
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
return new RedirectResponse(url('admin/users/' . $id . '/edit?error=invalid_email'));
}
// Check if email exists (exclude current user)
if ($data['email'] !== $user->users_email && User::where('users_email', $data['email'])->exists()) {
return new RedirectResponse(url('admin/users/' . $id . '/edit?error=email_exists'));
}
$requestedRole = $data['role'] ?? $user->users_role;
// Prevent non-super_admin from promoting to super_admin or changing a super_admin
if ($currentUserRole !== 'super_admin') {
if ($requestedRole === 'super_admin' || $user->users_role === 'super_admin') {
$requestedRole = $user->users_role;
}
}
$user->users_name = $data['name'];
$user->users_email = $data['email'];
$user->users_role = $requestedRole;
$user->users_status = $data['status'] ?? 'active';
// Only super_admin can change company of a user
if ($currentUserRole === 'super_admin' && isset($data['bus_id'])) {
$user->users_bus_id = $data['bus_id'];
}
if (!empty($data['password'])) {
// Password strength validation
if (strlen($data['password']) < 8 || !preg_match('/[A-Za-z]/', $data['password']) || !preg_match('/[0-9]/', $data['password'])) {
return new RedirectResponse(url('admin/users/' . $id . '/edit?error=weak_password'));
}
$user->users_password = $data['password']; // Mutator handles hashing
}
if ($request->files->has('avatar')) {
$file = $request->files->get('avatar');
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/avatars';
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 = 'avatar_' . $user->users_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 ($user->users_avatar && file_exists($uploadDir . '/' . $user->users_avatar)) {
unlink($uploadDir . '/' . $user->users_avatar);
}
$user->users_avatar = $filename;
}
}
}
$user->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/users'));
}
public function editPermissions(Request $request, string $id): Response
{
$currentUser = $this->getCurrentUser();
if (!$currentUser || (!$currentUser->isAdmin() && !$currentUser->isSuperAdmin())) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$user = User::find($id);
if (!$user) {
return new RedirectResponse(url('admin/users'));
}
// Check if Admin is from the same company
if (!$currentUser->isSuperAdmin() && $user->users_bus_id !== $currentUser->users_bus_id) {
return new RedirectResponse(url('admin/users?error=unauthorized'));
}
// Get enabled modules for the company
$modules = $this->getEnabledModules($user);
// Get current user permissions
$userPermissions = UserPermission::where('user_permissions_user_id', $user->users_id)
->where('user_permissions_bus_id', $user->users_bus_id)
->pluck('user_permissions_permission')
->toArray();
return $this->renderAdminView('users/views/admin/permissions.twig', [
'target_user' => $user,
'modules' => $modules,
'user_permissions' => $userPermissions,
'title' => __('users.headers.user_permissions')
]);
}
public function updatePermissions(Request $request, string $id): Response
{
$currentUser = $this->getCurrentUser();
if (!$currentUser || (!$currentUser->isAdmin() && !$currentUser->isSuperAdmin())) {
return new RedirectResponse(url('admin/dashboard?error=unauthorized'));
}
$user = User::find($id);
if (!$user) {
return new RedirectResponse(url('admin/users'));
}
// Check if Admin is from the same company
if (!$currentUser->isSuperAdmin() && $user->users_bus_id !== $currentUser->users_bus_id) {
return new RedirectResponse(url('admin/users?error=unauthorized'));
}
$permissions = $request->request->all()['permissions'] ?? [];
// Remove existing permissions for this user in this company
UserPermission::where('user_permissions_user_id', $user->users_id)
->where('user_permissions_bus_id', $user->users_bus_id)
->delete();
// Add new permissions
foreach ($permissions as $permission) {
$userPermission = new UserPermission();
$userPermission->user_permissions_user_id = $user->users_id;
$userPermission->user_permissions_bus_id = $user->users_bus_id;
$userPermission->user_permissions_permission = $permission;
$userPermission->user_permissions_granted_by = $currentUser->users_id;
$userPermission->save();
}
return new RedirectResponse(url('admin/users/' . $id . '?success=permissions_updated'));
}
private function getErrorMessage(string $error): string
{
$messages = [
'missing_fields' => 'Please fill in all required fields.',
'email_exists' => 'This email address is already registered.',
'invalid_email' => 'Please enter a valid email address.',
'weak_password' => 'Password must be at least 8 characters long and contain at least one letter and one number.',
];
return $messages[$error] ?? 'An error occurred.';
}
public function destroy(Request $request, string $id): Response
{
$currentUser = $this->getCurrentUser();
$query = User::where('users_id', $id);
if (!$currentUser->isSuperAdmin()) {
$query->where('users_bus_id', $currentUser->users_bus_id);
}
$user = $query->first();
// Prevent deleting self and check if user exists/accessible
if ($user && $user->users_id != $_SESSION['user_id']) {
if ($user->users_avatar) {
$uploadDir = dirname(__DIR__, 4) . '/storage/uploads/avatars';
if (file_exists($uploadDir . '/' . $user->users_avatar)) {
unlink($uploadDir . '/' . $user->users_avatar);
}
}
$user->delete();
}
return new RedirectResponse(url('admin/users'));
}
public function manual(Request $request): Response
{
return $this->renderAdminView('users/views/admin/manual.twig', [
'title' => 'Manual do Usuário - Usuários e Permissões'
]);
}
}