188 lines
5.6 KiB
JavaScript
188 lines
5.6 KiB
JavaScript
const fs = require('fs')
|
|
const path = require('path')
|
|
const router = require('express').Router()
|
|
|
|
const timer = (time = 100) => (req, res, next) => setTimeout(next, time)
|
|
|
|
const dataDir = path.join(__dirname, 'data')
|
|
|
|
const readJson = (fileName) => {
|
|
const filePath = path.join(dataDir, fileName)
|
|
const content = fs.readFileSync(filePath, 'utf-8')
|
|
return JSON.parse(content)
|
|
}
|
|
|
|
const sendNotFound = (res, message) => {
|
|
res.status(404).json({ error: { message }, data: null })
|
|
}
|
|
|
|
router.use(timer())
|
|
router.use((req, res, next) => {
|
|
res.type('application/json')
|
|
next()
|
|
})
|
|
|
|
// Challenge API endpoints
|
|
router.post('/challenge/auth', (req, res) => {
|
|
const { nickname, workplaceNumber } = req.body
|
|
const response = readJson('auth.json')
|
|
|
|
// Логируем для отладки
|
|
console.log('Auth request:', { nickname, workplaceNumber })
|
|
|
|
res.json(response)
|
|
})
|
|
|
|
router.get('/challenge/chains', (req, res) => {
|
|
res.json(readJson('chains.json'))
|
|
})
|
|
|
|
router.get('/challenge/chain/:id', (req, res) => {
|
|
const data = readJson('chains.json')
|
|
const chains = data.body || data
|
|
const chain = chains.find((item) => item.id === req.params.id || item._id === req.params.id)
|
|
if (!chain) {
|
|
return sendNotFound(res, `Цепочка ${req.params.id} не найдена`)
|
|
}
|
|
return res.json({ success: true, body: chain })
|
|
})
|
|
|
|
router.get('/challenge/task/:id', (req, res) => {
|
|
const data = readJson('chains.json')
|
|
const chains = data.body || data
|
|
const task = chains
|
|
.flatMap((chain) => chain.tasks || [])
|
|
.find((item) => item.id === req.params.id || item._id === req.params.id)
|
|
|
|
if (!task) {
|
|
return sendNotFound(res, `Задание ${req.params.id} не найдено`)
|
|
}
|
|
|
|
return res.json({ success: true, body: task })
|
|
})
|
|
|
|
router.post('/challenge/submit', (req, res) => {
|
|
const response = readJson('submit.json')
|
|
const queueId = response.body?.queueId
|
|
|
|
if (queueId) {
|
|
queueBehaviors[queueId] = queueBehaviors[queueId] ?? { nextFailure: false, attemptNumber: 0 }
|
|
queueStates[queueId] = {
|
|
position: 3,
|
|
initialPosition: 3,
|
|
pollCount: 0,
|
|
startTime: Date.now(),
|
|
}
|
|
}
|
|
|
|
res.json(response)
|
|
})
|
|
|
|
// Храним состояние очереди для каждого queueId
|
|
const queueStates = {}
|
|
const queueBehaviors = {}
|
|
|
|
router.get('/challenge/check-status/:queueId', (req, res) => {
|
|
const queueId = req.params.queueId
|
|
|
|
// Инициализируем состояние очереди, если его нет
|
|
if (!queueStates[queueId]) {
|
|
queueStates[queueId] = {
|
|
position: 3,
|
|
initialPosition: 3,
|
|
pollCount: 0,
|
|
startTime: Date.now()
|
|
}
|
|
}
|
|
|
|
const state = queueStates[queueId]
|
|
state.pollCount++
|
|
|
|
// Симулируем движение в очереди
|
|
// Каждый запрос уменьшаем позицию (быстрее)
|
|
if (state.pollCount >= 1 && state.position > 0) {
|
|
state.position--
|
|
state.pollCount = 0
|
|
}
|
|
|
|
// Если позиция 0, переходим к проверке
|
|
if (state.position === 0 && state.pollCount >= 1) {
|
|
const behavior = queueBehaviors[queueId] ?? { nextFailure: false, attemptNumber: 0 }
|
|
const attemptNumber = behavior.attemptNumber + 1
|
|
behavior.attemptNumber = attemptNumber
|
|
const shouldFail = behavior.nextFailure
|
|
behavior.nextFailure = !shouldFail
|
|
|
|
const baseSubmission = {
|
|
_id: `submission-${queueId}-${attemptNumber}`,
|
|
id: `submission-${queueId}-${attemptNumber}`,
|
|
user: 'user-frontend-001',
|
|
task: 'task-html-intro',
|
|
result: '<html><head></head><body><h1>Hello</h1></body></html>',
|
|
queueId,
|
|
submittedAt: new Date(state.startTime).toISOString(),
|
|
checkedAt: new Date().toISOString(),
|
|
attemptNumber,
|
|
}
|
|
|
|
const submission = shouldFail
|
|
? {
|
|
...baseSubmission,
|
|
status: 'needs_revision',
|
|
feedback: 'Добавьте описание внутри <section> и поясните, зачем нужен заголовок.',
|
|
}
|
|
: {
|
|
...baseSubmission,
|
|
status: 'accepted',
|
|
feedback: 'Отличная работа! Теперь можно двигаться дальше.',
|
|
}
|
|
|
|
delete queueStates[queueId]
|
|
|
|
return res.json({
|
|
success: true,
|
|
body: {
|
|
status: 'completed',
|
|
position: 0,
|
|
submission,
|
|
},
|
|
})
|
|
}
|
|
|
|
// Возвращаем текущее состояние очереди с начальной позицией для расчёта прогресса
|
|
const status = state.position > 0
|
|
? { status: 'waiting', position: state.position, initialPosition: state.initialPosition }
|
|
: { status: 'in_progress', position: 0, initialPosition: state.initialPosition }
|
|
|
|
return res.json({ success: true, body: status })
|
|
})
|
|
|
|
router.get('/challenge/user/:userId/stats', (req, res) => {
|
|
const data = readJson('user-stats.json')
|
|
const statsMap = data.body || data
|
|
const stats = statsMap[req.params.userId]
|
|
|
|
if (!stats) {
|
|
return sendNotFound(res, `Статистика пользователя ${req.params.userId} не найдена`)
|
|
}
|
|
|
|
return res.json({ success: true, body: stats })
|
|
})
|
|
|
|
router.get('/challenge/user/:userId/submissions', (req, res) => {
|
|
const data = readJson('user-submissions.json')
|
|
const submissionsMap = data.body || data
|
|
const submissions = submissionsMap[req.params.userId] || []
|
|
return res.json({ success: true, body: submissions })
|
|
})
|
|
|
|
router.get('/challenge/stats', (req, res) => {
|
|
res.json(readJson('system-stats.json'))
|
|
})
|
|
|
|
router.get('/challenge/submissions', (req, res) => {
|
|
res.json(readJson('submissions.json'))
|
|
})
|
|
|
|
module.exports = router
|