دیتابیس تست کدکاپ


سلام بر کد‌کاپ!

— کدکاپی‌ها

بچه‌های کدکاپ قصد دارند تا قبل از شروع مسابقه اصلی، مسابقه‌ای را ترتیب دهند و سؤالات را تست کنند، اما آن‌ها نمی‌خواهند تا تغییرات در دیتابیس اصلی پروژه اعمال شوند آن‌ها. از شما می‌خواهند تا لاراول را طوری کانفیگ کنید که بتوانند به‌راحتی با دیتابیس‌های‌شان کار کنند.

جزئیات پروژه🔗

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

ساختار فایل‌ها
codecup_test_connection
├── app
├── bootstrap
├── config
│   ├── app.php
│   ├── auth.php
│   ├── broadcasting.php
│   ├── cache.php
│   ├── cors.php
│   ├── database.php
│   ├── filesystems.php
│   ├── hashing.php
│   ├── logging.php
│   ├── mail.php
│   ├── queue.php
│   ├── sanctum.php
│   ├── services.php
│   ├── session.php
│   └── view.php
├── database
│   ├── factories
│   ├── migrations
│   ├── seeders
│   ├── codecup.sqlite
│   └── codecup_test.sqlite
├── public
├── resources
├── routes
│   ├── api.php
│   ├── channels.php
│   ├── console.php
│   └── web.php
├── storage
├── tests
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
Plain text
راه‌اندازی پروژه

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

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.
  • برای اجرای تست‌های نمونه، می‌توانید از دستور php artisan test استفاده کنید.

در دایرکتوری database دو دیتابیس codecup.sqlite و codecup_test.sqlite وجود دارد. درون هر یک از این دیتابیس‌ها جدولی با همان نام دیتابیس وجود دارد و اطلاعاتی نیز داخل جدول‌ها وجود دارد.

شما باید تنظیماتی را فراهم کنید تا بتوان اتصالی با هر یک از این دیتابیس‌ها برقرار کرد و محتوای جداول دلخواه را برگرداند. برای مثال، کد زیر باید اطلاعات جدول codecup_test داخل دیتابیس codecup_test را برگرداند:

DB::connection('codecup_test')->table('codecup_test')->get();
PHP

نام کانکشن دیتابیس codecup.sqlite باید برابر با codecup باشد و نام کانکشن دیتابیس codecup_test.sqlite باید برابر با codecup_test باشد.

نکات🔗

  • محتوای اطلاعاتی که از جداول برگردانده می‌شوند اهمیتی ندارد و فقط ملاک داوری برقراری ارتباط با دیتابیس‌ها و اجرای کوئری روی جداول آن‌ها است.
  • شما تنها مجاز به اعمال تغییرات در فایل config/database.php هستید.

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

پس از اعمال تغییرات، فایل config/database.php را آپلود کنید.

QPedia


امان از ویرایش‌های ویکی‌پدیا!

— حامد

حامد که از محتوای ویکی‌پدیا بسیار ناراحت و خسته شده، قصد دارد تا آن را به شیوه‌ای که خودش دوست دارد پیاده‌سازی کند. او می‌خواهد رفتار تمام کاربرانی که پستی را ویرایش می‌کنند را زیر نظر داشته باشد و هم‌چنین اطلاعات سازنده و آخرین ویرایش‌کننده را هم سریعاً به‌دست بیاورد.

شما باید برای رسیدن به این هدف به او کمک کنید.

جزئیات پروژه🔗

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

ساختار فایل‌ها
qpedia
├── app
│   ├── Console
│   ├── Exceptions
│   ├── Http
│   ├── Models
│   │   ├── Edit.php
│   │   ├── Post.php
│   │   └── User.php
│   └── Providers
├── bootstrap
├── config
├── database
│   ├── factories
│   │   └── UserFactory.php
│   ├── migrations
│   │   ├── 2014_10_12_000000_create_users_table.php
│   │   ├── 2014_10_12_100000_create_password_resets_table.php
│   │   ├── 2019_08_19_000000_create_failed_jobs_table.php
│   │   ├── 2019_12_14_000001_create_personal_access_tokens_table.php
│   │   ├── 2021_11_30_135802_create_posts_table.php
│   │   ├── 2021_11_30_135820_create_edits_table.php
│   │   └── 2021_11_30_140323_create_edit_post_table.php
│   └── seeders
├── public
├── resources
├── routes
├── storage
├── tests
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
Plain text
راه‌اندازی پروژه

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

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.
  • برای اجرای تست‌های نمونه، می‌توانید از دستور php artisan test استفاده کنید.

مایگریشن‌ها🔗

مایگریشن‌های مربوط به پروژه از قبل ایجاد شده‌اند. در اولین گام باید ساختار جداول پروژه را مطابق توضیحات زیر تکمیل کنید:

مایگریشن posts: ستون‌های زیر را به مایگریشن جدول posts اضافه کنید:

نام ستون نوع تعریف
user_id bigInteger کلید خارجی به جدول users و ستون id
title string عنوان
body text بدنه
created_by bigInteger آی‌دی کاربر ایجاد‌کننده‌ی پست
updated_by bigInteger آی‌دی آخرین کاربر به‌روز‌کننده‌ی پست

مایگریشن edits: ستون‌های زیر را به مایگریشن جدول edits اضافه کنید:

نام ستون نوع تعریف
user_id bigInteger کلید خارجی به جدول users و ستون id
change string ستون تغییر‌یافته مثلا title
value string مقدار جدید

سپس باید بین این جداول روابط زیر را برقرار کنید:

  • هر کاربر می‌تواند چندین پست ایجاد کند و هر پست متعلق به یک کاربر است.
  • هر کاربر می‌تواند چندین ویرایش بر روی پست‌ها داشته باشد و هر ویرایش را یک کاربر ایجاد کرده است.
  • بین جدول پست‌ها و جدول ویرایش‌ها باید رابطه‌ی چند‌به‌چند وجود داشته باشد. مایگریشن مربوط به جدول میانی این رابطه هم که از قبل وجود دارد نیز باید تکمیل شود.

ساختار نهایی جداول باید به‌صورت زیر باشد:

نمودار ER

مدل‌ها🔗

در آخرین گام شما باید امکانی را به این پروژه اضافه کنید که اگر پستی ایجاد شد، مقادیر created_by و updated_by این پست با آی‌دی کاربری که این پست را ایجاد کرده پر شود و اگر پستی آپدیت شد، مقدار updated_by آن نیز با آی‌دی کاربری که این پست را آپدیت کرد پر شود. در این حالت که پست آپدیت شد، باید مقدار تغییریافته‌ی پست را به دست آورده و آن را به جدول ویرایش‌ها اضافه کنید.

برای درک بهتر سؤال، فرض کنید کاربری با آی‌دی 1 پستی را با عنوان تست و محتوا تست تست تست ایجاد کرده. مقادیر created_by و updated_by این پست باید با مقدار 1 در دیتابیس وجود داشته باشند. حال فرض کنید کاربری با آی‌دی 2 عنوان این پست را به test ویرایش می‌کند. در این حالت باید مقدار updated_by این پست به آی‌دی 2 تغییر کند و هم‌چنین یک سطر به صورت زیر در جدول ویرایش‌ها اضافه شود:

user_id change value
2 title test

نکات🔗

  • تضمین می‌شود که هنگام ویرایش پست‌ها کاربر در برنامه لاگین کرده است.
  • شما تنها مجاز به اعمال تغییرات در پوشه‌های app/Models و database/migrations هستید.
  • شما باید برای هر تغییر، یک سطر به جدول ویرایش‌ها اضافه کنید؛ یعنی اگر در مثال قبل علاوه بر عنوان پست، محتوای پست هم تغییر می‌کرد، باید یک سطر دیگر هم به جدول ویرایش‌ها اضافه می‌شد.

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

پس از پیاده‌سازی موارد خواسته‌شده، پوشه‌های app و database را زیپ کرده و آپلود کنید.

مدل‌ساز


اخیراً به هوتن تسکی داده شده که باید دیتابیسی پر از جدول با روابط متعدد ایجاد کند. او که از این کار خسته شده، ایده‌ای به ذهنش رسیده که این فرایند را خودکار کند. برای این کار به هوتن کمک کنید.

جزئیات پروژه🔗

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

ساختار فایل‌ها
model-maker
├── app
├── bootstrap
├── config
├── database
├── public
├── resources
├── routes
├── storage
├── tests
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
Plain text
راه‌اندازی پروژه

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

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.
  • برای اجرای تست‌های نمونه، می‌توانید از دستور php artisan test استفاده کنید.

شما باید دستوری را ایجاد کنید تا مدل‌ها و مایگریشن‌هایی را با جزئیاتی که در ادامه گفته می‌شود، ایجاد کند.

قالب دستوری که می‌سازید باید به‌صورت زیر باشد:

php artisan make:custom-model MODEL_NAME_1 MODEL_NAME_2 --type=RELATION_TYPE
Shell

دستور فوق به این معنی است که باید دو مدل با نام‌های MODEL_NAME_1 و MODEL_NAME_2 ایجاد شوند و بین این دو مدل رابطه‌ای از نوع RELATION_TYPE برقرار شود. مقدار RELATION_TYPE می‌تواند یکی از مقادیر 11، 1n یا nn باشد. 11 به‌معنی رابطه‌ی One to One ، 1n به‌معنی رابطه‌ی One to Many و nn به‌معنی رابطه‌ی Many to Many است.

مثال🔗

فرض کنید دستور زیر اجرا می‌شود:

php artisan make:custom-model Author Book --type=nn
Shell

با اجرای دستور فوق، باید فایل‌های Author.php و Book.php در دایرکتوری app/Models ایجاد شوند. محتویات فایل‌های این دو کلاس باید به‌صورت زیر باشد:

محتویات مدل‌ها
extensionFromNameapp/Models/Author.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
    use HasFactory;

    public function books()
    {
        return $this->belongsToMany(Book::class);
    }
}
PHP
extensionFromNameapp/Models/Book.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    use HasFactory;

    public function authors()
    {
        return $this->belongsToMany(Author::class);
    }
}
PHP

هم‌چنین مایگرشن‌های مورنیاز مدل‌ها و رابطه‌شان باید ایجاد شود:

محتویات مایگریشن‌ها
extensionFromNamedatabase/migrations/2021_11_16_202919_create_authors_table.php
class CreateAuthorsTable extends Migration
{
    public function up()
    {
        Schema::create('authors', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('authors');
    }
}
PHP
extensionFromNamedatabase/migrations/2021_11_16_202921_create_books_table.php
class CreateBooksTable extends Migration
{
    public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('books');
    }
}
PHP
extensionFromNamedatabase/migrations/2021_11_16_202922_create_author_book_table.php
class CreateAuthorBookTable extends Migration
{
    public function up()
    {
        Schema::create('author_book', function (Blueprint $table) {
            $table->id();
            $table->foreignId('author_id')->constrained()->onDelete('cascade');
            $table->foreignId('book_id')->constrained()->onDelete('cascade');
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('author_book');
    }
}
PHP

نکته‌ی مهمی که باید به آن دقت کنید نام روابط در مدل‌هاست، که باید به‌صورت زیر قرار دهید:

  • اگر نوع رابطه مفرد به مفرد بود نام رابطه باید به‌صورت مفرد کلاس هدف قرار گیرد مثلا فرض کنید بین دو مدل User و Name رابطه یک‌به‌یک برقرار است پس نام رابطه در مدل User باید برابر name قرار گیرد.
  • اگر نوع رابطه مفرد به جمع بود نام رابطه باید به‌صورت جمع کلاس هدف قرار گیرد مثل مدل‌های Author و Book مثال ذکر شده در همین سوال.

تضمین می‌شود که در دستور نام مدل‌ها به‌صورت صحیح داده می‌شوند.

نکات🔗

  • برای هر رابطه باید مدل و مایگریشن متناسب با نوع رابطه ایجاد شود.
  • در نام‌گذاری جداول، باید از convention لاراول پیروی کنید.
  • تمامی این فرایند‌ها باید به‌صورت خودکار انجام شود و در داوری، ساخت مدل‌های مختلف تست می‌شود.
  • برای ساخت مایگریشن‌ها حتماً به زمان ساخت مایگریشن‌ها دقت کنید تا به‌ترتیب اجرا شوند.
  • شما تنها مجاز به اعمال تغییرات در پوشه app و در صورت نیاز stubs هستید.

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

پس از پیاده‌سازی موارد خواسته‌شده، پوشه‌ی app و پوشه‌ی stubs را (در صورت وجود) زیپ کرده و آپلود کنید.

API جاج PHP


مهدی برنامه‌نویس خفنی است و پروژه‌های خفنی انجام می‌دهد. دوستان او از نحوه‌ی پیاده‌سازی سیستم داوری کوئرا در عجب‌اند، اما مهدی به آن‌ها می‌گوید پیاده‌سازی جاجی مثل کوئرا عین آب خوردنه! مهدی می‌خواهد این موضوع را به دوستانش اثبات کند، اما در حال حاضر مشغول انجام پروژه‌های خفن است و فرصت انجام این کار را ندارد.

از شما می‌خواهیم این موضوع را به دوستان مهدی اثبات کنید.

جزئیات پروژه🔗

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

ساختار فایل‌ها
judge-api
├── app
│   ├── Console
│   ├── Exceptions
│   ├── Http
│   ├── Jobs
│   │   └── JudgeSubmission.php
│   ├── Judge
│   │   ├── InputOutputJudge.php
│   │   ├── Judge.php
│   │   └── JudgeResult.php
│   ├── Models
│   │   ├── Submission.php
│   │   └── User.php
│   └── Providers
├── bootstrap
├── config
├── database
├── public
├── resources
├── routes
├── storage
├── tests
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
Plain text
راه‌اندازی پروژه

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

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.
  • برای اجرای تست‌های نمونه، می‌توانید از دستور php artisan test استفاده کنید.

همان‌طور که می‌دانید، سیستم داوری کوئرا (در حالت ورودی/خروجی) به این‌صورت است که یک رشته به‌عنوان stdin به یک برنامه داده می‌شود و در انتها، نتیجه‌ی اجرای برنامه دریافت می‌شود.

مدل‌ها🔗

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

کلاس App\Judge\JudgeResult🔗

از این کلاس برای نگه‌داری اطلاعات مربوط به داوری ارسال‌ها استفاده می‌شود.

extensionFromNameapp/Judge/JudgeResult.php
class JudgeResult
{
    const SUCCESS = 0;
    const TIME_LIMIT_EXCEEDED = 1;
    const RUNTIME_ERROR = 2;
    const SYNTAX_ERROR = 3;

    public function __construct(
        public string $stderr,
        public string $stdout,
        public int $status
    ) {}
}
PHP

اینترفیس App\Judge\Judge🔗

این اینترفیس شامل یک متد با نام run است که پارامترهای آن به‌صورت زیر هستند:

  • code: متن کد
  • timeLimit: محدودیت زمان برحسب میلی‌ثانیه
  • stdin: ورودی برنامه
extensionFromNameapp/Judge/Judge.php
interface Judge
{
    public function run(string $code, int $timeLimit, string $stdin = ''): JudgeResult;
}
PHP

کلاس App\Judge\InputOutputJudge🔗

این کلاس یک پیاده‌سازی از اینترفیس App\Judge\Judge است که باید کدهای PHP را اجرا کند و نتیجه را در قالب آبجکتی از کلاس App\Judge\JudgeResult برگرداند. مقدار پراپرتی‌های آبجکت خروجی باید مطابق توضیحات زیر باشد:

  • اگر کد سینتکس ارور داشته باشد، مقدار status باید برابر با JudgeResult::SYNTAX_ERROR باشد و مقدار stderr و stdout باید برابر با رشته‌ی خالی باشد.
  • اگر اجرای برنامه در زمان مشخص‌شده خاتمه یابد و داده‌ای توسط برنامه در stderr نوشته نشده باشد، مقدار status باید برابر با JudgeResult::SUCCESS باشد، مقدار stderr باید برابر با رشته‌ی خالی باشد و مقدار stdout باید برابر با خروجی برنامه باشد.
  • اگر اجرای برنامه در زمان مشخص‌شده خاتمه یابد و داده‌ای توسط برنامه در stderr نوشته شده باشد، مقدار status باید برابر با JudgeResult::RUNTIME_ERROR باشد، مقدار stderr باید برابر با محتویات stderr باشد و مقدار stdout باید برابر با رشته‌ی خالی باشد.
  • اگر اجرای برنامه در زمان مشخص‌شده خاتمه نیابد، فارغ از این که داده‌ای توسط در stdout یا stderr نوشته شده باشد، مقدار status باید برابر با JudgeResult::TIME_LIMIT_EXCEEDED باشد و مقدار stderr و stdout باید برابر با رشته‌ی خالی باشد.

جاب JudgeSubmission🔗

این جاب شناسه‌ی یک Submission را دریافت می‌کند. وظیفه‌ی این جاب، داوری یک Submission است. متد handle این جاب را طوری پیاده‌سازی کنید که ابتدا مقدار ستون status مربوط به Submission را به judging تغییر دهد، سپس داوری را با استفاده از کلاس InputOutputJudge انجام دهد و در نهایت، status، stderr و stdout را مقداردهی کند و تغییرات را در دیتابیس ذخیره کند.

احراز هویت🔗

پکیج laravel/sanctum در این پروژه نصب شده و از آن می‌توانید برای احراز هویت استفاده کنید. توکن‌های احراز هویت هنگام داوری توسط این پکیج تولید می‌شوند. هنگام ارسال درخواست‌ها، مقدار header برابر با یک توکن Bearer قرار داده می‌شود و مقدار هدر Accept برابر با application/json خواهد بود.

endpoint های API🔗

در این برنامه باید سه endpoiont به‌صورت زیر تعریف کنید. همه‌ی این endpoint باید نیازمند احراز هویت کاربر باشند. در غیر این‌صورت، کد پاسخ 401 باید برگردانده شود:

  • GET /api/submissions: با ارسال این درخواست، کاربر باید لیست ارسال‌هایش را در قالب یک آرایه ببیند (باید کالکشنی از Submissionها را به JSON تبدیل کرده و آن را برگردانید). کد پاسخ باید برابر با 200 باشد.
  • POST /api/submissions: با ارسال این درخواست، باید یک Submission به Submissionهای کاربر اضافه شود. تضمین می‌شود که مقادیر code، time_limit و stdin در بدنه‌ی درخواست موجود خواهند بود. همچنین، جاب JudgeSubmission مربوط به Submission ارسال‌شده باید به صفی با عنوان judge اضافه شود. کد پاسخ باید برابر با 201 باشد.
  • GET /api/submissions/{submission_id}: با ارسال این درخواست، کاربر باید اطلاعات Submission با شناسه‌ی submission_id را مشاهده کند (باید آبجکت Submission را به JSON تبدیل کرده و آن را برگردانید). اگر Submission وجود نداشته باشد یا متعلق به کاربر نباشد، کد پاسخ باید برابر با 404 باشد. در غیر این‌صورت، کد پاسخ باید برابر با 200 باشد.

نکات🔗

  • داوری در یک سیستم لینوکسی صورت می‌گیرد. بنابراین می‌توانید از امکانات خط فرمان آن استفاده کنید.
  • شما تنها مجاز به اعمال تغییرات در پوشه‌های app و routes هستید (می‌توانید فایل‌های جدیدی نیز در این پوشه‌ها ایجاد کنید).

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

پس از پیاده‌سازی موارد خواسته‌شده، پوشه‌های app و routes را زیپ کرده و آپلود کنید.