Merge remote-tracking branch 'origin/codex/add-python-programming-mission-module'

This commit is contained in:
danilgryaznev 2025-09-29 12:23:40 -06:00
commit dccc6ab20b
3 changed files with 110 additions and 52 deletions

View File

@ -307,23 +307,9 @@ def list_missions(
dto.is_completed = False dto.is_completed = False
dto.is_available = is_available dto.is_available = is_available
dto.locked_reasons = reasons dto.locked_reasons = reasons
dto.has_coding_challenges = bool(mission.coding_challenges)
total_python = ( dto.coding_challenge_count = len(mission.coding_challenges)
db.query(PythonChallenge) dto.completed_coding_challenges = coding_progress.get(mission.id, 0)
.filter(PythonChallenge.mission_id == mission.id)
.count()
)
if total_python:
progress = (
db.query(PythonUserProgress)
.filter(
PythonUserProgress.user_id == current_user.id,
PythonUserProgress.mission_id == mission.id,
)
.first()
)
dto.python_challenges_total = total_python
dto.python_completed_challenges = progress.current_order if progress else 0
response.append(dto) response.append(dto)
return response return response
@ -395,28 +381,9 @@ def get_mission(
updated_at=mission.updated_at, updated_at=mission.updated_at,
) )
data.requires_documents = mission.id in REQUIRED_DOCUMENT_MISSIONS data.requires_documents = mission.id in REQUIRED_DOCUMENT_MISSIONS
data.has_coding_challenges = bool(mission.coding_challenges)
total_python = ( data.coding_challenge_count = len(mission.coding_challenges)
db.query(PythonChallenge) data.completed_coding_challenges = coding_progress.get(mission.id, 0)
.filter(PythonChallenge.mission_id == mission.id)
.count()
)
if total_python:
progress = (
db.query(PythonUserProgress)
.filter(
PythonUserProgress.user_id == current_user.id,
PythonUserProgress.mission_id == mission.id,
)
.first()
)
data.python_challenges_total = total_python
data.python_completed_challenges = progress.current_order if progress else 0
if progress and progress.current_order >= total_python:
data.is_completed = True
data.is_available = False
data.locked_reasons = ["Миссия уже завершена"]
if mission.id in completed_missions: if mission.id in completed_missions:
data.is_completed = True data.is_completed = True
data.is_available = False data.is_available = False

View File

@ -24,10 +24,9 @@ class MissionBase(BaseModel):
locked_reasons: list[str] = Field(default_factory=list) locked_reasons: list[str] = Field(default_factory=list)
is_completed: bool = False is_completed: bool = False
requires_documents: bool = False requires_documents: bool = False
python_challenges_total: Optional[int] = None has_coding_challenges: bool = False
python_completed_challenges: Optional[int] = None coding_challenge_count: int = 0
requires_documents: bool = False completed_coding_challenges: int = 0
is_completed: bool = False
class Config: class Config:
from_attributes = True from_attributes = True

View File

@ -164,8 +164,8 @@ def seed() -> None:
category="quest", category="quest",
) )
python_branch = Branch( python_branch = Branch(
title="Галактокод", title="Основы Python",
description="Практика языка Python по мотивам путеводителя.", description="Мини-курс из 10 задач для проверки синтаксиса и базовой логики.",
category="training", category="training",
) )
session.add_all([branch, python_branch]) session.add_all([branch, python_branch])
@ -206,16 +206,21 @@ def seed() -> None:
difficulty=MissionDifficulty.HARD, difficulty=MissionDifficulty.HARD,
minimum_rank_id=ranks[1].id, minimum_rank_id=ranks[1].id,
) )
mission_python = Mission( mission_python_basics = Mission(
title="Основы Python", title="Основные знания Python",
description="Решите последовательность задач, чтобы доказать владение базовыми конструкциями языка.", description="Решите 10 небольших задач и докажите, что уверенно чувствуете себя в языке программирования.",
xp_reward=250, xp_reward=250,
mana_reward=120, mana_reward=120,
difficulty=MissionDifficulty.MEDIUM, difficulty=MissionDifficulty.MEDIUM,
minimum_rank_id=ranks[0].id, minimum_rank_id=ranks[0].id,
artifact_id=artifact_by_name["Путеводитель по Галактике"].id,
) )
session.add_all([mission_documents, mission_resume, mission_interview, mission_onboarding, mission_python]) session.add_all([
mission_documents,
mission_resume,
mission_interview,
mission_onboarding,
mission_python_basics,
])
session.flush() session.flush()
session.add_all( session.add_all(
@ -241,7 +246,7 @@ def seed() -> None:
level_delta=1, level_delta=1,
), ),
MissionCompetencyReward( MissionCompetencyReward(
mission_id=mission_python.id, mission_id=mission_python_basics.id,
competency_id=competencies[2].id, competency_id=competencies[2].id,
level_delta=1, level_delta=1,
), ),
@ -254,7 +259,94 @@ def seed() -> None:
BranchMission(branch_id=branch.id, mission_id=mission_resume.id, order=2), BranchMission(branch_id=branch.id, mission_id=mission_resume.id, order=2),
BranchMission(branch_id=branch.id, mission_id=mission_interview.id, order=3), BranchMission(branch_id=branch.id, mission_id=mission_interview.id, order=3),
BranchMission(branch_id=branch.id, mission_id=mission_onboarding.id, order=4), BranchMission(branch_id=branch.id, mission_id=mission_onboarding.id, order=4),
BranchMission(branch_id=python_branch.id, mission_id=mission_python.id, order=1), BranchMission(branch_id=python_branch.id, mission_id=mission_python_basics.id, order=1),
]
)
python_challenges_specs = [
{
"order": 1,
"title": "Приветствие пилота",
"prompt": "Выведите в консоль точную фразу «Привет, Python!». Без дополнительных символов или пробелов.",
"starter_code": "# Напишите одну строку с функцией print\n",
"expected_output": "Привет, Python!",
},
{
"order": 2,
"title": "Сложение топлива",
"prompt": "Создайте переменные a и b, найдите их сумму и выведите результат в формате «Сумма: 12».",
"starter_code": "a = 7\nb = 5\n# Напечатайте строку в формате: Сумма: 12\n",
"expected_output": "Сумма: 12",
},
{
"order": 3,
"title": "Площадь отсека",
"prompt": "Перемножьте длину и ширину отсека и выведите строку «Площадь: 24».",
"starter_code": "length = 8\nwidth = 3\n# Вычислите площадь и выведите результат\n",
"expected_output": "Площадь: 24",
},
{
"order": 4,
"title": "Обратный отсчёт",
"prompt": "С помощью цикла for выведите числа от 1 до 5, каждое на новой строке.",
"starter_code": "for number in range(1, 6):\n # Напечатайте текущее число\n pass\n",
"expected_output": "1\n2\n3\n4\n5",
},
{
"order": 5,
"title": "Квадраты сигналов",
"prompt": "Создайте список квадратов чисел от 1 до 5 и выведите строку «Список квадратов: [1, 4, 9, 16, 25]».",
"starter_code": "levels = [1, 2, 3, 4, 5]\n# Соберите список квадратов и напечатайте его\n",
"expected_output": "Список квадратов: [1, 4, 9, 16, 25]",
},
{
"order": 6,
"title": "Длина сообщения",
"prompt": "Определите длину строки message и выведите её как «Количество символов: 25».",
"starter_code": "message = \"Пангалактический экспресс\"\n# Посчитайте длину и выведите результат\n",
"expected_output": "Количество символов: 25",
},
{
"order": 7,
"title": "Запасы склада",
"prompt": "Пройдитесь по словарю storage и выведите информацию в формате «мануал: 3» и «датчик: 5».",
"starter_code": "storage = {\"мануал\": 3, \"датчик\": 5}\n# Выведите данные из словаря построчно\n",
"expected_output": "мануал: 3\nдатчик: 5",
},
{
"order": 8,
"title": "Проверка чётности",
"prompt": "Для чисел 2 и 7 напечатайте на отдельных строках True, если число чётное, иначе False.",
"starter_code": "numbers = [2, 7]\nfor number in numbers:\n # Напечатайте True или False в зависимости от чётности\n pass\n",
"expected_output": "True\nFalse",
},
{
"order": 9,
"title": "Сумма диапазона",
"prompt": "Посчитайте сумму чисел от 1 до 10 и выведите строку «Сумма от 1 до 10: 55».",
"starter_code": "total = 0\nfor number in range(1, 11):\n # Добавляйте число к сумме\n pass\n# После цикла выведите итог\n",
"expected_output": "Сумма от 1 до 10: 55",
},
{
"order": 10,
"title": "Факториал 5",
"prompt": "Вычислите факториал числа 5 и выведите строку «Факториал 5: 120».",
"starter_code": "result = 1\nfor number in range(1, 6):\n # Умножайте result на текущее число\n pass\n# Выведите итоговое значение\n",
"expected_output": "Факториал 5: 120",
},
]
session.add_all(
[
CodingChallenge(
mission_id=mission_python_basics.id,
order=spec["order"],
title=spec["title"],
prompt=spec["prompt"],
starter_code=spec["starter_code"],
expected_output=spec["expected_output"],
)
for spec in python_challenges_specs
] ]
) )