لینک‌های مفید برای شرکت در مسابقه:

در طول مسابقه، می‌توانید سوال‌های خود را از قسمت «سؤال بپرسید» مطرح کنید.

اسنپ‌باز


تیم فنی اسنپ قصد دارد تا سیستم جدیدی برای مدیریت دستاوردهای کاربران و دادن امتیاز به آن‌ها با بهره‌گیری از gamification پیاده‌سازی کند، اما به دلیل درخواست این تیم برای جذب نیروی فنی، آن‌ها این تسک را به برخی از افرادی سپرده‌اند که در مرحله‌ی اول مصاحبه‌ی اسنپ قبول شده‌اند. مهدی که سرش شلوغ است، اما می‌خواهد در اسنپ استخدام شود، از شما می‌خواهد تا این تسک را برایش انجام دهید. نسخه‌ی اولیه‌ی این سیستم قرار است یک API ساده باشد.

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

پروژه‌ی اولیه را از این لینک دانلود کنید. ساختار فایل‌های پروژه به‌صورت زیر است:

snapp_baz
├── achievements
│   └── achievements.go
├── db
│   └── connection.go
├── handlers
│   └── achievements.go
├── test
│   └── achievements_sample_test.go
├── go.mod
├── go.sum
└── main.go
Plain text

پایگاه داده🔗

در این پروژه از پایگاه داده‌ی PostgreSQL استفاده شده است. برنامه شامل جداول زیر است:

  1. کاربران (users):
نام ستون نوع تعریف ملاحضات
id BIGSERIAL شناسه‌ی کاربر PRIMARY KEY
name VARCHAR(255) نام
phone VARCHAR(255) شماره تلفن
  1. دستاوردها (achievements):
نام ستون نوع تعریف ملاحظات
id BIGSERIAL شناسه‌ی دستاورد PRIMARY KEY
title VARCHAR(255) عنوان دستاورد
  1. دستاوردهای کاربران (user_achievements):
نام ستون نوع تعریف
user_id BIGINT شناسه‌ی کاربر
achievement_id BIGINT شناسه‌ی دستاورد

دسترسی به پایگاه داده از طریق تابع db.GetConnection صورت می‌گیرد که به شکل singleton پیاده‌سازی شده است.

منطق کسب دستاوردها🔗

یک map[int](func(int) bool) به شکل singleton در برنامه تعریف شده که از طریق تابع achievements.GetMap قابل دسترسی است. این مپ، نگاشتی از شناسه‌ی دستاوردها به توابعی است که با دریافت شناسه‌ی یک کاربر، مشخص می‌کنند که آیا آن دستاورد توسط کاربر کسب شده است یا خیر.

روت‌ها🔗

نسخه‌ی اولیه‌ی این API شامل روت‌های زیر است:

  • /is_achieved: این روت به تابع handlers.IsAchieved مپ شده است که با دریافت یک user_id و یک achievement_id از query string، مشخص می‌کند که آیا دستاورد توسط کاربر ذکرشده کسب شده است یا خیر.
    • اگر پارامتر user_id مقداردهی نشده باشد، کد پاسخ باید 400 و بدنه‌ی پاسخ باید {"error": "no user id provided"} باشد.
    • اگر پارامتر user_id مقداردهی شده باشد، اما پارامتر achievement_id مقداردهی نشده باشد، کد پاسخ باید 400 و بدنه‌ی پاسخ باید {"error": "no achievement id provided"} باشد.
    • اگر مقدار پارامتر user_id عددی نباشد، کد پاسخ باید 400 و بدنه‌ی پاسخ باید {"error": "invalid user id"} باشد.
    • اگر مقدار پارامتر user_id عددی باشد، اما مقدار پارامتر achievement_id عددی نباشد، کد پاسخ باید 400 و بدنه‌ی پاسخ باید {"error": "invalid achievement id"} باشد.
    • اگر کاربری با شناسه‌ی user_id در جدول users موجود نباشد، کد پاسخ باید 404 و بدنه‌ی پاسخ باید {"error": "user not found"} باشد.
    • اگر کاربری با شناسه‌ی user_id در جدول users موجود باشد، اما دستاوردی با شناسه‌ی achievement_id در جدول achievements موجود نباشد، کد پاسخ باید 404 و بدنه‌ی پاسخ باید {"error": "achievement not found"} باشد.
    • اگر هیچ یک از شرایط فوق برقرار نباشد، کد پاسخ باید 200 و بدنه‌ی پاسخ باید {"is_achieved": true} یا {"is_achieved": false} باشد (بسته به این که کاربر دستاورد را کسب کرده است یا خیر).
  • /get_achievements: این روت به تابع handlers.GetAchievements مپ شده است که با دریافت یک user_id از query string، لیست دستاوردهای کاربر را برمی‌گرداند.
    • اگر پارامتر user_id مقداردهی نشده باشد، کد پاسخ باید 400 و بدنه‌ی پاسخ باید {"error": "no user id provided"} باشد.
    • اگر مقدار پارامتر user_id عددی نباشد، کد پاسخ باید 400 و بدنه‌ی پاسخ باید {"error": "invalid user id"} باشد.
    • اگر کاربری با شناسه‌ی user_id در جدول users موجود نباشد، کد پاسخ باید 404 و بدنه‌ی پاسخ باید {"error": "user not found"} باشد.
    • اگر هیچ یک از شرایط فوق برقرار نباشد، کد پاسخ باید 200 و بدنه‌ی پاسخ باید به فرم {"achievements": ["achievement 1 name", "achievement 2 name"]} باشد (نام دستاوردها باید به‌ترتیب صعودی شناسه‌شان باشد).
  • /refresh_achievements: این روت به تابع handlers.RefreshAchievements مپ شده است که با دریافت یک user_id از query_string، لیست دستاوردهای کاربر را به‌روز می‌کند. در واقع، دستاوردهایی که تاکنون توسط کاربر کسب نشده‌اند باید مجدداً بررسی شوند و در صورتی که دستاورد جدیدی کسب شده بود، در جدول user_achievements درج شود.
    • کد و بدنه‌ی پاسخ این روت باید مشابه روت /get_achievements باشد، با این تفاوت که دستاوردهای کسب‌نشده مجدداً بررسی می‌شوند.

توجه: مقدار هدر Content-Type در پاسخ همه‌ی درخواست‌ها باید برابر با application/json قرار داده شود.

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

پس از پیاده‌سازی برنامه، یک فایل زیپ آپلود کنید که وقتی آن را باز می‌کنیم، با ساختار زیر مواجه شویم:

snapp_baz
├── handlers
│   └── achievements.go
├── go.mod (Optional)
└── go.sum (Optional)
Plain text
ارسال پاسخ برای این سؤال
در حال حاضر شما دسترسی ندارید.