add upload file to support ticket

This commit is contained in:
Hesabix 2025-03-01 17:17:11 +00:00
parent b935fdf6b2
commit 4c5908c5c8
4 changed files with 238 additions and 141 deletions

View file

@ -8,6 +8,7 @@ parameters:
archiveTempMediaDir: '%kernel.project_dir%/../hesabixArchive/temp' archiveTempMediaDir: '%kernel.project_dir%/../hesabixArchive/temp'
avatarDir: '%kernel.project_dir%/../hesabixArchive/avatars' avatarDir: '%kernel.project_dir%/../hesabixArchive/avatars'
sealDir: '%kernel.project_dir%/../hesabixArchive/seal' sealDir: '%kernel.project_dir%/../hesabixArchive/seal'
SupportFilesDir: '%kernel.project_dir%/../hesabixArchive/support'
services: services:
# default configuration for services in *this* file # default configuration for services in *this* file
_defaults: _defaults:

View file

@ -5,6 +5,7 @@ namespace App\Controller;
use App\Entity\Settings; use App\Entity\Settings;
use App\Entity\Support; use App\Entity\Support;
use App\Entity\User; use App\Entity\User;
use App\Service\Access;
use App\Service\Explore; use App\Service\Explore;
use App\Service\Extractor; use App\Service\Extractor;
use App\Service\Jdate; use App\Service\Jdate;
@ -14,205 +15,284 @@ use App\Service\registryMGR;
use App\Service\SMS; use App\Service\SMS;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class SupportController extends AbstractController class SupportController extends AbstractController
{ {
// ثابت‌ها برای مدیریت خطاها
private const ERROR_TICKET_NOT_FOUND = ['error' => 1, 'message' => 'تیکت یافت نشد.'];
private const ERROR_NO_FILE = ['error' => 2, 'message' => 'فایلی برای این تیکت وجود ندارد.'];
private const ERROR_FILE_NOT_FOUND = ['error' => 3, 'message' => 'فایل در سرور یافت نشد.'];
private const ERROR_ACCESS_DENIED = ['error' => 4, 'message' => 'شما اجازه دسترسی به این فایل را ندارید.'];
private const ERROR_INVALID_PARAMS = ['error' => 999, 'message' => 'تمام موارد لازم را وارد کنید.'];
/** /**
* function to generate random strings * Generate a random string
* @param int $length number of characters in the generated string
* @return string a new string is created with random characters of the desired length
*/ */
private function RandomString($length = 32) private function randomString(int $length = 32): string
{ {
return substr(str_shuffle(str_repeat($x = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length); return substr(str_shuffle(str_repeat('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', ceil($length / 32))), 1, $length);
}
/**
* Fetch ticket by ID and check ownership
*/
private function getTicket(EntityManagerInterface $entityManager, string $id, bool $checkOwnership = false): ?Support
{
$ticket = $entityManager->getRepository(Support::class)->find($id);
if (!$ticket || ($checkOwnership && $ticket->getSubmitter() !== $this->getUser())) {
return null;
}
return $ticket;
} }
#[Route('/api/admin/support/list', name: 'app_admin_support_list')] #[Route('/api/admin/support/list', name: 'app_admin_support_list')]
public function app_admin_support_list(Extractor $extractor, EntityManagerInterface $entityManager): JsonResponse public function app_admin_support_list(Extractor $extractor, EntityManagerInterface $entityManager): JsonResponse
{ {
$items = $entityManager->getRepository(Support::class)->findBy(['main' => 0], ['id' => 'DESC']); $items = $entityManager->getRepository(Support::class)->findBy(['main' => 0], ['id' => 'DESC']);
$res = []; $res = array_map(fn($item) => Explore::ExploreSupportTicket($item, $this->getUser()), $items);
foreach ($items as $item) {
$res[] = Explore::ExploreSupportTicket($item, $this->getUser());
}
return $this->json($extractor->operationSuccess($res)); return $this->json($extractor->operationSuccess($res));
} }
#[Route('/api/admin/support/view/{id}', name: 'app_admin_support_view')] #[Route('/api/admin/support/view/{id}', name: 'app_admin_support_view')]
public function app_admin_support_view(Extractor $extractor, Jdate $jdate, EntityManagerInterface $entityManager, string $id = ''): JsonResponse public function app_admin_support_view(Extractor $extractor, EntityManagerInterface $entityManager, string $id): JsonResponse
{ {
$item = $entityManager->getRepository(Support::class)->find($id); $item = $this->getTicket($entityManager, $id);
if (!$item) if (!$item) {
throw $this->createNotFoundException(); throw $this->createNotFoundException();
$replays = $entityManager->getRepository(Support::class)->findBy(['main' => $item->getId()]);
$res = [];
foreach ($replays as $replay) {
if ($replay->getSubmitter() == $this->getUser())
$replay->setState(1);
else
$replay->setState(0);
$res[] = Explore::ExploreSupportTicket($replay, $this->getUser());
}
return $this->json(
$extractor->operationSuccess([
'item' => Explore::ExploreSupportTicket($item, $this->getUser()),
'replays' => $res
])
);
}
#[Route('/api/admin/support/mod/{id}', name: 'app_admin_support_mod')]
public function app_admin_support_mod(registryMGR $registryMGR, SMS $SMS, Request $request, EntityManagerInterface $entityManager, Notification $notifi, string $id = ''): JsonResponse
{
$params = [];
if ($content = $request->getContent()) {
$params = json_decode($content, true);
} }
$item = $entityManager->getRepository(Support::class)->find($id); $replays = $entityManager->getRepository(Support::class)->findBy(['main' => $item->getId()]);
if (!$item) $res = array_map(function ($replay) {
$this->createNotFoundException(); $replay->setState($replay->getSubmitter() === $this->getUser() ? 1 : 0);
if (array_key_exists('body', $params)) { return Explore::ExploreSupportTicket($replay, $this->getUser());
$support = new Support(); }, $replays);
$support->setDateSubmit(time());
$support->setTitle('0'); return $this->json($extractor->operationSuccess([
$support->setBody($params['body']); 'item' => Explore::ExploreSupportTicket($item, $this->getUser()),
$support->setState('0'); 'replays' => $res
$support->setMain($item->getId()); ]));
$support->setSubmitter($this->getUser());
$entityManager->persist($support);
$entityManager->flush();
$item->setState('پاسخ داده شده');
$entityManager->persist($support);
$entityManager->flush();
//send sms to customer
if ($item->getSubmitter()->getMobile()) {
$SMS->send(
[$item->getId()],
$registryMGR->get('sms', 'ticketReplay'),
$item->getSubmitter()->getMobile()
);
} }
//send notification to user
#[Route('/api/admin/support/mod/{id}', name: 'app_admin_support_mod')]
public function app_admin_support_mod(registryMGR $registryMGR, SMS $SMS, Request $request, EntityManagerInterface $entityManager, Notification $notifi, string $id): JsonResponse
{
$params = $request->getPayload()->all();
$item = $this->getTicket($entityManager, $id);
if (!$item) {
throw $this->createNotFoundException();
}
if (!isset($params['body'])) {
return $this->json(self::ERROR_INVALID_PARAMS);
}
$support = new Support();
$support->setDateSubmit(time())
->setTitle('0')
->setBody($params['body'])
->setState('0')
->setMain($item->getId())
->setSubmitter($this->getUser());
// ذخیره موقت برای گرفتن ID
$entityManager->persist($support);
$entityManager->flush();
// مدیریت فایل با متد handleFileUpload
$fileName = $this->handleFileUpload($request, $this->getParameter('SupportFilesDir'), $support->getId());
if ($fileName) {
$support->setFileName($fileName);
}
$entityManager->persist($support);
$item->setState('پاسخ داده شده');
$entityManager->persist($item);
$entityManager->flush();
// بررسی سوئیچ ارسال SMS
$sendSms = filter_var($params['sendSms'] ?? true, FILTER_VALIDATE_BOOLEAN); // پیش‌فرض true
if ($sendSms && ($mobile = $item->getSubmitter()->getMobile())) {
$SMS->send([$item->getId()], $registryMGR->get('sms', 'ticketReplay'), $mobile);
}
$settings = $entityManager->getRepository(Settings::class)->findAll()[0]; $settings = $entityManager->getRepository(Settings::class)->findAll()[0];
$url = '/profile/support-view/' . $item->getId(); $notifi->insert("به درخواست پشتیبانی پاسخ داده شد", "/profile/support-view/{$item->getId()}", null, $item->getSubmitter());
$notifi->insert("به درخواست پشتیبانی پاسخ داده شد", $url, null, $item->getSubmitter());
return $this->json([ return $this->json([
'error' => 0, 'error' => 0,
'message' => 'successful' 'message' => 'successful',
'file' => $fileName
]); ]);
} }
return $this->json([
'error' => 999, /**
'message' => 'تمام موارد لازم را وارد کنید.' * Handle file upload and return filename
]); */
private function handleFileUpload(Request $request, string $uploadDirectory, int $ticketId): ?string
{
if (!file_exists($uploadDirectory)) {
mkdir($uploadDirectory, 0777, true);
} }
$files = $request->files->get('files');
if ($files && !empty($files)) {
$file = $files[0]; // فقط اولین فایل
$extension = $file->getClientOriginalExtension();
$fileName = $ticketId . '.' . $extension;
$file->move($uploadDirectory, $fileName);
return $fileName;
}
return null;
}
#[Route('/api/support/list', name: 'app_support_list')] #[Route('/api/support/list', name: 'app_support_list')]
public function app_support_list(Jdate $jdate, EntityManagerInterface $entityManager): JsonResponse public function app_support_list(Jdate $jdate, EntityManagerInterface $entityManager): JsonResponse
{ {
$items = $entityManager->getRepository(Support::class)->findBy( $items = $entityManager->getRepository(Support::class)->findBy(
[ ['submitter' => $this->getUser(), 'main' => 0],
'submitter' => $this->getUser(), ['id' => 'DESC']
'main' => 0
],
[
'id' => 'DESC'
]
); );
foreach ($items as $item) { foreach ($items as $item) {
$item->setDateSubmit($jdate->jdate('Y/n/d', $item->getDateSubmit())); $item->setDateSubmit($jdate->jdate('Y/n/d', $item->getDateSubmit()));
} }
return $this->json($items); return $this->json($items);
} }
#[Route('/api/support/mod/{id}', name: 'app_support_mod')] #[Route('/api/support/mod/{id}', name: 'app_support_mod')]
public function app_support_mod(registryMGR $registryMGR, SMS $SMS, Request $request, EntityManagerInterface $entityManager, string $id = ''): JsonResponse public function app_support_mod(registryMGR $registryMGR, SMS $SMS, Request $request, EntityManagerInterface $entityManager, string $id = ''): JsonResponse
{ {
$params = []; $params = $request->getPayload()->all();
if ($content = $request->getContent()) { $uploadDirectory = $this->getParameter('SupportFilesDir');
$params = json_decode($content, true); if (!file_exists($uploadDirectory)) {
mkdir($uploadDirectory, 0777, true);
} }
if ($id == '') {
if (array_key_exists('title', $params) && array_key_exists('body', $params)) { if ($id === '') {
if (!isset($params['title'], $params['body'])) {
return $this->json(self::ERROR_INVALID_PARAMS);
}
$item = new Support(); $item = new Support();
$item->setBody($params['body']); $item->setBody($params['body'])
$item->setTitle($params['title']); ->setTitle($params['title'])
$item->setDateSubmit(time()); ->setDateSubmit(time())
$item->setSubmitter($this->getUser()); ->setSubmitter($this->getUser())
$item->setMain(0); ->setMain(0)
$item->setCode($this->RandomString(8)); ->setCode($this->randomString(8))
$item->setState('در حال پیگیری'); ->setState('در حال پیگیری');
$entityManager->persist($item); $entityManager->persist($item);
$entityManager->flush(); $entityManager->flush();
//send sms to manager
$SMS->send( $fileName = $this->handleFileUpload($request, $uploadDirectory, $item->getId());
[$item->getId()], if ($fileName) {
$registryMGR->get('sms', 'ticketRec'), $item->setFileName($fileName);
$registryMGR->get('ticket', 'managerMobile') }
);
$entityManager->persist($item);
$entityManager->flush();
$SMS->send([$item->getId()], $registryMGR->get('sms', 'ticketRec'), $registryMGR->get('ticket', 'managerMobile'));
return $this->json([ return $this->json([
'error' => 0, 'error' => 0,
'message' => 'ok', 'message' => 'ok',
'url' => $item->getId() 'url' => $item->getId(),
'files' => $fileName
]); ]);
} }
} else {
if (array_key_exists('body', $params)) {
$item = new Support();
$upper = $entityManager->getRepository(Support::class)->find($id);
if ($upper)
$item->setMain($upper->getid());
$item->setBody($params['body']); if (!isset($params['body'])) {
$item->setTitle($upper->getTitle()); return $this->json(self::ERROR_INVALID_PARAMS);
$item->setDateSubmit(time()); }
$item->setSubmitter($this->getUser());
$item->setState('در حال پیگیری'); $upper = $this->getTicket($entityManager, $id);
if (!$upper) {
return $this->json(self::ERROR_TICKET_NOT_FOUND);
}
$item = new Support();
$item->setMain($upper->getId())
->setBody($params['body'])
->setTitle($upper->getTitle())
->setDateSubmit(time())
->setSubmitter($this->getUser())
->setState('در حال پیگیری');
$entityManager->persist($item); $entityManager->persist($item);
$entityManager->flush(); $entityManager->flush();
$fileName = $this->handleFileUpload($request, $uploadDirectory, $item->getId());
if ($fileName) {
$item->setFileName($fileName);
}
$entityManager->persist($item);
$upper->setState('در حال پیگیری'); $upper->setState('در حال پیگیری');
$entityManager->persist($upper); $entityManager->persist($upper);
$entityManager->flush(); $entityManager->flush();
//send sms to manager
$SMS->send( $SMS->send([$item->getId()], $registryMGR->get('sms', 'ticketRec'), $registryMGR->get('ticket', 'managerMobile'));
[$item->getId()],
$registryMGR->get('sms', 'ticketRec'),
$registryMGR->get('ticket', 'managerMobile')
);
return $this->json([ return $this->json([
'error' => 0, 'error' => 0,
'message' => 'ok', 'message' => 'ok',
'url' => $item->getId() 'url' => $item->getId(),
]); 'files' => $fileName
}
}
return $this->json([
'error' => 999,
'message' => 'تمام موارد لازم را وارد کنید.'
]); ]);
} }
#[Route('/api/support/view/{id}', name: 'app_support_view')] #[Route('/api/support/view/{id}', name: 'app_support_view')]
public function app_support_view(Jdate $jdate, EntityManagerInterface $entityManager, string $id = ''): JsonResponse public function app_support_view(EntityManagerInterface $entityManager, string $id): JsonResponse
{ {
$item = $entityManager->getRepository(Support::class)->find($id); $item = $this->getTicket($entityManager, $id, true);
if (!$item) if (!$item) {
throw $this->createNotFoundException();
if ($item->getSubmitter() != $this->getUser())
throw $this->createAccessDeniedException(); throw $this->createAccessDeniedException();
$replays = $entityManager->getRepository(Support::class)->findBy(['main' => $item->getId()]);
$replaysArray = [];
foreach ($replays as $replay) {
$replaysArray[] = Explore::ExploreSupportTicket($replay, $this->getUser());
} }
$replays = $entityManager->getRepository(Support::class)->findBy(['main' => $item->getId()]);
$replaysArray = array_map(fn($replay) => Explore::ExploreSupportTicket($replay, $this->getUser()), $replays);
return $this->json([ return $this->json([
'item' => Explore::ExploreSupportTicket($item, $this->getUser()), 'item' => Explore::ExploreSupportTicket($item, $this->getUser()),
'replays' => $replaysArray 'replays' => $replaysArray
]); ]);
} }
#[Route('/api/support/download/file/{id}', name: 'app_support_download_file')]
public function app_support_download_file(EntityManagerInterface $entityManager, string $id): Response
{
$ticket = $this->getTicket($entityManager, $id);
if (!$ticket) {
return $this->json(self::ERROR_TICKET_NOT_FOUND, 404);
}
$currentUser = $this->getUser();
if (!$currentUser || (!$this->isGranted('ROLE_ADMIN') && $ticket->getSubmitter() !== $currentUser)) {
return $this->json(self::ERROR_ACCESS_DENIED, 403);
}
$fileName = $ticket->getFileName();
if (!$fileName) {
return $this->json(self::ERROR_NO_FILE, 404);
}
$filePath = $this->getParameter('SupportFilesDir') . '/' . $fileName;
if (!file_exists($filePath)) {
return $this->json(self::ERROR_FILE_NOT_FOUND, 404);
}
return new BinaryFileResponse($filePath, 200, [
'Content-Disposition' => ResponseHeaderBag::DISPOSITION_ATTACHMENT . '; filename="' . $fileName . '"'
]);
}
} }

View file

@ -38,6 +38,9 @@ class Support
#[ORM\Column(length: 255, nullable: true)] #[ORM\Column(length: 255, nullable: true)]
private ?string $code = null; private ?string $code = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $fileName = null;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -126,4 +129,16 @@ class Support
return $this; return $this;
} }
public function getFileName(): ?string
{
return $this->fileName;
}
public function setFileName(?string $fileName): static
{
$this->fileName = $fileName;
return $this;
}
} }

View file

@ -564,6 +564,7 @@ class Explore
$res['submitter'] = self::ExploreUser($support->getSubmitter()); $res['submitter'] = self::ExploreUser($support->getSubmitter());
$res['main'] = $support->getMain(); $res['main'] = $support->getMain();
$res['owner'] = true; $res['owner'] = true;
$res['fileName'] = $support->getFileName();
if ($user->getId() != $support->getSubmitter()->getId()) { if ($user->getId() != $support->getSubmitter()->getId()) {
$res['owner'] = false; $res['owner'] = false;
} }