Skip to main content
#P1394

GET /api/v2/exam/get

Route Info

Method Endpoint Controller Middleware Purpose تگ Swagger
GET /api/v2/exam/get OfficialController@getExam domainAccess, ipTrust دریافت فرم آزمون (نظرسنجی) برای سفر یا ارزیابی ۳۶۰ درجه همکاران tags={"Exam","V2"}

توضیح عملکرد (Function Logic)

تابع getExam() بر اساس نوع درخواست مشخص می‌کند که آزمون از کدام شاخه بارگذاری شود:
  • نوع ۱: trip = نظرسنجی خدمات سفر (Trip Survey)
  • نوع ۲: 360_degree_feedback = ارزیابی عملکرد همکار به صورت ۳۶۰ درجه

منطق کلی:

  1. بررسی مقدار $request->type.
  2. اجرای مسیر مرتبط متناسب با نوع آزمون.
  3. در صورت یافتن شرایط واجد، تولید ساختار آزمون شامل سؤالات، هدر، فوتر و فیلدهای جایگزین‌شده از داده‌های مالی یا اطلاعات همکار.
  4. بازگشت پاسخ JSON شامل status، time و داده یا پیام خطا.

ورودی‌ها (Request Parameters)

پارامتر محل نوع داده الزامی توضیح
type Query string بله نوع آزمون؛ مقدارهای مجاز: "trip" یا "360_degree_feedback".
id Query string|int بله شناسه مرجع آزمون (Slug سفر یا شناسه همکار).
branch Query string|int بله کد شعبه فعال (برای محدودسازی دامنه آزمون).
operator Header/Auth Context object اختیاری* در حالت ۳۶۰ درجه برای تشخیص کاربر واردشده مورد نیاز است.

الف) جریان عملکرد نوع «trip»

  1. یافتن فاکتور از جدول factors بر اساس slug داده‌شده.
  2. بررسی وجود پاسخ قبلی در جدول exam_response با فیلدهای: object_type='reference' و object=factor.id. اگر وجود داشته باشد → پیغام «این سفر قبلاً نظرسنجی شده است.».
  3. در غیراین‌صورت:
    • دریافت داده مالی از Redis با کلید reference:{id}:information. در صورت عدم وجود، صدا زدن TradeController::financial() و ذخیره در Redis.
    • واکشی کالاهای موجود در فاکتور از جدول factor_items.
    • یافتن آزمون فعال با type=trip_survey برای همان شعبه.
    • دریافت سؤالات فعال از exam_questions مرتب‌شده بر اساس order و id.
    • اعمال فیلتر سؤالات: اگر موضوع hotel است، فقط هنگام وجود محصول مرتبط استفاده می‌شود.
    • جایگزینی متغیرهای دینامیک در title، header و footer با متد replaceExamItem('trip',...).
    • ساخت ساختار خروجی نهایی شامل مشخصات آزمون و آرایه سؤالات.

ب) جریان عملکرد نوع «360_degree_feedback»

  1. بررسی وجود operator.id؛ اگر کاربر لاگین نکرده → پیام خطا.
  2. عدم تطابق شناسه خواسته‌شده با personnel_id کاربر فعلی (جلوگیری از خودارزیابی).
  3. جست‌وجوی همکار هدف در جدول operators با شروط:
    • branch JSON contains current branch
    • status = 1، no_feedback = null.
  4. بررسی اینکه تاریخ استخدام کارمند حداقل ۱ ماه قبل باشد.
  5. در صورت گذشت شرط: بررسی عدم وجود پاسخ از کاربر فعلی در ۶ ماه اخیر (exam_response).
  6. اگر تاکنون پاسخ نداده → واکشی آزمون با type=360_degree_feedback و branch جاری.
  7. واکشی سؤالات و تولید ساختار خروجی مشابه نوع trip، با جایگزینی پارامترهای {colleague} و {position} در title، header و footer.

ساختار پاسخ (Response Structure)

فیلد نوع داده توضیح
status boolean نتیجه نهایی تابع.
time int (unix timestamp) زمان پاسخ سرور (بر حسب ثانیه).
data object|null در صورت true حاوی ساختار آزمون کامل است.
message string|null پیغام خطا هنگام بروز استثنا.

نمونه پاسخ موفق (trip):

{
  "status": true,
  "time": 1693905000,
  "data": {
    "id": 15,
    "object": 1472,
    "title": "نظرسنجی خدمات پرواز",
    "header": "مشتری گرامی، لطفاً به سفر خود امتیاز دهید.",
    "footer": "با تشکر از همکاری شما",
    "created_at": "1402-02-02 00:00:00",
    "questions": [
      {
        "id": 1,
        "type": "rating",
        "subject": "flight",
        "title": "ارزیابی کیفیت پرواز شما",
        "options": [1,2,3,4,5],
        "description": null,
        "mandatory": 1,
        "score": 5
      }
    ]
  }
}

نمونه پاسخ خطا:

{
  "status": false,
  "time": 1693905001,
  "message": "این سفر قبلا نظرسنجی شده است."
}

تحلیل امنیتی

  • ✅ Middleware دوگانه domainAccess و ipTrust مانع درخواست‌های خارج از محدوده مجاز می‌شود.
  • ⚠️ Endpoint فاقد authWithJwt است؛ در حالت فعلی کاربران ناشناس می‌توانند با دانستن slug به آزمون سفر دسترسی یابند. در حالت Production پیشنهاد می‌شود JWT فعال شود.
  • ✅ داده‌ی حساسی در خروجی وجود ندارد (تنها ساختار آزمون).
  • ⚠️ تابع از Redis و DB مستقیم استفاده می‌کند بدون هندل استثناء؛ خطای Redis می‌تواند کل عملیات را fail کند.

وابستگی‌ها (Dependencies)

  • use Illuminate\Http\Request;
  • use Illuminate\Support\Facades\DB;
  • use Illuminate\Support\Facades\Redis;
  • use Carbon\Carbon;
  • use App\Http\Controllers\Api\Panel\V2\TradeController;

ساختار داخلی data در پاسخ موفق

فیلد نوع توضیح
id int شناسه آزمون.
object int شناسه مرجع (سفر یا کارمند).
title string عنوان اصلی آزمون.
header/footer string متن معرفی و پایان آزمون.
questions array لیست سؤالات با فیلدهای id, type, subject, title, options, description, mandatory, score.

پیغام‌های خطای محتمل

  • ⚠️ "لینک نظرسنجی معتبر نمی باشد" → شناسه یا کاربر نامعتبر.
  • ⚠️ "بانک سوالات تعریف نشده است" → آزمون نوع مربوطه برای این شعبه فعال نشده.
  • ⚠️ "این سفر قبلا نظرسنجی شده است" یا "این مورد قبلا نظرسنجی شده است" → پاسخ قبلی موجود است.
  • ⚠️ "این کارمند هنوز به مرحله ارزیابی 360 درجه نرسیده" → کمتر از ۱ ماه از ایجاد حساب کارمند گذشته.
  • ⚠️ "شما امکان ارائه نظر به خود را ندارید" → جلوگیری از Self Feedback.
  • ⚠️ "این نظرسنجی احتیاج به ورود به سیستم دارد." → بدون Auth.

نکات کارایی (Performance)

  • دسترسی Redis برای کش اطلاعات فاکتور سرعت واکشی آزمون را افزایش می‌دهد.
  • اما هر بار بررسی DB + Redis روی مسیر عمومی ریسک افزایش تاخیر دارد.
  • پیشنهاد: تجمیع داده‌ها در یک Service Layer با TTL منطقی ۵ دقیقه‌ای برای Redis Keyها.

پیوست نگهداری و توسعه بعدی

  • انتقال Logic از Controller به Service مستقل (ExamService) جهت پوشش Exception Handling.
  • افزودن فیلد category یا tag به آزمون‌ها جهت فیلتر بهتر در سامانه آموزش.
  • درخواست بعدی (POST /api/v2/exam/response) جهت ثبت پاسخ آزمون، مکمل همین Endpoint است و بلافاصله باید مستند شود.