5.9 KiB
Doctor Import (IRIMC) API
Endpoint:
POST /api/v1/admin/doctors/importPermission:ROLE_ADMINController:App\Admin\Controller\AdminApiController::importDoctor
وارد کردن یک پزشک از سازمان نظام پزشکی (membersearch.irimc.org) بدون شماره موبایل.
برخلاف POST /api/v1/admin/doctors (که موبایل معتبر ایرانی میخواهد)، این اندپوینت برای
هر پزشک یک کاربر جانشینِ غیرفعال با شناسهٔ مصنوعی میسازد و پروفایل را در وضعیت
unclaimed ذخیره میکند تا بعداً به پزشک واقعی منتقل شود.
مصرفکنندهٔ اصلی: خزندهٔ پایتون (clinicpro-crawler/pipeline.py) که با کاربر «مالک
سیستمی» (0000000000) لاگین میکند و هر ~۶۰ ثانیه یک پزشک را میفرستد.
مدل مالکیت (ستونهای جدید doctors)
| ستون | مقدار هنگام ایمپورت | توضیح |
|---|---|---|
owner_status |
unclaimed |
claimed | unclaimed | pending_transfer |
source |
irimc |
manual (پیشفرض رکوردهای قدیمی) | irimc |
source_ref |
profile_url |
شناسهٔ رکورد مبدأ برای ممیزی |
managed_by |
id کاربر ادمینِ فراخوان | کاربری که پروفایل را مدیریت میکند |
claimed_at |
null |
زمان انتقال مالکیت (هنگام claim پر میشود) |
رکوردهای موجود در migration مقدار manual + claimed میگیرند تا رفتارشان تغییر نکند.
idempotency
کلید یکتای منطقی: (source, medical_system_code).
- اگر پزشکی با همان
source+medical_system_codeوجود نداشته باشد → ساخته میشود (201). - اگر وجود داشته باشد و
owner_status != claimed→ بهروزرسانی میشود (200). - اگر وجود داشته باشد و
owner_status == claimed→ رد میشود (200,skipped: "claimed") تا دادهٔ مالک واقعی بازنویسی نشود.
Request
{
"name": "دکتر فرخنده حسینی",
"medical_system_code": "145657",
"source": "irimc",
"source_ref": "https://membersearch.irimc.org/member/profile?id=…",
"gender": "woman",
"degree": "general",
"info": "دکترای حرفهای پزشکی",
"specialties": [1],
"states": [23],
"cities": [123]
}
| فیلد | الزامی | توضیح |
|---|---|---|
name |
✅ | نام کامل پزشک |
medical_system_code |
✅ | کد نظام پزشکی (کلید idempotency) |
source |
— | پیشفرض irimc |
source_ref |
— | profile_url یا شناسهٔ مبدأ |
gender |
— | man | woman |
degree |
— | general | expert | specialist | subspecialistplus |
info |
— | متن تخصص/توضیح |
specialties / states / cities |
— | آرایهٔ شناسههای مرجع (id) |
gender/degreeباید با ثابتهایDoctor::GENDERS/Doctor::DEGREESسازگار باشند.specialties/states/citiesاگر داده شوند مجموعهٔ فعلی را جایگزین میکنند.
Response
201 Created (ساخته شد)
{ "success": true, "data": { "uuid": "…", "created": true } }
200 OK (بهروزرسانی شد)
{ "success": true, "data": { "uuid": "…", "created": false } }
200 OK (رد بهدلیل تصاحبشده)
{ "success": true, "data": { "uuid": "…", "created": false, "skipped": "claimed" } }
422 (اعتبارسنجی)
{ "success": false, "data": null, "errors": [ { "code": "…", "message": "کد نظام پزشکی الزامی است", "field": "medical_system_code" } ] }
عکس پروفایل
پس از ایمپورت، عکس با دو مرحله اضافه میشود (همان مسیر پزشکِ عادی):
POST /file/upload/clinic_pro/doctor/field_image— بدنه: باینری خام؛ هدرContent-Disposition: attachment; filename="145657.jpg". پاسخ:{ fid, uuid, url, filename, filemime, filesize }.PATCH /api/v1/doctor/{uuid}با بدنهٔ{ "image_data": <پاسخ مرحلهٔ ۱> }تا به آرایهٔimagesپروفایل افزوده شود.
کاربر سیستمی و چرخهٔ عمر
# ساخت/فعالسازی کاربر مالک سیستمی (کرالر با این لاگین میکند)
php bin/console app:system-owner 0000000000 --password=<secret> --activate
# غیرفعالسازی پس از پایان کار (کرالر هم با --deactivate-on-finish این را از طریق API انجام میدهد)
php bin/console app:system-owner 0000000000 --deactivate
کاربر باید ROLE_ADMIN و status=1 داشته باشد تا لاگینِ رمزی (POST /api/v1/user/login)
و فراخوانی این اندپوینت ممکن باشد.
⚠️ captcha: مسیر
/api/v1/user/loginازCaptchaGuardرد میشود و این guard وقتیALTCHA_ENABLED=trueباشد (مقدار فعلی.env) یک payloadِ altcha میخواهد. برای اجرای بدونِمرورگرِ کرالر یکی از اینها لازم است: ۱) روی همان سرورALTCHA_ENABLED=falseدر.env.local(سادهترین برای dev)، یا ۲) افزودن یک استثنا درPasswordAuthenticatorکه برای کاربر مالک سیستمی captcha را رد کند، یا ۳) لاگین سرویس با یک هدر سرّیِ مورد اعتماد. تا وقتی این حل نشود، لاگین کرالر با ۴۲۲ (ERR_CAPTCHA_001) رد میشود.