تیم فنی کوئرا در تمامی این سال‌ها، همواره سعی کرده تا خارق‌العاده‌ترین ویژگی‌ها را به زیبا‌ترین شکل به کاربران در تمام بخش‌های کوئرا از جمله کانتست، کالج و بوت‌کمپ ارائه کند. لود زیاد تیم فنی کوئرا در تمام این سال‌ها باعث شده تا توسعه‌دهندگانش همواره تنها‌ و تنها به فکر توسعه فیچر‌های مختلف باشند. آن هم به هر قیمتی که شده! حتی به قیمت خلق کد‌بِیسی (Code Base) بسیار کثیف و آشفته...

ممزواد (Mamzavad)، مدیرفنی (CTO) و از محبوب‌ترین شخصیت‌های سوالات مسابقات برنامه‌نویسی کوئرا، به تازگی و پس از پیوستن شخصیت محبوب دیگر، یعنی آمین (Aaaamin)، به تیم فنی‌اش در کوئرا، شدیدا دچار تحول شده و بالاخره تصمیم گرفته است تا کدبِیس کثیف کوئرا را بعد از نزدیک به یک دهه بازنویسی کند! ممزواد که قرار است به زودی لود سنگین و جدید دیگری را نیز که سری دوم #المپیک‌فناوری پردیس است را تحمل کند، تصمیم گرفته تا توسعه فیچر‌های جدید را مستقل از بازنویسی کدبِیس کثیف کوئرا انجام دهد.

اگر از روز‌های نخستین کوئرا چیزی به یاد داشته باشید، کوئرای اولیه از پروژه‌ی قدیمی و معروف شریف‌جاج (Sharif Judge) شکل گرفته و به ترتیب در تمام یک دهه فعالیتش، بخش‌های زیادی از آن بازنویسی شده و ویژگی‌های بسیاری که امروزه نیز شما در حال استفاده از بسیاری از ویژگی‌ها هستید، به آن افزوده شدند. ممزواد نیز که تصمیم به بازنویسی کدبِیس کوئرا افتاده این‌بار اما با الهام از روز‌های قدیمی کوئرا، این پروژه جدید را با نام رمزی جاجِ مَمجَجاد تعریف کرده است. آمین، که خود نیز از الهام‌بخشان شروع پروژه بازنویسی کدبیس کوئرا و جاج مَمجَجاد بوده است می‌خواهد خود شخصا دست به کار شود تا چرخ این پروژه نیز مانند سایر پروژه‌های تعریف شده در کوئرا، به حرکت در بیاید.

توضیح تصویر

از آن‌جایی که کار جاج مَمجَجاد باید همزمان با آماده‌سازی ویژگی‌های جدید کوئرا برای سری جدید مسابقات المپیک‌فناوری پردیس پیشروی کند و آمین نیز به تازگی و پس از مدت زیادی کوئرا‌کاری، حسابی خسته شده و تصمیم به سفری طولانی مدت و بی‌بازگشت از مبدا کوئرا گرفته، با تهیه مستنداتی کامل از تمام اندپوینت‌ها (Endpoints) و سرویس‌ها در کوئرا، پروژه مهم و اساسی جاج مَمجَجاد را به شما، که با عبور از تمام سوالات سخت و مردافکن این مسابقه تا به این سوال رسیده‌اید، سپرده است.

پروژه اولیه

برای دانلود پروژه‌ی اولیه روی این این لینک کلیک کنید.

ساختار فایل‌ها

mini-quera
├── Dockerfile
├── accounts
├── contests
├── core
├── db.sqlite3
├── docker-compose.yml
├── entrypoint.sh
├── judge
├── judge-worker.Dockerfile
├── lms
├── manage.py
├── mini_quera
├── plagiarism
├── problems
├── requirements.txt
├── static
├── submission_files
├── submissions
└── templates

راه‌اندازی پروژه

برای اجرای پروژه، باید پایتون و ابزار داکر را از قبل نصب کرده باشید.

  • ابتدا فایل پروژه‌ی اولیه را از قسمت لینک بالا دانلود و استخراج کنید.

  • برای اجرای پروژه با داکر کامپوز، دستور زیر را در مسیر پوشه‌ی اصلی پروژه اجرا کنید. این دستور سرویس‌های پروژه‌ی جنگویی جاج مَمجَجاد، Celery، RabbitMQ و محیط داوری کد را در سیستم شما بالا می‌آورد:

docker compose up --build
  • بعد از بالا آمدن کانتینرها و توسعه مدل‌های جدید، مایگریشن‌های دیتابیس را اجرا کنید تا جداول مورد نیاز ایجاد شوند:
docker compose exec web python manage.py migrate
  • برای جمع‌آوری فایل‌های استاتیک و آماده‌سازی پروژه، دستور زیر را اجرا کنید:
docker compose exec web python manage.py collectstatic --noinput
  • در صورتی که تغییراتی در وابستگی‌ها ایجاد شد یا سرویس‌ها به مشکل برخوردند، کانتینرها را می‌توانید با استفاده از دستور زیر مجدداً اجرا کنید:
docker compose up --build -d
  • پس از اجرای موفق، وب‌اپلیکیشن جاج مَمجَجاد از طریق آدرس http://localhost:8000 در دسترس است و ادمین پنل مدیریت سرویس RabbitMQ از طریق آدرس http://localhost:15672 با نام کاربری rabbitmq_user و رمز عبور rabbitmq_pass قابل مشاهده خواهد بود.

جزئیات پروژه

پروژه جاج مَمجَجاد، دقیقا عملکردی مشابه آن‌چه امروزه شما به عنوان کوئرا می‌شناسید را دارد. این پروژه امکانات مختلفی از جمله احراز هویت کاربران، ساخت و مدیریت سوالات و تست‌کیس‌ها، ساخت مسابقات و کلاس‌های جدید و افزودن سوالات ساخته شده به آن‌ها، ارسال کد و داوری در سرویس جدا و مخصوص judge_worker که با داشتن وابستگی‌های مختلف، امکان اجرای کد‌‌های پایتونی، جاوا، سی و سی‌پلاس‌پلاس را امکان پذیر می‌کند.

معماری این پروژه به‌صورت ماژولار و مبتنی بر صف طراحی شده است؛ سرویس web مسئول مدیریت کاربران و اندپوینت‌های مختلف است، یک ورکر Celery با استفاده از RabbitMQ وظایف داوری را به‌صورت غیرهم‌زمان اجرا می‌کند و سرویس judge_worker محیطی ایزوله و امن برای اجرای کدها فراهم می‌سازد. این ساختار امکان داوری سریع، ایمن و مقیاس‌پذیر را برای زبان‌های مختلف برنامه‌نویسی فراهم کرده و جاج مَمجَجاد را بیش‌تر از قبل به کوئرای واقعی شبیه‌تر می‌کند.

معرفی سرویس‌های پروژه mini-quera

سرویس web

سرویس web هسته اصلی جاج مَمجَجاد است و مسئول ارائه APIها و رابط کاربری می‌باشد. این سرویس با Gunicorn اجرا شده و تمامی درخواست‌های کاربران را مدیریت می‌کند. جاج مَمجَجاد به سرویس rabbitmq و judge_worker متصل است تا وظایف داوری و پردازش پس‌زمینه را ارسال کند. تمامی اندپوینت‌ها، شامل ثبت نام، ارسال کد و دسترسی به مسابقات و مشکلات، از طریق این سرویس قابل دسترسی هستند.

سرویس celery

سرویس celery وظایف پس‌زمینه و زمان‌بر جاج را مدیریت می‌کند. این سرویس از RabbitMQ به عنوان پیام‌رسان (Message Broker) استفاده می‌کند تا تسک‌ها را بدون مسدود کردن سرویس web اجرا کند. وظایفی مانند داوری کدها و بررسی سرقت ادبی توسط این سرویس پردازش می‌شوند. با استفاده از این سرویس، اجرای همزمان چندین تسک بدون ایجاد تداخل یا کندی در پروژه امکان‌پذیر است.

سرویس judge_worker

سرویس judge_worker برای اجرای کدهای کاربران در محیط ایزوله طراحی شده است. این سرویس با نصب داشتن انواع وابستگی‌های مورد نیاز برای اجرای امن کدهای پایتون، C، C++ و جاوا استفاده می‌شود.خروجی و وضعیت اجرای کدها به سرویس web و celery بازگردانده می‌شود تا نتایج داوری ثبت و نمایش داده شوند. سرویس judge_worker به طور مستقل عمل می‌کند تا از تاثیر اجرای کدهای کاربران بر سرویس اصلی جلوگیری شود.

سرویس rabbitmq

سرویس rabbitmq پیام‌رسان (Message Broker) اصلی پروژه است که ارتباط بین سرویس‌های web، celery و judge_worker را برقرار می‌کند. این سرویس وظیفه مدیریت صف‌ها و ارسال پیام‌های مربوط به وظایف پس‌زمینه را دارد. بدون RabbitMQ، Celery نمی‌تواند تسک‌ها را دریافت و اجرا کند و هماهنگی بین سرویس‌ها از بین می‌رود. سرویس RabbitMQ امکان پردازش همزمان چندین تسک و مدیریت اولویت‌ها را فراهم می‌کند.


معرفی و پیاده‌سازی اپلیکیشن core (پیاده‌سازی اندپوینت health الزامی است!)

اپلیکیشن core باید شامل اندپوینت سلامت سرویس، مدیریت سیگنال‌های سیستم و تنظیمات تعامل با سرویس celery برای پردازش پس‌زمینه باشد.

بررسی سلامت سرویس (/health/)

این اندپوینت وضعیت کلی سرویس را بیان می‌کند و برای اطمینان از فعال بودن سرویس مورد استفاده قرار می‌گیرد. هیچ ورودی پیچیده‌ای نیاز ندارد و پاسخ آن ساده و سریع است.

curl -X GET http://localhost:8000/health/

پاسخ موفق:

{
  "status": "ok"
}

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

معرفی و پیاده‌سازی اپلیکیشن accounts

اپلیکیشن accounts مسئول مدیریت کاربران سامانه است. این اپ که بر پایه مدل AbstractUser جنگویی باید توسعه یابد، امکان ثبت نام کاربران جدید و مشاهده فهرست کاربران موجود را فراهم می‌کند. ثبت نام برای همه کاربران قابل دسترسی است، در حالی که مشاهده لیست کاربران فقط برای مدیران امکان‌پذیر است.

ثبت نام کاربر جدید (/api/accounts/register/)

ورودی اندپوینت ثبت نام کاربر جدید (/api/accounts/register/) شامل فیلدهای username، email، password، password2 و role است. مقدار فیلد role مشخص می‌کند کاربر چه نقشی در سامانه خواهد داشت، به عنوان مثال اگر مقدار آن برابر با admin باشد، کاربر با سطح دسترسی مدیریتی (is_staff) ایجاد می‌شود و در غیر این صورت سطح دسترسی معمولی مانند دانشجو یا استاد به او اختصاص می‌یابد. در صورت موفقیت در ثبت نام، پاسخ شامل اطلاعات کاربر تازه ایجاد شده به همراه شناسه کاربر است. اگر مقدارهای password و password2 با یکدیگر مطابقت نداشته باشند، سیستم خطای اعتبارسنجی را بازمی‌گرداند تا کاربر از اصلاح ورودی خود مطمئن شود.

curl -X POST http://localhost:8000/api/accounts/register/ \
-H "Content-Type: application/json" \
-d '{
  "username": "example_user",
  "email": "user@example.com",
  "password": "password123",
  "password2": "password123",
  "role": "student"
}'
  • در صورتی که رمز عبور و تکرار آن مطابقت نداشته باشند، خطای اعتبارسنجی با متن زیر بازگردانده می‌شود:
{
  "password": "رمز عبور مطابقت ندارد."
}
  • در پاسخ موفقیت‌آمیز ثبت نام، اطلاعات کاربر جدید بدون رمز عبور به شکل زیر نمایش داده می‌شود:
{
  "id": 1,
  "username": "example_user",
  "email": "user@example.com",
  "role": "student"
}

مشاهده لیست کاربران (/api/accounts/users/)

اندپوینت مشاهده لیست کاربران (/api/accounts/users/) تنها در صورتی قابل دسترسی است که کاربر دارای نقش مدیر باشد. در صورت پاسخ موفق، لیستی از کاربران موجود را بازمی‌گرداند که هر کاربر با شناسه، نام کاربری، ایمیل و نقش خود نمایش داده می‌شود. در صورتی که کاربر نقش مدیر نداشته باشد یا توکن معتبر ارسال نکند، پاسخ شامل خطای عدم دسترسی خواهد بود تا از مشاهده اطلاعات سایر کاربران جلوگیری شود.

curl -X GET http://localhost:8000/api/accounts/users/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در پاسخ موفق برای مشاهده لیست کاربران، فهرست کاربران موجود بازگردانده می‌شود، هر آیتم شامل id, username, email و role است:
[
  {
    "id": 1,
    "username": "example_user",
    "email": "user@example.com",
    "role": "student"
  },
  {
    "id": 2,
    "username": "admin_user",
    "email": "admin@example.com",
    "role": "admin"
  }
]
  • در صورتی که کاربر غیرمدیر به این اندپوینت دسترسی پیدا کند، خطای زیر بازگردانده می‌شود:
{
  "detail": "You do not have permission to perform this action."
}

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

معرفی و پیاده‌سازی اپلیکیشن problems

اپلیکیشن problems مسئول مدیریت سوالات (Problems) و تست‌کیس‌های (TestCases) جاج است. این اپ امکان ایجاد و مشاهده سوالات و مدیریت تست‌کیس‌ها را فراهم می‌کند. ایجاد سوالات و تست‌کیس‌ها فقط برای مدیران امکان‌پذیر است، اما مشاهده جزئیات و فهرست مسائل برای همه کاربران قابل دسترسی است.

ایجاد سوال جدید (/api/problems/create/)

ورودی اندپوینت ایجاد سوال جدید (/api/problems/create/) شامل فیلدهای title به عنوان عنوان سوال، description برای توضیح کامل سوال، input_description و output_description برای تشریح داده‌های ورودی و خروجی و محدودیت‌های زمان (time_limit) و حافظه (memory_limit) است. تنها مدیران می‌توانند از این اندپوینت استفاده کنند و در پاسخ موفق، تمام جزئیات مسئله شامل id، title، description، input_description، output_description، time_limit، memory_limit و آرایه‌ای از تست‌کیس‌های سوال (testcases) بازگردانده می‌شود. در صورتی که مقادیر time_limit یا memory_limit نامعتبر باشند، خطای اعتبارسنجی مناسب صادر می‌شود تا اطمینان حاصل شود که محدودیت‌ها مثبت و معتبر هستند.

curl -X POST http://localhost:8000/api/problems/create/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "title": "Sum of Numbers",
  "description": "Calculate the sum of given numbers",
  "input_description": "Two integers",
  "output_description": "Sum of integers",
  "time_limit": 1,
  "memory_limit": 64
}'
  • در صورت موفقیت، اطلاعات سوال ایجاد شده بازگردانده می‌شود:
{
  "id": 1,
  "title": "Sum of Numbers",
  "description": "Calculate the sum of given numbers",
  "input_description": "Two integers",
  "output_description": "Sum of integers",
  "time_limit": 1,
  "memory_limit": 64,
  "testcases": []
}
  • در صورت ارسال مقدار نامعتبر برای time_limit یا memory_limit، خطای اعتبارسنجی بازگردانده می‌شود:
{
  "time_limit": ["Time limit must be greater than 0 seconds."]
}

مشاهده فهرست سوالات (/api/problems/)

اندپوینت مشاهده فهرست سوالات (/api/problems/) خروجی را به صورت آرایه‌ای از سوالات بازمی‌گرداند که هر عنصر شامل id، title، description، input_description، output_description، time_limit، memory_limit و آرایه‌ای از تست‌کیس‌ها (testcases) است. این اندپوینت برای همه کاربران قابل دسترسی است و امکان مشاهده سوالات و تست‌کیس‌های مرتبط با آن‌ها را فراهم می‌کند. هر تست‌کیس شامل id، input_data، expected_output و is_sample است که مشخص می‌کند آیا تست‌کیس در نتیجه اصلی محاسبه می‌شود و یا صرفا به عنوان نمونه است و در سیستم داوری مورد استفاده قرار نمی‌گیرد.

curl -X GET http://localhost:8000/api/problems/
  • نمونه پاسخ موفق:
[
  {
    "id": 1,
    "title": "Sum of Numbers",
    "description": "Calculate the sum of given numbers",
    "input_description": "Two integers",
    "output_description": "Sum of integers",
    "time_limit": 1,
    "memory_limit": 64,
    "testcases": [
      {
        "id": 1,
        "input_data": "2 3",
        "expected_output": "5",
        "is_sample": true
      }
    ]
  }
]

مشاهده جزئیات سوال (/api/problems/<int:pk>/)

اندپوینت مشاهده جزئیات سوال (/api/problems/<int:pk>/) اطلاعات یک مسئله مشخص را بر اساس شناسه آن ارائه می‌دهد و شامل تمام فیلدهای مسئله مانند id، title، description، input_description، output_description، time_limit، memory_limit و آرایه‌ای از تست‌کیس‌ها (testcases) است. این اندپوینت برای همه کاربران قابل دسترسی است و اگر مسئله‌ای با شناسه مشخص وجود نداشته باشد، پاسخ شامل خطای استاندارد {"detail": "Not found."} خواهد بود.

curl -X GET http://localhost:8000/api/problems/1/
  • نمونه پاسخ موفق مشابه نمونه پاسخ فهرست سوالات است، اما فقط اطلاعات یک سوال بازگردانده می‌شود.

ایجاد تست‌کیس‌ها (/api/problems/testcases/create/)

ورودی اندپوینت ایجاد نمونه داده تست (/api/problems/testcases/create/) شامل problem به عنوان شناسه مسئله مرتبط، input_data، expected_output و is_sample برای مشخص کردن نمونه بودن یا اصلی بودن تست‌کیس است (تست‌کیس‌های نمونه در سیستم داوری مورد استفاده قرار نخواهند گرفت). تنها مدیران می‌توانند از این اندپوینت استفاده کنند و در پاسخ موفق، تمام جزئیات تست‌کیس شامل id، شناسه مسئله (probleminput_data، expected_output و is_sample بازگردانده می‌شود.

curl -X POST http://localhost:8000/api/problems/testcases/create/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "problem": 1,
  "input_data": "2 3",
  "expected_output": "5",
  "is_sample": true
}'
  • در پاسخ موفق، اطلاعات تست‌کیس ایجاد شده بازگردانده می‌شود:
{
  "id": 1,
  "problem": 1,
  "input_data": "2 3",
  "expected_output": "5",
  "is_sample": true
}

مشاهده تست‌کیس‌های یک سوال (/api/problems/<int:problem_id>/testcases/)

اندپوینت مشاهده تست‌کیس‌های یک سوال (/api/problems/<int:problem_id>/testcases/) خروجی را به صورت آرایه‌ای از تست‌کیس‌های مرتبط به سوال مشخص شده بازمی‌گرداند و هر تست‌کیس شامل id، input_data، expected_output و is_sample است. تنها مدیران قادر به دسترسی به این اندپوینت هستند و در صورت تلاش کاربران غیرمجاز، پاسخ شامل خطای {"detail": "You do not have permission to perform this action."} خواهد بود.

curl -X GET http://localhost:8000/api/problems/1/testcases/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • نمونه پاسخ موفق:
[
  {
    "id": 1,
    "input_data": "2 3",
    "expected_output": "5",
    "is_sample": true
  }
]
  • در صورت عدم دسترسی کاربر غیرمدیر، خطای زیر بازگردانده می‌شود:
{
  "detail": "You do not have permission to perform this action."
}

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

معرفی و پیاده‌سازی اپلیکیشن submissions

اپلیکیشن submissions مسئول مدیریت ارسال کد کاربران و بررسی وضعیت اجرای آن‌هاست. کاربران می‌توانند کد خود را ارسال کنند و وضعیت اجرای آن شامل موفقیت، خطا، خروجی و زمان اجرا را مشاهده کنند.

ارسال کد برای اجرا (/api/submissions/submit/)

اندپوینت ارسال کد برای اجرا (/api/submissions/submit/) ورودی را به صورت multipart/form-data دریافت می‌کند که شامل فیلد problem برای مشخص کردن شناسه سوال، code_file به عنوان فایل کد کاربر و language برای تعیین زبان برنامه‌نویسی است. کاربران ثبت‌نام شده با توکن معتبر می‌توانند از این اندپوینت استفاده کنند و در پاسخ موفق، شناسه ارسال (submission_id) و وضعیت اولیه submitted بازگردانده می‌شود تا سیستم داوری بتواند ارسال را پیگیری کند. در صورتی که هر یک از فیلدها خالی یا نامعتبر باشند، خطای مناسب شامل پیام‌هایی مانند This field is required. یا No file was submitted. نمایش داده می‌شود.

سیگنال‌های ایجاد شده توسط این اندپوینت وضعیت اجرای کد را در سه وضعیت ACCEPTED ,FAILED و ERROR ثبت می‌کنند. هر لاگ مرتبط با یک اجرای کد شامل وضعیت کلی، خروجی تولید شده، خطا در صورت وجود و زمان اجرای کد است. سیستم داوری باید با استفاده از سرویس judge_worker و سیگنال‌هایی که توسط سرویس celery پردازش خواهند شد، هنگام داوری سوال هر تست‌کیس غیر نمونه‌ای را جداگانه اجرا کند و نتیجه آن با مقایسه خروجی واقعی و خروجی مورد انتظار ثبت شود. اگر تمام تست‌کیس‌ها درست باشند، وضعیت نهایی ACCEPTED خواهد بود، در صورت عدم شباهت خروجی‌ها در حداقل یک تست‌کیس وضعیت نهایی FAILED می‌شود و اگر اجرای کد با خطا مواجه شود یا زبان پشتیبانی نشود، وضعیت ERROR باید ثبت گردد.

curl -X POST http://localhost:8000/api/submissions/submit/ \
-H "Content-Type: multipart/form-data" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-F "problem=1" \
-F "code_file=@solution.py" \
-F "language=python"
  • در صورت موفقیت‌آمیز بودن ارسال، پاسخ شامل شناسه ارسال و وضعیت اولیه است:
{
  "submission_id": 42,
  "status": "submitted"
}
  • در صورتی که داده‌های ارسالی نامعتبر باشند، خطا‌های زیر بازگردانده می‌شود:
{
  "problem": ["This field is required."],
  "code_file": ["No file was submitted."],
  "language": ["This field is required."]
}

مشاهده وضعیت ارسال (/api/submissions/status/<int:submission_id>/)

اندپوینت مشاهده وضعیت ارسال (/api/submissions/status/<int:submission_id>/) تمام لاگ‌های یک ارسال مشخص را برای کاربر ارسال بازمی‌گرداند**. هر لاگ شامل وضعیت اجرای کد** (ACCEPTED, FAILED, ERRORخروجی تولید شده، خطا در صورت وجود، زمان اجرای کد و زمان ثبت لاگ است. پاسخ به صورت لیست از لاگ‌ها بازگردانده می‌شود و ترتیب آن بر اساس ترتیب صعودی زمان ثبت لاگ (created_at) است. تنها کاربر صاحب ارسال یا مدیر با توکن معتبر می‌تواند به این اندپوینت دسترسی داشته باشد و اگر شناسه ارسال وجود نداشته باشد یا متعلق به کاربر دیگری باشد، پاسخ شامل خطای {"error": "Submission not found"} خواهد بود.

همچنین توجه داشته باشید که در این اندپوینت، کلید output شامل نتایج اجرای کد برای تست‌کیس‌های غیر نمونه‌ی تعریف شده برای هر سوال به شکل دقیقا TestCase #n: {PASS, FAIL} خواهد بود که همگی باید توسط \n به یکدیگر متصل شده و نمایش داده شوند.

curl -X GET http://localhost:8000/api/submissions/status/42/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • نمونه پاسخ موفق:
[
    {
        "id": 6,
        "submission": 42,
        "status": "ERROR",
        "output": null,
        "error": "Some error text",
        "created_at": "2025-09-25T06:07:17.911261Z"
    },
    {
        "id": 7,
        "submission": 42,
        "status": "ACCEPTED",
        "output": "TestCase #1: PASS\nTestCase #2: PASS",
        "error": null,
        "created_at": "2025-09-25T06:07:23.145892Z"
    }
]
  • در صورتی که شناسه ارسال وجود نداشته باشد یا متعلق به کاربر دیگری باشد، خطای زیر بازگردانده می‌شود:
{
  "error": "Submission not found"
}

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

معرفی و پیاده‌سازی اپلیکیشن contests

اپلیکیشن contests مسئول مدیریت مسابقات است. این اپ قابلیت ایجاد مسابقه جدید، مشاهده جزئیات مسابقه، فهرست مسابقات و مشاهده رده‌بندی زنده مسابقات را فراهم می‌کند. همه اندپوینت‌ها نیازمند احراز هویت کاربر هستند و تنها کاربران وارد شده قادر به استفاده از آن‌ها هستند.

ایجاد مسابقه جدید (/api/contests/create/)

ورودی اندپوینت ایجاد مسابقه جدید (/api/contests/create/) شامل فیلدهای name به عنوان نام مسابقه، start_time و end_time به صورت تاریخ و زمان است. تمام این فیلدها باید معتبر باشند و شرط اصلی این است که end_time بعد از start_time باشد؛ در غیر این صورت خطای اعتبارسنجی با پیام End time must be after start time بازمی‌گرداند. در پاسخ موفق، تمام اطلاعات مسابقه شامل id و name، start_time، end_time، description نمایش دهد. این اندپوینت تنها برای کاربران وارد شده با توکن معتبر قابل دسترسی است و سریالایزر اعتبار داده‌ها را تضمین می‌کند.

curl -X POST http://localhost:8000/api/contests/create/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "name": "Sample Contest",
  "start_time": "2025-09-14T10:00:00Z",
  "end_time": "2025-09-14T12:00:00Z"
}'
  • خطای اعتبارسنجی در صورت اشتباه بودن زمان‌ها:
{
  "end_time": "End time must be after start time"
}
  • در پاسخ موفق، جزئیات مسابقه ایجاد شده برگردانده می‌شود:
{
  "id": 1,
  "name": "Sample Contest",
  "start_time": "2025-09-14T10:00:00Z",
  "end_time": "2025-09-14T12:00:00Z",
}

مشاهده جزئیات مسابقه (/api/contests/<int:pk>/)

اندپوینت مشاهده جزئیات مسابقه (/api/contests/<int:pk>/) اطلاعات کامل یک مسابقه مشخص را بر اساس شناسه آن ارائه می‌دهد. خروجی شامل id، name، start_time، end_time، description می‌باشد. کاربران برای دسترسی باید وارد سامانه باشند و در صورت درخواست برای کانتستی که وجود ندارد، پاسخ شامل خطای {"detail": "Not found."} خواهد بود. این اندپوینت به کاربر امکان می‌دهد جزئیات کامل مسابقه را مشاهده کند.

curl -X GET http://localhost:8000/api/contests/1/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در صورت عدم وجود مسابقه با شناسه مورد نظر، خطای زیر بازگردانده می‌شود:
{
  "detail": "Not found."
}
  • در پاسخ موفق، جزئیات مسابقه شامل تمام فیلدهای آن نمایش داده می‌شود.

مشاهده لیست مسابقات (/api/contests/)

اندپوینت مشاهده فهرست مسابقات (/api/contests/) تمام مسابقات موجود در جاجِ مَمجَجاد را به صورت آرایه‌ای بازمی‌گرداند. هر عنصر آرایه شامل id، name، start_time، end_time، description می‌باشد. این اندپوینت نیز محدود به کاربران وارد شده است و به آن‌ها اجازه می‌دهد تمام مسابقات فعال و گذشته را مشاهده کنند.

curl -X GET http://localhost:8000/api/contests/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در پاسخ موفق، آرایه‌ای از اطلاعات مسابقات شامل id, name, start_time و end_time بازگردانده می‌شود:
[
  {
    "id": 1,
    "name": "Sample Contest",
    "start_time": "2025-09-14T10:00:00Z",
    "end_time": "2025-09-14T12:00:00Z"
  },
  {
    "id": 2,
    "name": "Another Contest",
    "start_time": "2025-09-15T09:00:00Z",
    "end_time": "2025-09-15T11:00:00Z"
  }
]

مشاهده رده‌بندی زنده مسابقه (/api/contests/<int:contest_id>/standings/live/)

اندپوینت مشاهده رده‌بندی زنده مسابقه (/api/contests/<int:contest_id>/standings/live/) امکان دریافت امتیازات شرکت‌کنندگان به صورت لحظه‌ای (Streaming) را فراهم می‌کند. کاربران وارد شده می‌توانند با ارسال توکن معتبر، جریان داده را در هر ثانیه دریافت کنند که شامل آرایه‌ای از دیکشنری‌ها است و هر دیکشنری شامل کلید user و مقدار نام کاربری شرکت‌کننده و کلید score به عنوان امتیاز فعلی او می‌باشد. اگر مسابقه با شناسه مورد نظر وجود نداشته باشد، پاسخ شامل خطای {"detail": "No Contest matches the given query."} خواهد بود. همچنین رده‌بندی بر اساس امتیازات بدست آمده از ارسال‌های در سوالات مسابقه مشخص شده به صورت نزولی است.

curl -N http://localhost:8000/api/contests/1/standings/live/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در صورتی که مسابقه‌ای با شناسه مورد نظر وجود نداشته باشد، خطای زیر بازگردانده می‌شود:
{
  "detail": "No Contest matches the given query."
}
  • در پاسخ موفق، داده‌ها به صورت استریم هر ثانیه بروزرسانی می‌شوند:
data: [{"user": "user1", "score": 100}, {"user": "user2", "score": 90}]

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

معرفی و پیاده‌سازی اپلیکیشن lms

اپلیکیشن lms مسئول مدیریت کلاس‌ها، درس‌ها و مسائل مرتبط با درس‌ها است. این اپ قابلیت ایجاد و مدیریت کلاس‌ها، ایجاد درس‌ها و مسائل و ثبت‌نام دانش‌آموزان در کلاس‌ها را فراهم می‌کند. همه اندپوینت‌ها نیازمند احراز هویت هستند و بسیاری از آن‌ها فقط برای مدیران قابل دسترسی هستند.

لیست و ایجاد کلاس‌ها (/api/lms/classes/)

ورودی اندپوینت لیست و ایجاد کلاس‌ها (/api/lms/classes/) شامل فیلد name به عنوان نام کلاس، teacher به عنوان شناسه استاد مرتبط با کلاس و students به صورت آرایه‌ای از شناسه‌های دانش‌آموزان است. این اندپوینت تنها برای مدیران قابل دسترسی است و در پاسخ موفق، تمام جزئیات کلاس شامل id، name، شناسه استاد (teacher) و آرایه شناسه‌های دانش‌آموزان (students) بازگردانده می‌شود. نام کلاس نباید خالی باشد و استاد و دانش‌آموزان باید همگی موجود باشند.

curl -X POST http://localhost:8000/api/lms/classes/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "name": "Sample Class",
  "teacher": 1,
  "students": [1]
}'
  • در پاسخ موفق، جزئیات کلاس ایجاد شده برگردانده می‌شود:
{
  "id": 1,
  "name": "Sample Class",
  "teacher": 1,
  "students": [1]
}

جزئیات کلاس (/api/lms/classes/<int:pk>/)

اندپوینت جزئیات کلاس (/api/lms/classes/<int:pk>/) اطلاعات کامل یک کلاس مشخص را بر اساس شناسه آن ارائه می‌دهد و شامل id، name، شناسه استاد (teacher) و آرایه دانش‌آموزان (students) است. این اندپوینت تنها برای مدیران قابل دسترسی است و در صورتی که کلاس با شناسه مورد نظر وجود نداشته باشد، پاسخ شامل خطای {"detail": "Not found."} خواهد بود.

curl -X GET http://localhost:8000/api/lms/classes/1/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در صورت عدم وجود کلاس، خطای زیر بازگردانده می‌شود:
{
  "detail": "Not found."
}

افزودن دانش‌آموز در کلاس (/api/lms/classes/<int:class_id>/enroll/)

اندپوینت افزودن دانش‌آموز در کلاس (/api/lms/classes/<int:class_id>/enroll/) شامل فیلد student_id برای مشخص کردن شناسه دانش‌آموز است. تنها مدیران می‌توانند از این اندپوینت استفاده کنند و در پاسخ موفق، پیغام {"status": "enrolled"} بازگردانده می‌شود. در صورتی که کلاس یا دانش‌آموز وجود نداشته باشند، پاسخ شامل خطای {"error": "Class not found"} یا {"error": "Student not found"} خواهد بود و اگر student_id ارسال نشود، خطای {"error": "student_id is required"} بازگردانده می‌شود. این اندپوینت امکان مدیریت ثبت‌نام دانش‌آموزان در کلاس مورد نظر را فراهم می‌کند.

curl -X POST http://localhost:8000/api/lms/classes/1/enroll/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "student_id": 2
}'
  • در پاسخ موفق:
{
  "status": "enrolled"
}
  • در صورت عدم وجود کلاس یا دانش‌آموز:
{"error": "Class not found"}
{"error": "Student not found"}
  • و اگر student_id ارسال نشود:
{"error": "student_id is required"}

لیست و ایجاد درس‌ها (/api/lms/lessons/)

ورودی اندپوینت لیست و ایجاد درس‌ها (/api/lms/lessons/) شامل name به عنوان نام درس و class_obj به عنوان شناسه کلاس مرتبط است. این اندپوینت تنها برای مدیران قابل دسترسی است و در پاسخ موفق، تمام جزئیات درس شامل id، name و شناسه کلاس (class_obj) بازگردانده می‌شود تا امکان مدیریت و پیگیری درس‌ها فراهم شود.

curl -X POST http://localhost:8000/api/lms/lessons/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "name": "Lesson 1",
  "class_obj": 1
}'
  • در پاسخ موفق، جزئیات درس جدید بازگردانده می‌شود.

جزئیات درس (/api/lms/lessons/<int:pk>/)

اندپوینت جزئیات درس (/api/lms/lessons/<int:pk>/) اطلاعات کامل یک درس مشخص را ارائه می‌دهد و شامل id، name و شناسه کلاس مرتبط (class_obj) است. تنها مدیران قادر به دسترسی به این اندپوینت هستند و در صورت عدم وجود درس با شناسه مشخص، پاسخ شامل خطای {"detail": "Not found."} خواهد بود.

curl -X GET http://localhost:8000/api/lms/lessons/1/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در صورت عدم وجود درس:
{
  "detail": "Not found."
}

لیست و ایجاد مسائل درس (/api/lms/lesson-problems/)

ورودی اندپوینت لیست و ایجاد مسائل درس (/api/lms/lesson-problems/) شامل title برای عنوان مسئله، lesson به عنوان شناسه درس مرتبط و problem به عنوان شناسه مسئله دریافت می‌کند. تنها مدیران می‌توانند از این اندپوینت استفاده کنند و در پاسخ موفق، جزئیات مسئله شامل id، title، شناسه درس (lesson) و شناسه مسئله (problem) بازگردانده می‌شود.

curl -X POST http://localhost:8000/api/lms/lesson-problems/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "title": "Problem 1",
  "lesson": 1,
  "problem": 1
}'

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

معرفی و پیاده‌سازی اپلیکیشن plagiarism

اپلیکیشن plagiarism مسئول بررسی شباهت کدهای ارسال شده توسط کاربران و تشخیص موارد سرقت ادبی کد (Code Plagiarism) است. این اپ امکان اجرای بررسی سرقت ادبی برای یک مسئله خاص یا تمامی ارسال‌ها و مشاهده نتایج بررسی‌ها را فراهم می‌کند. همه اندپوینت‌ها فقط برای مدیران قابل دسترسی هستند.

اجرای بررسی تقلب (/api/plagiarism/run/)

ورودی اندپوینت اجرای بررسی تقلب (/api/plagiarism/run/) شامل فیلد اختیاری problem_id برای محدود کردن بررسی به یک مسئله مشخص است. اگر این فیلد ارسال نشود، بررسی روی تمامی ارسال‌ها انجام می‌شود. تنها مدیران می‌توانند از این اندپوینت استفاده کنند و در پاسخ موفق، پیغام {"status": "Plagiarism check completed"} بازگردانده می‌شود تا مشخص شود فرآیند بررسی به پایان رسیده است. در پس‌زمینه، جاجِ مَمجَجاد تمامی ارسال‌ها را مقایسه می‌کند و با استفاده از مقایسه ساختار درختی *AST،*میزان شباهت بین هر جفت ارسال را محاسبه می‌کند. اگر درصد شباهت بین دو ارسال بیشتر یا مساوی 70% باشد، ارسال‌ها به عنوان تقلب علامت‌گذاری (Flagged) می‌شوند. این روش تضمین می‌کند که شباهت‌های ساده ناشی از تغییر نام متغیر یا فرمت‌بندی، باعث تشخیص تقلب نادرست نشوند و تنها شباهت‌های واقعی در ساختار کد مشخص شوند.

curl -X POST http://localhost:8000/api/plagiarism/run/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-d '{
  "problem_id": 5
}'
  • اگر problem_id ارسال نشود، بررسی روی تمام ارسال‌ها انجام می‌شود.
{
  "status": "Plagiarism check completed"
}

مشاهده نتایج بررسی تقلب (/api/plagiarism/results/)

اندپوینت مشاهده نتایج بررسی تقلب (/api/plagiarism/results/) خروجی را به صورت آرایه‌ای از نتایج بازمی‌گرداند که هر آیتم شامل id به عنوان شناسه رکورد، submission1 و submission2 به عنوان شناسه‌های دو ارسال مقایسه شده، similarity به صورت درصد شباهت بین دو کد، flagged به صورت بولین که مشخص می‌کند آیا دو ارسال به عنوان تقلب علامت‌گذاری شده‌اند یا خیر و created_at به عنوان زمان ثبت نتیجه است. تنها مدیران قادر به دسترسی به این اندپوینت هستند و در صورت عدم دسترسی کاربر غیرمدیر، پاسخ شامل پیغام خطای {"detail": "You do not have permission to perform this action."} خواهد بود. این خروجی به سیستم داوری امکان می‌دهد تا به صورت دقیق و خودکار تشخیص دهد کدام ارسال‌ها از نظر شباهت کد به هم نزدیک هستند و کدام موارد نیاز به بررسی دستی برای تعیین تقلب دارند.

curl -X GET http://localhost:8000/api/plagiarism/results/ \
-H "Authorization: Bearer <YOUR_TOKEN>"
  • در پاسخ موفق، آرایه‌ای از نتایج بازگردانده می‌شود:
[
  {
    "id": 1,
    "submission1": 10,
    "submission2": 15,
    "similarity": 85.5,
    "flagged": true,
    "created_at": "2025-09-14T12:00:00Z"
  },
  {
    "id": 2,
    "submission1": 11,
    "submission2": 12,
    "similarity": 45.0,
    "flagged": false,
    "created_at": "2025-09-14T12:05:00Z"
  }
]
  • در صورت عدم دسترسی کاربر غیرمدیر:
{
  "detail": "You do not have permission to perform this action."
}

جدول پیاده‌سازی

تصویر جدول پیاده‌سازی

آن‌چه باید آپلود کنید

  • توجه: تمام مواردی که در سیستم داوری سوال مورد ارزیابی قرار می‌گیرند، به جزئیات و به صورت مفصل در متن سوال به همراه ذکر مثال‌ها توضیح داده شده‌اند. مواردی که در متن سوال به ان‌ها اشاره‌ای نشده است، مانند نحوه پیاده‌سازی مدل‌ها، سیگنال‌ها، سریالایزر‌ها و ... در سیستم داوری به صورت مستقیم مورد ارزیابی قرار نخواهند گرفت و می‌توانند به دلخواه شما، اما در چارچوب سوال پیاده‌سازی شوند.

  • توجه: سرویس‌هایی که در این سوال از آن‌ها می‌توانید استفاده کنید و در فایل docker-compose.yml تعریف شده‌اند، همگی در بخش معرفی سرویس‌های پروژه مشخص شده و تعریف سرویس جدید و یا شخصی سازی سرویس‌های موجود با استفاده از تغییر فایل داکر کامپوز، امکان پذیر نیست!

  • توجه: شما در این سوال مجاز به ایجاد هر گونه تغییرات جدیدی در داکرفایل‌ها، فایل docker-compose.yml و تنظیمات از پیش انجام شده‌ی پروژه جنگویی نیستید و پیاده‌سازی‌های شما صرفا باید به اپلیکیشن‌های مشخص شده در بخش ساختار فایل‌ها محدود شود. همچنین شما در این سوال مجاز به ایجاد اپلیکیشن جدیدی نیز نیستید.

  • توجه: کد‌های وضعیت در سیستم داوری دارای اهمیت بوده و بررسی خواهند شد. کد‌های وضعیت زیر، کد‌هایی که هستند در پیاده‌سازی اندپوینت‌های مختلف باید به صورت منطقی و با توجه به اطلاعات هر بخش مورد استفاده قرار گیرند:

    • کد 403Forbidden: کاربر مجوز دسترسی به این منابع یا عملیات را ندارد.
    • کد 400Bad Request: درخواست ارسال شده نامعتبر است یا داده‌ها ناقص هستند.
    • کد 200OK: درخواست موفق بوده و پاسخ مورد انتظار بازگردانده شده است.
    • کد 201Created: منبع جدید با موفقیت ایجاد شده است (مانند ارسال کد یا ساخت کلاس جدید).
    • کد 401Unauthorized: کاربر احراز هویت نشده یا توکن معتبر ندارد.
    • کد 404Not Found: منبع مورد نظر وجود ندارد یا کاربر دسترسی به آن ندارد.
  • توجه: پس از پیاده‌سازی موارد خواسته شده، کل فایل‌های را زیپ کرده و ارسال کنید.

  • توجه: شما مجاز به افزودن فایل جدیدی در این ساختار نیستید و تنها باید تغییرات را در فایل‌های موجود اعمال کنید.

  • توجه: که نام فایل Zip اهمیتی ندارد.

ارسال پاسخ برای این سؤال
فایلی انتخاب نشده است.