diff --git a/assets/controllers.json b/assets/controllers.json index 29ea244..6e0ec2a 100644 --- a/assets/controllers.json +++ b/assets/controllers.json @@ -12,4 +12,4 @@ } }, "entrypoints": [] -} +} \ No newline at end of file diff --git a/assets/controllers/wallet_connect_controller.js b/assets/controllers/wallet_connect_controller.js index 1161e1b..73073cb 100644 --- a/assets/controllers/wallet_connect_controller.js +++ b/assets/controllers/wallet_connect_controller.js @@ -9,6 +9,8 @@ export default class extends Controller { connect() { console.log('Wallet Connect Controller connected'); + console.log('Controller targets:', this.targets); + console.log('Controller values:', this.values); this.selectedWallet = null; this.walletAddress = null; this.signature = null; @@ -130,14 +132,20 @@ export default class extends Controller { } } - async setPrimaryWallet(walletId) { + async setPrimaryWallet(event) { + const walletId = event.currentTarget.dataset.walletId; + if (!walletId) { + this.showMessage('شناسه کیف پول یافت نشد', 'error'); + return; + } + if (!confirm('آیا می‌خواهید این کیف پول را به عنوان اصلی تنظیم کنید؟')) { return; } try { const response = await fetch(`/api/wallet/${walletId}/set-primary`, { - method: 'POST', + method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfTokenValue || '' @@ -161,10 +169,19 @@ export default class extends Controller { } } - async toggleWalletStatus(walletId) { + async toggleWalletStatus(event) { + console.log('toggleWalletStatus called', event); + const walletId = event.currentTarget.dataset.walletId; + console.log('Wallet ID:', walletId); + if (!walletId) { + this.showMessage('شناسه کیف پول یافت نشد', 'error'); + return; + } + try { + console.log('Making request to toggle wallet status...'); const response = await fetch(`/api/wallet/${walletId}/toggle-status`, { - method: 'POST', + method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.csrfTokenValue || '' @@ -188,12 +205,21 @@ export default class extends Controller { } } - async deleteWallet(walletId) { + async deleteWallet(event) { + console.log('deleteWallet called', event); + const walletId = event.currentTarget.dataset.walletId; + console.log('Wallet ID:', walletId); + if (!walletId) { + this.showMessage('شناسه کیف پول یافت نشد', 'error'); + return; + } + if (!confirm('آیا مطمئن هستید که می‌خواهید این کیف پول را حذف کنید؟')) { return; } try { + console.log('Making request to delete wallet...'); const response = await fetch(`/api/wallet/${walletId}`, { method: 'DELETE', headers: { diff --git a/config/packages/csrf.yaml b/config/packages/csrf.yaml index c102b17..bf3726b 100644 --- a/config/packages/csrf.yaml +++ b/config/packages/csrf.yaml @@ -5,8 +5,4 @@ framework: token_id: submit csrf_protection: - stateless_token_ids: - - submit - - authenticate - - logout enabled: true diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 89896cf..480afdb 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -42,6 +42,18 @@ security: logout: path: customer_logout target: app_home + qa: + pattern: ^/qa + lazy: true + provider: app_user_provider + remember_me: + secret: '%kernel.secret%' + lifetime: 604800 # 1 week + path: / + always_remember_me: false + logout: + path: customer_logout + target: app_home main: pattern: ^/ lazy: true @@ -69,6 +81,12 @@ security: # محافظت از سایر مسیرهای /admin - { path: ^/admin, roles: ROLE_ADMIN } - { path: ^/customer/dashboard, roles: ROLE_CUSTOMER } + # محافظت از مسیرهای QA + - { path: ^/qa/ask, roles: ROLE_CUSTOMER } + - { path: ^/qa/question/.*/answer, roles: ROLE_CUSTOMER } + - { path: ^/qa/.*/vote, roles: ROLE_CUSTOMER } + - { path: ^/qa/.*/accept, roles: ROLE_CUSTOMER } + - { path: ^/qa/tag/create, roles: ROLE_CUSTOMER } # - { path: ^/profile, roles: ROLE_USER } when@test: diff --git a/src/Controller/QA/QAController.php b/src/Controller/QA/QAController.php index e991d54..e6bd655 100644 --- a/src/Controller/QA/QAController.php +++ b/src/Controller/QA/QAController.php @@ -136,9 +136,82 @@ class QAController extends AbstractController $form = $this->createForm(QuestionFormType::class, $question); $form->handleRequest($request); - if ($form->isSubmitted() && $form->isValid()) { - // مدیریت تگ‌ها - $selectedTagIds = $request->request->all('question')['tags'] ?? []; + + + if ($form->isSubmitted()) { + // بررسی CSRF token - حذف شده چون Symfony خودش بررسی می‌کند + // if (!$this->isCsrfTokenValid('question', $request->request->get('_token'))) { + // $this->addFlash('error', 'CSRF token نامعتبر است.'); + // $availableTags = $this->tagRepository->findActiveTags(); + // return $this->render('qa/ask_question.html.twig', [ + // 'form' => $form, + // 'availableTags' => $availableTags, + // ]); + // } + + // دریافت تگ‌های انتخاب شده از فرم + $selectedTags = $form->get('tags')->getData(); + $selectedTagIds = []; + + if ($selectedTags) { + foreach ($selectedTags as $tag) { + $selectedTagIds[] = $tag->getId(); + } + } + + // Debug: بررسی تگ‌های ارسال شده + error_log('Selected tag IDs from form: ' . print_r($selectedTagIds, true)); + error_log('Form is valid: ' . ($form->isValid() ? 'true' : 'false')); + + // اگر form valid نیست، خطاها را نمایش بده + if (!$form->isValid()) { + $this->addFlash('error', 'لطفاً تمام فیلدهای الزامی را پر کنید'); + $availableTags = $this->tagRepository->findActiveTags(); + return $this->render('qa/ask_question.html.twig', [ + 'form' => $form, + 'availableTags' => $availableTags, + ]); + } + + // مدیریت پیوست فایل‌ها + $attachments = $form->get('attachments')->getData(); + error_log('Attachments from form: ' . print_r($attachments, true)); + + // بررسی فایل‌های ارسال شده در request + $uploadedFiles = $request->files->get('question_form')['attachments'] ?? []; + error_log('Uploaded files from request: ' . print_r($uploadedFiles, true)); + + if ($attachments && count($attachments) > 0) { + error_log('Processing ' . count($attachments) . ' attachments from form'); + $uploadedAttachments = $this->attachmentService->uploadAttachments($attachments, $this->getUser(), $question); + error_log('Uploaded attachments: ' . print_r($uploadedAttachments, true)); + + foreach ($uploadedAttachments as $attachment) { + $question->addAttachment($attachment); + error_log('Added attachment to question: ' . $attachment->getOriginalFilename()); + } + } elseif ($uploadedFiles && count($uploadedFiles) > 0) { + error_log('Processing ' . count($uploadedFiles) . ' files from request'); + $uploadedAttachments = $this->attachmentService->uploadAttachments($uploadedFiles, $this->getUser(), $question); + error_log('Uploaded attachments from request: ' . print_r($uploadedAttachments, true)); + + foreach ($uploadedAttachments as $attachment) { + $question->addAttachment($attachment); + error_log('Added attachment to question: ' . $attachment->getOriginalFilename()); + } + } else { + error_log('No attachments found in form data or request'); + } + + // حذف تمام تگ‌های قبلی برای این سوال + $existingRelations = $this->entityManager->getRepository(QuestionTagRelation::class) + ->findBy(['question' => $question]); + + foreach ($existingRelations as $relation) { + $this->entityManager->remove($relation); + } + + // اضافه کردن تگ‌های جدید foreach ($selectedTagIds as $tagId) { $tag = $this->tagRepository->find($tagId); if ($tag) { @@ -149,21 +222,16 @@ class QAController extends AbstractController // افزایش تعداد استفاده از تگ $tag->incrementUsageCount(); + + error_log('Added tag relation for tag ID: ' . $tagId); } } - // مدیریت پیوست فایل‌ها - $attachments = $form->get('attachments')->getData(); - if ($attachments) { - $uploadedAttachments = $this->attachmentService->uploadAttachments($attachments, $this->getUser(), $question); - foreach ($uploadedAttachments as $attachment) { - $question->addAttachment($attachment); - } - } - + + // ذخیره سوال در دیتابیس $this->entityManager->persist($question); $this->entityManager->flush(); - + $this->addFlash('success', 'سوال شما با موفقیت ثبت شد.'); return $this->redirectToRoute('qa_question_show', ['id' => $question->getId()]); } @@ -394,7 +462,7 @@ class QAController extends AbstractController public function createTag(Request $request): JsonResponse { // بررسی CSRF token - if (!$this->isCsrfTokenValid('vote', $request->request->get('_token'))) { + if (!$this->isCsrfTokenValid('question', $request->request->get('_token'))) { return new JsonResponse(['error' => 'CSRF token نامعتبر است.'], 403); } diff --git a/src/Form/QA/QuestionFormType.php b/src/Form/QA/QuestionFormType.php index d0d8168..096b9a1 100644 --- a/src/Form/QA/QuestionFormType.php +++ b/src/Form/QA/QuestionFormType.php @@ -61,13 +61,19 @@ class QuestionFormType extends AbstractType ->add('tags', EntityType::class, [ 'class' => QuestionTag::class, 'choice_label' => 'name', + 'choice_value' => 'id', 'multiple' => true, 'expanded' => false, - 'required' => false, 'mapped' => false, + 'required' => false, + 'query_builder' => function (\Doctrine\ORM\EntityRepository $er) { + return $er->createQueryBuilder('t') + ->where('t.isActive = :active') + ->setParameter('active', true) + ->orderBy('t.name', 'ASC'); + }, 'attr' => [ - 'class' => 'form-control', - 'style' => 'display: none;' // مخفی کردن چون با JavaScript مدیریت می‌شود + 'class' => 'form-control d-none' // مخفی می‌کنیم چون با JavaScript مدیریت می‌شود ], 'constraints' => [ new Assert\Count([ diff --git a/templates/customer/dashboard.html.twig b/templates/customer/dashboard.html.twig index 964f05f..7bfbae8 100644 --- a/templates/customer/dashboard.html.twig +++ b/templates/customer/dashboard.html.twig @@ -173,21 +173,21 @@
{% if not wallet.isPrimary and wallet.isActive %} - + {% endif %} - -