<?php
namespace App\Controller;
use App\Entity\Answer;
use App\Entity\Article;
use App\Entity\ArticleHistory;
use App\Entity\Question;
use App\Entity\QuestionnaireResult;
use App\Entity\Survey;
use App\Entity\Transaction;
use App\Entity\User;
use App\Exception\UserBannedException;
use App\Message\PaymentMessage;
use App\Repository\QuestionnaireResultRepository;
use App\Service\PaymentService;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Exception;
use Symfony\Component\String\Slugger\SluggerInterface;
class IndexController extends AbstractController
{
/**
* @var PaymentService
*/
protected PaymentService $payment;
private SluggerInterface $slugger;
public function __construct(
PaymentService $payment,
SluggerInterface $slugger
) {
$this->payment = $payment;
$this->slugger = $slugger;
}
private function normalizePhone(string $phone): string
{
$phone = preg_replace('/\D+/', '', $phone);
if (str_starts_with($phone, '0')) {
$phone = '996' . substr($phone, 1);
} elseif (!str_starts_with($phone, '996')) {
$phone = '996' . $phone;
}
return $phone;
}
public function getUserRequest(Request $request)
{
$em = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent(), true);
$telegramId = $data["telegramId"] ?? null;
$phoneInput = $data["phone"] ?? null;
$isBanned = false;
$user = null;
if ($telegramId) {
$user = $em->getRepository(User::class)->findOneBy([
"telegramId" => $telegramId
]);
}
if (!$user && $phoneInput) {
$digits = preg_replace('/\D+/', '', $phoneInput);
if (str_starts_with($digits, '996')) {
$phone = trim($digits, '996');
} else {
if ($digits !== '' && $digits[0] === '0') {
$digits = substr($digits, 1);
}
$phone = $digits;
}
$users = $em->getRepository(User::class)->createQueryBuilder('user')
->where("user.phone LIKE :phone")
->setParameter('phone', '%'.$phone.'%')
->getQuery()->getResult()
;
if (!empty($users)){
foreach ($users as $user){
if ($user->isBanned()){
$isBanned = true;
}
}
$user = $users[0];
}else{
$user = false;
}
}
if ($user and ($user->isBanned() or $isBanned)){
throw new UserBannedException('banned');
}
return $user;
}
/**
* @Route("/gti/user/create", methods={"POST"})
*/
public function createUser(Request $request): Response
{
try {
$em = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent(), true);
$user = $this->getUserRequest($request);
if ($user){
return $this->json(['success' => false, 'massage' => 'User exist']);
}
$digits = preg_replace('/\D+/', '', $data["phone"]);
if (str_starts_with($digits, '996')) {
$phone = $digits;
} else {
if ($digits !== '' && $digits[0] === '0') {
$digits = substr($digits, 1);
}
$phone = '996' . $digits;
}
$user = new User();
$user->setCreateAt(new \DateTimeImmutable());
$user->setName($data["name"]??null);
$user->setPhone($phone);
$user->setCity($data["city"]??null);
$user->setTelegramId($data["telegramId"]);
$user->setBrandsHistory($data["brand"]??null);
$em->persist($user);
$em->flush();
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
return $this->json(['success' => true, 'massage' => 'success']);
}
/**
* @Route("/gti/user", methods={"PATCH"})
*/
public function updateUser(Request $request): Response
{
try {
$em = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent(), true);
$user = $this->getUserRequest($request);
if (!$user){
return $this->json(['success' => false, 'massage' => 'User not exist']);
}
if (isset($data["phone"]) and $phone = $data["phone"]){
$user->setCity($phone);
}
if (isset($data["city"]) and $city = $data["city"]){
$user->setCity($city);
}
if (isset($data["brand"]) and $newBrand = $data["brand"]){
$currentHistory = $user->getBrandsHistory();
$brands = array_filter(array_map('trim', explode(',', $currentHistory ?: '')));
if (!in_array($newBrand, $brands, true)) {
$brands[] = $newBrand;
}
$user->setBrandsHistory(implode(',', $brands));
}
$em->persist($user);
$em->flush();
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
return $this->json(['success' => true, 'massage' => 'success']);
}
/**
* @Route("/gti/user/check-exist", methods={"POST"})
*/
public function checkExistUser(Request $request): Response
{
try {
$user = $this->getUserRequest($request);
if ($user){
return $this->json(['success' => true, 'massage' => 'User exist']);
}
return $this->json(['success' => false, 'massage' => 'User not exist']);
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
}
/**
* @Route("/gti/user/check-admin", methods={"GET"})
*/
public function checkAdminUser(Request $request): Response
{
try {
$user = $this->getUserRequest($request);
if (!$user){
return $this->json(['success' => false, 'massage' => 'User not exist']);
}elseif ($user and $user->isIsAdmin()){
return $this->json(['success' => true, 'massage' => 'User is admin']);
}
return $this->json(['success' => false, 'massage' => 'User is not admin']);
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
}
/**
* @Route("/gti/user/chats", methods={"GET"})
*/
public function getUserChats(Request $request): Response
{
try {
$em = $this->getDoctrine()->getManager();
$users = $em->getRepository( User::class )->getAllTelegramId();
$telegramIds = array_map(function ($entry) {
return $entry['telegramId'];
}, $users);
return $this->json(['success' => true, 'massage' => 'success', 'data' => $telegramIds]);
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
}
/**
* @Route("/gti/survey", methods={"GET"})
*/
public function getSurvey(Request $request): Response
{
$survey_images = $this->getParameter('IMAGE_URL').'/survey_images/';
$question_images = $this->getParameter('IMAGE_URL').'/question_images/';
try {
$em = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent(), true);
$lang = $data['lang'] ?? 'ru';
$user = $this->getUserRequest($request);
if (!$user) {
return $this->json(['success' => false, 'message' => 'User not found']);
}
$completedSurveys = $em->getRepository(QuestionnaireResult::class)
->createQueryBuilder('qr')
->select('IDENTITY(qr.survey)')
->where('qr.user = :user')
->andWhere('qr.completed = true')
->setParameter('user', $user)
->distinct()
->getQuery()
->getScalarResult();
$completedSurveyIds = array_map(fn($item) => current($item), $completedSurveys);
$surveys = $em->getRepository(Survey::class)->createQueryBuilder('s')
->where('s.isActive = 1')
->andWhere('s.id NOT IN (:completed)')
->setParameter('completed', $completedSurveyIds ?: [0])
->getQuery()
->getResult();
$dataResult = [];
foreach ($surveys as $survey) {
$images = [];
foreach ($survey->getImages() as $image) {
if ($lang === 'kg') {
if ($image->isKg()) {
$images[] = $survey_images.$image->getImageName();
}
} else {
if (!$image->isKg()) {
$images[] = $survey_images.$image->getImageName();
}
}
}
if ($lang === 'kg' && empty($images)) {
foreach ($survey->getImages() as $image) {
if (!$image->isKg()) {
$images[] = $survey_images.$image->getImageName();
}
}
}
$questions = [];
foreach ($survey->getQuestions() as $question) {
$answers = [];
$questionnaireResult = $em->getRepository( QuestionnaireResult::class )->findOneBy([
"question" => $question->getId(),
'user' => $user->getId()
]);
if (!$questionnaireResult){
foreach ($question->getAnswers() as $answer) {
$answers[] = [
"id" => $answer->getId(),
"title" => $lang == 'kg' ? $answer->getTextLocal() ?? $answer->getText() : $answer->getText(),
"isEndSurvey" => $answer->isEndSurvey(),
"isCorrect" => $answer->isCorrect()
];
}
$imagesQes = [];
foreach ($question->getImages() as $imageQue) {
if ($lang === 'kg') {
if ($imageQue->isKg()) {
$imagesQes[] = $question_images.$imageQue->getImageName();
}
} else {
if (!$imageQue->isKg()) {
$imagesQes[] = $question_images.$imageQue->getImageName();
}
}
}
if ($lang === 'kg' && empty($imagesQes)) {
foreach ($question->getImages() as $imageQue) {
if (!$imageQue->isKg()) {
$imagesQes[] = $question_images.$imageQue->getImageName();
}
}
}
$questions[] = [
"id" => $question->getId(),
"title" => $lang == 'kg' ? $question->getTextLocal() ?? $question->getText() : $question->getText(),
"type" => $question->getType(),
"answers" => $answers,
"images" => $imagesQes,
];
}
}
$title = $survey->getTitle();
$description = $survey->getDescription();
if ($lang == 'kg'){
$title = $survey->getTitleLocal() ?? $title;
$description = $survey->getDescriptionLocal() ?? $description;
}
$dataResult[] = [
"id" => $survey->getId(),
"isPoll" => $survey->isPoll(),
"title" => $title ,
"description" => $description,
"images" => $images,
"questions" => $questions
];
}
return $this->json(['success' => true, 'massage' => 'success', 'data' => $dataResult]);
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
}
private function handleImageUpload($imageData, SluggerInterface $slugger, string $uploadDir): string
{
// Декодируем base64 или обрабатываем URL
if (preg_match('/^data:image\/(\w+);base64,/', $imageData, $matches)) {
$data = substr($imageData, strpos($imageData, ',') + 1);
$extension = $matches[1] ?? 'png';
$imageData = base64_decode($data);
$fileName = uniqid().'.'.$extension;
file_put_contents($uploadDir.'/'.$fileName, $imageData);
}
// Если это URL
elseif (filter_var($imageData, FILTER_VALIDATE_URL)) {
$fileContent = file_get_contents($imageData);
$extension = pathinfo(parse_url($imageData, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
$fileName = uniqid().'.'.$extension;
file_put_contents($uploadDir.'/'.$fileName, $fileContent);
}
// Если это UploadedFile (например, из формы)
elseif ($imageData instanceof UploadedFile) {
$originalFilename = pathinfo($imageData->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = $slugger->slug($originalFilename);
$fileName = $safeFilename.'-'.uniqid().'.'.$imageData->guessExtension();
$imageData->move($uploadDir, $fileName);
} else {
throw new \InvalidArgumentException('Invalid image data');
}
return '/uploads/images/'.$fileName;
}
/**
* @Route("/gti/answer", methods={"POST"})
*/
public function answer(Request $request): Response
{
try {
$data = json_decode($request->getContent(), true);
$user = $this->getUserRequest($request);
if (!$user){
return $this->json(['success' => false, 'massage' => 'User not found']);
}
if (is_array($data["answerId"])){
foreach ($data["answerId"] as $answerId){
if($result = $this->setAnswer($data, $answerId, $user)){
return $result;
}
}
}else{
if($result = $this->setAnswer($data, $data["answerId"], $user)){
return $result;
}
}
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
return $this->json(['success' => true, 'massage' => 'success']);
}
function setAnswer($data, $answerId, $user){
$em = $this->getDoctrine()->getManager();
$answerId = $em->getRepository( Answer::class )->findOneBy([
"id" => $answerId
]);
if (!$answerId){
return $this->json(['success' => false, 'massage' => 'answerId not found']);
}
$questionnaireResult = $em->getRepository( QuestionnaireResult::class )->findOneBy([
"answer" => $answerId->getId(),
'user' => $user->getId()
]);
if ($questionnaireResult and $answerId->isEndSurvey()){
return $this->json(['success' => false, 'massage' => 'This question has already been answered']);
}
$question = $answerId->getQuestion();
$survey = $question->getSurvey();
$result = $data["result"];
if ($question->getType() == 'img'){
$uploadDir = $this->getParameter('kernel.project_dir').'/public/uploads/images';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
try {
$result = $this->handleImageUpload($result, $this->slugger, $uploadDir);
} catch (\Exception $e) {
$result = $data["result"];
}
}
$answer = new QuestionnaireResult();
$answer->setCreateAt(new \DateTimeImmutable());
$answer->setResult($result);
$answer->setSurvey($survey);
$answer->setQuestion($question);
$answer->setAnswer($answerId);
$answer->setUser($user);
if ($answerId->isEndSurvey()){
$answer->setCompleted(true);
}
$em->persist($answer);
$em->flush();
if ($answerId->isEndSurvey()){
$em = $this->getDoctrine()->getManager();
/** @var QuestionnaireResultRepository $qrRepo */
$qrRepo = $em->getRepository(QuestionnaireResult::class);
$correctCount = $qrRepo->countCorrectByUserAndSurvey($user, $answerId->getQuestion()->getSurvey());
$totalQuestions= $survey->getTotalCorrect();
if (!$totalQuestions){
$totalQuestions= $survey->getQuestions()->count();
}
if ($correctCount >= $totalQuestions) {
$this->sendArticle($survey->getArticleSuccess(), $user);
if ($question->isAddBalance()){
$this->addBalance($user);
}
}else{
$this->sendArticle($survey->getArticleFailed(), $user);
}
if ($survey->getType() == Survey::TYPE_SCORE){
$totalScore = $qrRepo->getTotalScore($user, $answerId->getQuestion()->getSurvey());
foreach ($survey->getArticles() as $article){
if ($article->getScoreFrom() <= $totalScore and $article->getScoreTo() >= $totalScore){
$this->sendArticle($article, $user);
break;
}
}
}
}
return false;
}
/**
* @Route("/gti/test/uploade", methods={"POST"})
*/
public function testUpload(Request $request): Response
{
$data = json_decode($request->getContent(), true);
$result = $data["result"];
$uploadDir = $this->getParameter('kernel.project_dir').'/public/uploads/images';
// Создаем директорию, если не существует
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
try {
$result = $this->handleImageUpload($result, $this->slugger, $uploadDir);
} catch (\Exception $e) {
$result = $data["result"];
}
return $this->json(['success' => true, 'massage' => $result]);
}
public function sendArticle(?Article $article, User $user)
{
if ($article){
$tgBotUrl = $this->getParameter('TG_BOT_TOKEN');
$client = new Client(['verify' => false]);
$articleImages = $this->getParameter('IMAGE_URL').'/article_images/'.$article->getImageName();
$em = $this->getDoctrine()->getManager();
try {
if ($article->getImageName()) {
$photoParams = [
'chat_id' => $user->getTelegramId(),
'photo' => $articleImages,
'caption' => $article->getDescription(),
];
$response = $client->get($tgBotUrl.'sendPhoto', ['query' => $photoParams]);
} else {
$messageParams = [
'chat_id' => $user->getTelegramId(),
'text' => $article->getDescription(),
];
$response = $client->get($tgBotUrl.'sendMessage', ['query' => $messageParams]);
}
$articleHistory = new ArticleHistory();
$articleHistory->setUser($user);
$articleHistory->setArticle($article);
$articleHistory->setMessageId(json_decode($response->getBody()->getContents(), true)['result']['message_id']);
$em->persist($articleHistory);
$em->flush();
} catch (GuzzleException $e) {}
}
}
/**
* @Route("/gti/answer-all/old", methods={"POST"})
*/
public function answerAll(Request $request): Response
{
try {
$em = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent(), true);
$user = $em->getRepository( User::class )->findOneBy([
"telegramId" => $data["telegramId"]
]);
if (!$user){
return $this->json(['success' => false, 'massage' => 'User not found']);
}
foreach ($data["data"] as $result){
$answer = new QuestionnaireResult();
$answer->setCreateAt(new \DateTimeImmutable());
$answer->setResult($result["result"]);
$answer->setUser($user);
$em->persist($answer);
$em->flush();
}
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => 'error']);
}
return $this->json(['success' => true, 'massage' => 'success']);
}
/**
* @Route("/gti/balance/test/add", methods={"POST"})
*/
public function addBalanceTest(Request $request): Response
{
try {
$em = $this->getDoctrine()->getManager();
$phones = [
];
foreach ($phones as $phone){
$user = $em->getRepository( User::class )->findOneBy([
"phone" => $phone
]);
if ($user){
$this->addBalanceOld($user);
}
}
}catch (\Error $error){
return $this->json(['success' => false, 'massage' => $error]);
}
return $this->json(['success' => true, 'massage' => 'success']);
}
public function addBalanceOld($user): bool
{
$balanceAmount = $this->getParameter('BALANCE_AMOUNT') ?? 1;
$em = $this->getDoctrine()->getManager();
try {
$transaction = new Transaction();
$transaction
->setUser($user)
->setAmount($balanceAmount);
$em->persist($transaction);
$em->flush();
$this->payment->makePayment($transaction);
$em->flush();
}catch (\Exception $d){}
return true;
}
public function addBalance($user): bool
{
$balanceAmount = $this->getParameter('BALANCE_AMOUNT') ?? 1;
$em = $this->getDoctrine()->getManager();
$transaction = new Transaction();
$transaction
->setUser($user)
->setAmount($balanceAmount);
$em->persist($transaction);
$em->flush();
$client = HttpClient::create();
try {
$client->request("POST", $this->getParameter('SITE_URL')."gti/balance/add/".$transaction->getId(), [
'buffer' => false,
'timeout' => 0.1
]);
}catch (Exception $exception){}
return true;
}
/**
* @Route("/gti/balance/add/{id}", methods={"POST"}, name="addBalancePending")
*/
public function addBalancePending(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$transaction = $em->getRepository(Transaction::class)->find($id);
if ($transaction and $transaction->getStatus() == Transaction::STATUS_PENDING) {
$this->payment->makePayment($transaction);
$em->flush();
}
}
}