feat: Add tagging system for SMS logs and templates
- Introduced a `tag` field in the `SmsLog` entity to categorize SMS messages. - Updated the `SmsService` to handle the new `tag` parameter during SMS dispatch. - Implemented a `SmsTextResolver` service to resolve SMS message templates based on tags. - Created a new `SmsMessageTemplate` entity for editable SMS templates with placeholders. - Added endpoints for managing SMS message templates in the admin panel. - Enhanced existing SMS dispatching methods across various controllers to utilize the tagging system. - Migrated the database to include the new `tag` field and created a seeding command for default SMS templates. - Updated admin API to filter SMS logs by tag and include tag information in responses.
This commit is contained in:
@@ -10,6 +10,24 @@ use Symfony\Component\Uid\Uuid;
|
||||
#[ORM\Index(columns: ['mobile', 'created_at'], name: 'idx_sms_logs_mobile')]
|
||||
class SmsLog
|
||||
{
|
||||
public const TAG_GLOBAL = 'global';
|
||||
public const TAG_OTP = 'otp';
|
||||
public const TAG_PAYMENT = 'payment';
|
||||
public const TAG_CLINIC_INVITATION = 'clinic_invitation';
|
||||
public const TAG_PRE_REGISTRATION = 'pre_registration';
|
||||
public const TAG_NOTIFICATION_MOBILE = 'notification_mobile';
|
||||
public const TAG_USER_TEMPLATE = 'user_template';
|
||||
|
||||
public const TAGS = [
|
||||
self::TAG_GLOBAL,
|
||||
self::TAG_OTP,
|
||||
self::TAG_PAYMENT,
|
||||
self::TAG_CLINIC_INVITATION,
|
||||
self::TAG_PRE_REGISTRATION,
|
||||
self::TAG_NOTIFICATION_MOBILE,
|
||||
self::TAG_USER_TEMPLATE,
|
||||
];
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
@@ -33,20 +51,26 @@ class SmsLog
|
||||
#[ORM\Column(name: 'template_uuid', type: 'string', length: 36, nullable: true)]
|
||||
private ?string $templateUuid = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 30, options: ['default' => self::TAG_GLOBAL])]
|
||||
private string $tag = self::TAG_GLOBAL;
|
||||
|
||||
#[ORM\Column(name: 'created_at', type: 'integer')]
|
||||
private int $createdAt;
|
||||
|
||||
public function __construct(string $mobile, string $message, string $provider, bool $success)
|
||||
public function __construct(string $mobile, string $message, string $provider, bool $success, string $tag = self::TAG_GLOBAL)
|
||||
{
|
||||
$this->uuid = Uuid::v4()->toRfc4122();
|
||||
$this->mobile = $mobile;
|
||||
$this->message = $message;
|
||||
$this->provider = $provider;
|
||||
$this->success = $success;
|
||||
$this->tag = $tag;
|
||||
$this->createdAt = time();
|
||||
}
|
||||
|
||||
public function setTemplateUuid(?string $v): self { $this->templateUuid = $v; return $this; }
|
||||
public function getTag(): string { return $this->tag; }
|
||||
public function setTag(string $v): self { $this->tag = $v; return $this; }
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
@@ -57,6 +81,7 @@ class SmsLog
|
||||
'provider' => $this->provider,
|
||||
'success' => $this->success,
|
||||
'template_uuid' => $this->templateUuid,
|
||||
'tag' => $this->tag,
|
||||
'created_at' => $this->createdAt,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Sms\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* متن ویرایشپذیرِ پیامکهای سیستمی، کلیددار با تگ (SmsLog::TAG_*).
|
||||
* body شامل placeholderهای {key} است که هنگام ارسال جایگزین میشوند.
|
||||
*/
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'sms_message_templates')]
|
||||
class SmsMessageTemplate
|
||||
{
|
||||
/**
|
||||
* متن و متادیتای پیشفرض هر تگ — مرجع برای seed و fallback.
|
||||
* @var array<string, array{title: string, body: string, variables: string[]}>
|
||||
*/
|
||||
public const DEFAULTS = [
|
||||
SmsLog::TAG_OTP => [
|
||||
'title' => 'کد تأیید ورود',
|
||||
'body' => 'کد تأیید شما: {code}',
|
||||
'variables' => ['code'],
|
||||
],
|
||||
SmsLog::TAG_PAYMENT => [
|
||||
'title' => 'تأیید پرداخت و نوبت',
|
||||
'body' => 'نوبت شما با {doctor} در تاریخ {date} ثبت و تأیید شد.',
|
||||
'variables' => ['doctor', 'date'],
|
||||
],
|
||||
SmsLog::TAG_CLINIC_INVITATION => [
|
||||
'title' => 'دعوت پزشک به کلینیک',
|
||||
'body' => "دکتر گرامی، کلینیک {clinic} شما را برای همکاری دعوت کرده است.\nبرای بررسی: {link}\nاین لینک تا ۷۲ ساعت معتبر است.",
|
||||
'variables' => ['clinic', 'link'],
|
||||
],
|
||||
SmsLog::TAG_PRE_REGISTRATION => [
|
||||
'title' => 'پیشثبتنام',
|
||||
'body' => 'به کلینیک پرو خوش آمدید! شمارهکاربری: {username} | رمز عبور: {password} | لینک ورود: {link}',
|
||||
'variables' => ['username', 'password', 'link'],
|
||||
],
|
||||
SmsLog::TAG_NOTIFICATION_MOBILE => [
|
||||
'title' => 'تأیید شماره اعلان',
|
||||
'body' => "کد تأیید شماره اعلان شما: {code}\nاعتبار: ۵ دقیقه",
|
||||
'variables' => ['code'],
|
||||
],
|
||||
];
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 30, unique: true)]
|
||||
private string $tag;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 100)]
|
||||
private string $title;
|
||||
|
||||
#[ORM\Column(type: 'text')]
|
||||
private string $body;
|
||||
|
||||
#[ORM\Column(type: 'json')]
|
||||
private array $variables = [];
|
||||
|
||||
#[ORM\Column(name: 'updated_at', type: 'integer')]
|
||||
private int $updatedAt;
|
||||
|
||||
public function __construct(string $tag, string $title, string $body, array $variables = [])
|
||||
{
|
||||
$this->tag = $tag;
|
||||
$this->title = $title;
|
||||
$this->body = $body;
|
||||
$this->variables = $variables;
|
||||
$this->updatedAt = time();
|
||||
}
|
||||
|
||||
public function getId(): ?int { return $this->id; }
|
||||
public function getTag(): string { return $this->tag; }
|
||||
public function getTitle(): string { return $this->title; }
|
||||
public function getBody(): string { return $this->body; }
|
||||
public function getVariables(): array { return $this->variables; }
|
||||
public function getUpdatedAt(): int { return $this->updatedAt; }
|
||||
|
||||
public function setTitle(string $v): self { $this->title = $v; $this->updatedAt = time(); return $this; }
|
||||
public function setBody(string $v): self { $this->body = $v; $this->updatedAt = time(); return $this; }
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'tag' => $this->tag,
|
||||
'title' => $this->title,
|
||||
'body' => $this->body,
|
||||
'variables' => $this->variables,
|
||||
'updated_at' => $this->updatedAt,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user