feat: Implement SMS sending functionality with KavehNegar and Rangineh providers
- Add SendSmsMessage class for encapsulating SMS message data. - Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS. - Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates. - Develop SendSmsHandler for handling SMS sending messages. - Create SmsService to manage SMS dispatching and logging. - Add UserProfileController for managing user profiles with CRUD operations. - Implement UserProfile entity and repository for user profile data management. - Update symfony.lock and bootstrap.php for project dependencies and environment setup.
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace App\Sms\Controller;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Controller\BaseController;
|
||||
use App\Sms\Entity\SmsTemplate;
|
||||
use App\Sms\Repository\SmsTemplateRepository;
|
||||
use App\Sms\Service\SmsService;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||
class SmsController extends BaseController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SmsTemplateRepository $templateRepo,
|
||||
private readonly SmsService $smsService,
|
||||
) {}
|
||||
|
||||
// ── Send SMS directly ─────────────────────────────────────────────────────
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/sms/send', methods: ['POST'])]
|
||||
public function send(Request $request): JsonResponse
|
||||
{
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$mobile = trim($data['mobile'] ?? '');
|
||||
$message = trim($data['message'] ?? '');
|
||||
$provider = $data['provider'] ?? 'kavenegar';
|
||||
|
||||
if (empty($mobile) || empty($message)) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'mobile و message الزامی است', 422);
|
||||
}
|
||||
|
||||
$this->smsService->dispatchAsync($mobile, $message, $provider);
|
||||
|
||||
return $this->success(['message' => 'پیامک در صف ارسال قرار گرفت']);
|
||||
}
|
||||
|
||||
// ── Templates ─────────────────────────────────────────────────────────────
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/sms/template', methods: ['POST'])]
|
||||
public function createTemplate(Request $request): JsonResponse
|
||||
{
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$name = trim($data['name'] ?? '');
|
||||
$body = trim($data['body'] ?? '');
|
||||
$variables = $data['variables'] ?? [];
|
||||
|
||||
if (empty($name) || empty($body)) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'name و body الزامی است', 422);
|
||||
}
|
||||
|
||||
$template = new SmsTemplate($name, $body, $variables);
|
||||
$this->templateRepo->save($template);
|
||||
|
||||
return $this->success(['data' => $template->toArray()], 201);
|
||||
}
|
||||
|
||||
#[Route('/api/v1/sms/template/{uuid}', methods: ['GET'])]
|
||||
public function getTemplate(string $uuid): JsonResponse
|
||||
{
|
||||
$template = $this->templateRepo->findByUuid($uuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
return $this->success(['data' => $template->toArray()]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/sms/template/{uuid}', methods: ['PATCH'])]
|
||||
public function updateTemplate(string $uuid, Request $request): JsonResponse
|
||||
{
|
||||
$template = $this->templateRepo->findByUuid($uuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
|
||||
if ($template->getStatus() === SmsTemplate::STATUS_APPROVED) {
|
||||
return $this->error(ErrorCodes::ERR_SMS_003, ErrorCodes::message(ErrorCodes::ERR_SMS_003), 422);
|
||||
}
|
||||
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
if (array_key_exists('name', $data)) $template->setName($data['name']);
|
||||
if (array_key_exists('body', $data)) $template->setBody($data['body']);
|
||||
if (array_key_exists('variables', $data)) $template->setVariables($data['variables']);
|
||||
|
||||
$this->templateRepo->save($template);
|
||||
|
||||
return $this->success(['data' => $template->toArray()]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/sms/template/{uuid}/submit', methods: ['POST'])]
|
||||
public function submitTemplate(string $uuid): JsonResponse
|
||||
{
|
||||
$template = $this->templateRepo->findByUuid($uuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
|
||||
$template->submitForReview();
|
||||
$this->templateRepo->save($template);
|
||||
|
||||
return $this->success(['data' => $template->toArray()]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/sms/template/{uuid}', methods: ['DELETE'])]
|
||||
public function deleteTemplate(string $uuid): JsonResponse
|
||||
{
|
||||
$template = $this->templateRepo->findByUuid($uuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
$this->templateRepo->remove($template);
|
||||
return $this->success(['message' => 'تمپلیت حذف شد']);
|
||||
}
|
||||
|
||||
// ── Admin moderation ──────────────────────────────────────────────────────
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/admin/sms/templates', methods: ['GET'])]
|
||||
public function listTemplates(): JsonResponse
|
||||
{
|
||||
$templates = array_map(fn(SmsTemplate $t) => $t->toArray(), $this->templateRepo->findAll());
|
||||
return $this->success(['data' => $templates]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/admin/sms/template/{uuid}/approve', methods: ['POST'])]
|
||||
public function approveTemplate(string $uuid, Request $request): JsonResponse
|
||||
{
|
||||
$template = $this->templateRepo->findByUuid($uuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$template->approve($data['note'] ?? null);
|
||||
if (!empty($data['provider_code'])) $template->setProviderCode($data['provider_code']);
|
||||
$this->templateRepo->save($template);
|
||||
|
||||
return $this->success(['data' => $template->toArray()]);
|
||||
}
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/admin/sms/template/{uuid}/reject', methods: ['POST'])]
|
||||
public function rejectTemplate(string $uuid, Request $request): JsonResponse
|
||||
{
|
||||
$template = $this->templateRepo->findByUuid($uuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$note = trim($data['note'] ?? '');
|
||||
if (empty($note)) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'دلیل رد الزامی است', 422);
|
||||
}
|
||||
$template->reject($note);
|
||||
$this->templateRepo->save($template);
|
||||
|
||||
return $this->success(['data' => $template->toArray()]);
|
||||
}
|
||||
|
||||
// ── Send via template ─────────────────────────────────────────────────────
|
||||
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
#[Route('/api/v1/sms/send-template', methods: ['POST'])]
|
||||
public function sendViaTemplate(Request $request): JsonResponse
|
||||
{
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$mobile = trim($data['mobile'] ?? '');
|
||||
$templateUuid = trim($data['template_uuid'] ?? '');
|
||||
$vars = $data['vars'] ?? [];
|
||||
$provider = $data['provider'] ?? 'kavenegar';
|
||||
|
||||
$template = $this->templateRepo->findByUuid($templateUuid);
|
||||
if ($template === null) {
|
||||
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'تمپلیت یافت نشد', 404);
|
||||
}
|
||||
|
||||
if ($template->getStatus() !== SmsTemplate::STATUS_APPROVED) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'تمپلیت هنوز تأیید نشده است', 422);
|
||||
}
|
||||
|
||||
$message = $template->renderBody($vars);
|
||||
$this->smsService->dispatchAsync(
|
||||
$mobile, $message, $provider, $template->getUuid(),
|
||||
$vars, $template->getProviderCode()
|
||||
);
|
||||
|
||||
return $this->success(['message' => 'پیامک در صف ارسال قرار گرفت']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user