sticky qrcode
This commit is contained in:
		
							parent
							
								
									b2121cc133
								
							
						
					
					
						commit
						f4883ee6ea
					
				| @ -278,6 +278,9 @@ const LessonDetail = () => { | ||||
|             borderRadius="xl"  | ||||
|             bg={colorMode === "light" ? "gray.50" : "gray.700"} | ||||
|             boxShadow="md" | ||||
|             position="sticky" | ||||
|             top="20px" | ||||
|             zIndex="2" | ||||
|           ><Box pb={3}> | ||||
|           {formatDate(accessCode?.body?.lesson?.date, t('journal.pl.lesson.dateFormat'))}{' '} | ||||
|           {t('journal.pl.common.marked')} -  | ||||
|  | ||||
| @ -1,21 +1,88 @@ | ||||
| const router = require('express').Router() | ||||
| const fs = require('node:fs') | ||||
| const path = require('node:path') | ||||
| const mockGenerator = require('./mock-generator') | ||||
| 
 | ||||
| // Функция для чтения JSON файла и случайной модификации содержимого
 | ||||
| function readAndModifyJson(filePath) { | ||||
|   try { | ||||
|     // Используем fs.readFileSync вместо require для избежания кэширования
 | ||||
|     const fullPath = path.resolve(__dirname, filePath); | ||||
|     const fileContent = fs.readFileSync(fullPath, 'utf8'); | ||||
|     const jsonContent = JSON.parse(fileContent); | ||||
|      | ||||
|     // Если это список учеников, немного перемешаем их
 | ||||
|     if (jsonContent.body && Array.isArray(jsonContent.body.students)) { | ||||
|       jsonContent.body.students.sort(() => 0.5 - Math.random()); | ||||
|     } | ||||
|      | ||||
|     // Если это список реакций, обновим время создания и слегка перемешаем
 | ||||
|     if (jsonContent.body && Array.isArray(jsonContent.body.reactions)) { | ||||
|       const now = Date.now(); | ||||
|       jsonContent.body.reactions.forEach((reaction, index) => { | ||||
|         // Интервал от 10 секунд до 2 минут назад
 | ||||
|         const randomTime = now - Math.floor(Math.random() * (120000 - 10000) + 10000); | ||||
|         reaction.created = new Date(randomTime).toISOString(); | ||||
|       }); | ||||
|        | ||||
|       // Сортируем реакции по времени создания (новые сверху)
 | ||||
|       jsonContent.body.reactions.sort((a, b) =>  | ||||
|         new Date(b.created) - new Date(a.created) | ||||
|       ); | ||||
|     } | ||||
|      | ||||
|     // Если это список уроков, обновим даты
 | ||||
|     if (jsonContent.body && Array.isArray(jsonContent.body) && jsonContent.body[0] && jsonContent.body[0].name) { | ||||
|       jsonContent.body.forEach((lesson) => { | ||||
|         // Случайная дата в пределах последних 3 месяцев
 | ||||
|         const randomDate = new Date(); | ||||
|         randomDate.setMonth(randomDate.getMonth() - Math.random() * 3); | ||||
|         lesson.date = randomDate.toISOString(); | ||||
|         lesson.created = new Date(randomDate.getTime() - 86400000).toISOString(); // Создан за день до даты
 | ||||
|       }); | ||||
|     } | ||||
|      | ||||
|     // Если это список курсов, добавим случайные данные
 | ||||
|     if (jsonContent.body && Array.isArray(jsonContent.body) && jsonContent.body[0] && jsonContent.body[0].id) { | ||||
|       jsonContent.body.forEach((course) => { | ||||
|         course.startDt = new Date(new Date().getTime() - Math.random() * 31536000000).toISOString(); // В пределах года
 | ||||
|         course.created = new Date(new Date(course.startDt).getTime() - 604800000).toISOString(); // Создан за неделю до начала
 | ||||
|       }); | ||||
|     } | ||||
|      | ||||
|     return jsonContent; | ||||
|   } catch (error) { | ||||
|     console.error(`Error reading/modifying file ${filePath}:`, error); | ||||
|     return { success: false, error: "Failed to read file" }; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Функция для чтения JSON без модификации
 | ||||
| function readJsonFile(filePath) { | ||||
|   try { | ||||
|     const fullPath = path.resolve(__dirname, filePath); | ||||
|     const fileContent = fs.readFileSync(fullPath, 'utf8'); | ||||
|     return JSON.parse(fileContent); | ||||
|   } catch (error) { | ||||
|     console.error(`Error reading file ${filePath}:`, error); | ||||
|     return { success: false, error: "Failed to read file" }; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const timer = | ||||
| (time = 1000) => | ||||
|   (_req, _res, next) => | ||||
|     setTimeout(next, time) | ||||
| 
 | ||||
| router.use(timer()) | ||||
| // Небольшая задержка для имитации реальной сети
 | ||||
| router.use(timer(100)); | ||||
| 
 | ||||
| const config = { | ||||
|   examCreated: false | ||||
| } | ||||
| 
 | ||||
| router.get('/course/list', (req, res) => { | ||||
|   res.send(require('../mocks/courses/list/success.json')) | ||||
|   const modifiedData = readAndModifyJson('../mocks/courses/list/success.json'); | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.get('/course/:id', (req, res) => { | ||||
| @ -23,18 +90,30 @@ router.get('/course/:id', (req, res) => { | ||||
|     return res.status(400).send({ success: false, error: 'Invalid course id' }) | ||||
|    | ||||
|   if (config.examCreated) { | ||||
|     config.examCreated = false | ||||
|     return res.send(require('../mocks/courses/by-id/with-exam.json')) | ||||
|     config.examCreated = false; | ||||
|     const modifiedData = readAndModifyJson('../mocks/courses/by-id/with-exam.json'); | ||||
|     return res.send(modifiedData); | ||||
|   } | ||||
|   res.send(require('../mocks/courses/by-id/success.json')) | ||||
|    | ||||
|   const modifiedData = readAndModifyJson('../mocks/courses/by-id/success.json'); | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.get('/course/students/:courseId', (req, res) => { | ||||
|   res.send(require('../mocks/courses/all-students/success.json')) | ||||
|   const modifiedData = readAndModifyJson('../mocks/courses/all-students/success.json'); | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.post('/course', (req, res) => { | ||||
|   res.send(require('../mocks/courses/create/success.json')) | ||||
|   const baseData = readJsonFile('../mocks/courses/create/success.json'); | ||||
|    | ||||
|   // Добавляем данные из запроса
 | ||||
|   if (baseData.body) { | ||||
|     baseData.body.name = req.body.name || baseData.body.name; | ||||
|     baseData.body.created = new Date().toISOString(); | ||||
|   } | ||||
|    | ||||
|   res.send(baseData); | ||||
| }) | ||||
| 
 | ||||
| router.post('/course/toggle-exam-with-jury/:id', (req, res) => { | ||||
| @ -43,35 +122,62 @@ router.post('/course/toggle-exam-with-jury/:id', (req, res) => { | ||||
| }) | ||||
| 
 | ||||
| router.get('/lesson/list/:courseId', (req, res) => { | ||||
|   res.send(require('../mocks/lessons/list/success.json')) | ||||
|   const modifiedData = readAndModifyJson('../mocks/lessons/list/success.json'); | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
| // https://platform.bro-js.ru/jrnl-bh/api/lesson/67cf0c9f2f4241c6fc29f464/ai/generate-lessons
 | ||||
| router.get('/lesson/:courseId/ai/generate-lessons', timer(3000), (req, res) => { | ||||
|   res.send(require('../mocks/lessons/generate/success.json')) | ||||
|   const modifiedData = readAndModifyJson('../mocks/lessons/generate/success.json'); | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.post('/lesson', (req, res) => { | ||||
|   res.send(require('../mocks/lessons/create/success.json')) | ||||
|   const baseData = readJsonFile('../mocks/lessons/create/success.json'); | ||||
|    | ||||
|   // Добавляем данные из запроса
 | ||||
|   if (baseData.body) { | ||||
|     baseData.body.name = req.body.name || baseData.body.name; | ||||
|     baseData.body.date = req.body.date || new Date().toISOString(); | ||||
|     baseData.body.created = new Date().toISOString(); | ||||
|   } | ||||
|    | ||||
|   res.send(baseData); | ||||
| }) | ||||
| 
 | ||||
| router.post('/lesson/access-code', (req, res) => { | ||||
|   // Generate random students and reactions dynamically
 | ||||
|   const dynamicData = mockGenerator.generateDynamicAccessCodeResponse(); | ||||
|   res.send(dynamicData); | ||||
|   const modifiedData = readAndModifyJson('../mocks/lessons/access-code/create/success.json'); | ||||
|    | ||||
|   // Обновляем дату истечения через час от текущего времени
 | ||||
|   if (modifiedData.body) { | ||||
|     modifiedData.body.expires = new Date(Date.now() + 60 * 60 * 1000).toISOString(); | ||||
|     modifiedData.body.created = new Date().toISOString(); | ||||
|   } | ||||
|    | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.get('/lesson/access-code/:accessCode', (req, res) => { | ||||
|   // Generate dynamic data for the access code lookup
 | ||||
|   const dynamicData = mockGenerator.generateDynamicAccessLookupResponse(req.params.accessCode); | ||||
|   res.send(dynamicData); | ||||
|   const modifiedData = readAndModifyJson('../mocks/lessons/access-code/get/success.json'); | ||||
|    | ||||
|   // Обновляем дату истечения через час от текущего времени
 | ||||
|   if (modifiedData.body && modifiedData.body.accessCode) { | ||||
|     modifiedData.body.accessCode.expires = new Date(Date.now() + 60 * 60 * 1000).toISOString(); | ||||
|     modifiedData.body.accessCode.created = new Date().toISOString(); | ||||
|   } | ||||
|    | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.get('/lesson/:lessonId', (req, res) => { | ||||
|   // Generate dynamic lesson data using the same helpers
 | ||||
|   const dynamicData = mockGenerator.generateDynamicLessonResponse(req.params.lessonId); | ||||
|   res.send(dynamicData); | ||||
|   const modifiedData = readAndModifyJson('../mocks/lessons/byid/success.json'); | ||||
|    | ||||
|   // Обновляем даты
 | ||||
|   if (modifiedData.body) { | ||||
|     modifiedData.body.date = new Date().toISOString(); | ||||
|     modifiedData.body.created = new Date(Date.now() - 86400000).toISOString(); // Создан день назад
 | ||||
|   } | ||||
|    | ||||
|   res.send(modifiedData); | ||||
| }) | ||||
| 
 | ||||
| router.delete('/lesson/:lessonId', (req, res) => { | ||||
| @ -103,270 +209,3 @@ router.post('/lesson/reaction/:lessonId', (req, res) => { | ||||
| }); | ||||
| 
 | ||||
| module.exports = router | ||||
| 
 | ||||
| // Database of potential students
 | ||||
| const potentialStudents = [ | ||||
|   { | ||||
|     "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|     "email_verified": true, | ||||
|     "name": "Мария Капитанова", | ||||
|     "preferred_username": "maryaKapitan@gmail.com", | ||||
|     "given_name": "Мария", | ||||
|     "family_name": "Капитанова", | ||||
|     "email": "maryaKapitan@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJgIjjOFD2YUSyRF5kH4jaysE6X5p-kq0Cg0CFncfMi=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|     "email_verified": true, | ||||
|     "name": "Евгения Жужова", | ||||
|     "preferred_username": "zhuzhova@gmail.com", | ||||
|     "given_name": "Евгения", | ||||
|     "family_name": "Жужова", | ||||
|     "email": "zhuzhova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJUtJBAVBm642AxoGpMDDMV8CPu3MEoLjU3hmO7oisG=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "a723b8c2-f1d7-4620-9c35-1d48c821afb7", | ||||
|     "email_verified": true, | ||||
|     "name": "Иван Петров", | ||||
|     "preferred_username": "ivan.petrov@gmail.com", | ||||
|     "given_name": "Иван", | ||||
|     "family_name": "Петров", | ||||
|     "email": "ivan.petrov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJKHmMLFXY1s0Lkj_KKf9ZEsHl-rW6FnDs4vPHUl2aF=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "e4f9d328-7b2e-49c1-b5e8-12f78c54a63d", | ||||
|     "email_verified": true, | ||||
|     "name": "Алексей Смирнов", | ||||
|     "preferred_username": "alexey.smirnov@gmail.com", | ||||
|     "given_name": "Алексей", | ||||
|     "family_name": "Смирнов", | ||||
|     "email": "alexey.smirnov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocK9Nfj_jT4DLjG5hVQWS2bz8_QTZ3cHVJ6K8mD8aqWr=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "b9d7e1f5-6a3c-47d0-9bce-3c54e28a0ef2", | ||||
|     "email_verified": true, | ||||
|     "name": "Ольга Иванова", | ||||
|     "preferred_username": "olga.ivanova@gmail.com", | ||||
|     "given_name": "Ольга", | ||||
|     "family_name": "Иванова", | ||||
|     "email": "olga.ivanova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocI48DY7C2ZXbMvHrEjKmY6w9JdF5PLKwEDgTR9x1jY2=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "c5e8d4f3-2b1a-4c9d-8e7f-6a5b4c3d2e1f", | ||||
|     "email_verified": true, | ||||
|     "name": "Дмитрий Кузнецов", | ||||
|     "preferred_username": "dmitry.kuznetsov@gmail.com", | ||||
|     "given_name": "Дмитрий", | ||||
|     "family_name": "Кузнецов", | ||||
|     "email": "dmitry.kuznetsov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocLqZD7KjXy3B1P2VsRn6Z9tY8XMhCJ6F5gK7sD1qB3t=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "d6f9e8d7-3c2b-4a1d-9e8f-7a6b5c4d3e2f", | ||||
|     "email_verified": true, | ||||
|     "name": "Анна Соколова", | ||||
|     "preferred_username": "anna.sokolova@gmail.com", | ||||
|     "given_name": "Анна", | ||||
|     "family_name": "Соколова", | ||||
|     "email": "anna.sokolova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocK3dN5mYwLjE1qFvX9pZ8rY1hJ5L2mN3oP6gR7tUb4s=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "e7f8g9h0-4d3c-2b1a-0f9e-8d7c6b5a4e3d", | ||||
|     "email_verified": true, | ||||
|     "name": "Сергей Новиков", | ||||
|     "preferred_username": "sergey.novikov@gmail.com", | ||||
|     "given_name": "Сергей", | ||||
|     "family_name": "Новиков", | ||||
|     "email": "sergey.novikov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocI7P2dF3vQ5wR9jH6tN8bZ1cM4kD6yL2jN5oR8tYb5r=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "f8g9h0i1-5e4d-3c2b-1a0f-9e8d7c6b5a4e", | ||||
|     "email_verified": true, | ||||
|     "name": "Екатерина Морозова", | ||||
|     "preferred_username": "ekaterina.morozova@gmail.com", | ||||
|     "given_name": "Екатерина", | ||||
|     "family_name": "Морозова", | ||||
|     "email": "ekaterina.morozova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJ6N5oR7sD8tUb4rY1hJ5L2mN3oP6gR7tUb4s9pZ8=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "g9h0i1j2-6f5e-4d3c-2b1a-0f9e8d7c6b5a", | ||||
|     "email_verified": true, | ||||
|     "name": "Андрей Волков", | ||||
|     "preferred_username": "andrey.volkov@gmail.com", | ||||
|     "given_name": "Андрей", | ||||
|     "family_name": "Волков", | ||||
|     "email": "andrey.volkov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocK4e3d2c1b0a9f8e7d6c5b4a3e2d1c0b9a8f7e6d5=s96-c" | ||||
|   } | ||||
| ]; | ||||
| 
 | ||||
| // Available reaction types
 | ||||
| const reactionTypes = ['thumbs_up', 'heart', 'laugh', 'wow', 'clap']; | ||||
| 
 | ||||
| // Function to generate a random integer between min and max (inclusive)
 | ||||
| function getRandomInt(min, max) { | ||||
|   return Math.floor(Math.random() * (max - min + 1)) + min; | ||||
| } | ||||
| 
 | ||||
| // Function to generate a random subset of students
 | ||||
| function getRandomStudents() { | ||||
|   const totalStudents = potentialStudents.length; | ||||
|   const count = getRandomInt(1, Math.min(8, totalStudents)); | ||||
|    | ||||
|   // Shuffle array and take a subset
 | ||||
|   const shuffled = [...potentialStudents].sort(() => 0.5 - Math.random()); | ||||
|   return shuffled.slice(0, count); | ||||
| } | ||||
| 
 | ||||
| // Function to generate a random reaction
 | ||||
| function generateReaction(studentSub, index) { | ||||
|   const reactionType = reactionTypes[getRandomInt(0, reactionTypes.length - 1)]; | ||||
|    | ||||
|   return { | ||||
|     "_id": `r-${Date.now()}-${index}`, | ||||
|     "sub": studentSub, | ||||
|     "reaction": reactionType, | ||||
|     "created": new Date().toISOString() | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| // Function to generate random reactions for each student
 | ||||
| function generateReactions(students) { | ||||
|   const reactions = []; | ||||
|   let reactionIndex = 0; | ||||
|    | ||||
|   students.forEach(student => { | ||||
|     // Small chance (20%) of a "reaction burst" - multiple reactions in rapid succession
 | ||||
|     const hasBurst = Math.random() < 0.2; | ||||
|      | ||||
|     if (hasBurst) { | ||||
|       // Generate a burst of 2-5 rapid reactions
 | ||||
|       const burstCount = getRandomInt(2, 5); | ||||
|       const now = Date.now(); | ||||
|        | ||||
|       for (let i = 0; i < burstCount; i++) { | ||||
|         // Reactions spaced 0.5-2 seconds apart
 | ||||
|         const timeOffset = i * getRandomInt(500, 2000); | ||||
|         const reactionTime = new Date(now - timeOffset); | ||||
|          | ||||
|         reactions.push({ | ||||
|           "_id": `r-burst-${now}-${i}-${reactionIndex++}`, | ||||
|           "sub": student.sub, | ||||
|           "reaction": reactionTypes[getRandomInt(0, reactionTypes.length - 1)], | ||||
|           "created": reactionTime.toISOString() | ||||
|         }); | ||||
|       } | ||||
|     } else { | ||||
|       // Each student may have 0-3 random reactions
 | ||||
|       const reactionCount = getRandomInt(0, 3); | ||||
|        | ||||
|       for (let i = 0; i < reactionCount; i++) { | ||||
|         // Space out regular reactions by 5-30 seconds
 | ||||
|         const timeOffset = getRandomInt(5000, 30000); | ||||
|         const reactionTime = new Date(Date.now() - timeOffset); | ||||
|          | ||||
|         reactions.push({ | ||||
|           "_id": `r-${Date.now()}-${reactionIndex++}`, | ||||
|           "sub": student.sub, | ||||
|           "reaction": reactionTypes[getRandomInt(0, reactionTypes.length - 1)], | ||||
|           "created": reactionTime.toISOString() | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|    | ||||
|   // Sort reactions by creation time (newest first)
 | ||||
|   return reactions.sort((a, b) => new Date(b.created) - new Date(a.created)); | ||||
| } | ||||
| 
 | ||||
| // Function to generate the entire dynamic response
 | ||||
| function generateDynamicAccessCodeResponse() { | ||||
|   // Base template from the static file
 | ||||
|   const baseTemplate = { | ||||
|     "success": true, | ||||
|     "body": { | ||||
|       "expires": new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hour from now
 | ||||
|       "lesson": { | ||||
|         "_id": "65df996c584b172772d69706", | ||||
|         "name": "ВВОДНАЯ ПО JS.ПРИМЕНЕНИЕ И СПОСОБЫ ПОДКЛЮЧЕНИЯ НА СТРАНИЦЕ. LET, CONST. БАЗОВЫЕ ТИПЫ ДАННЫХ, ПРИВЕДЕНИЕ ТИПОВ. ПЕРЕМЕННЫЕ, ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ", | ||||
|         "date": new Date().toISOString(), | ||||
|         "created": new Date().toISOString(), | ||||
|         "__v": 0 | ||||
|       }, | ||||
|       "_id": `access-${Date.now()}`, | ||||
|       "created": new Date().toISOString(), | ||||
|       "__v": 0 | ||||
|     } | ||||
|   }; | ||||
|    | ||||
|   // Generate random students
 | ||||
|   const students = getRandomStudents(); | ||||
|   baseTemplate.body.lesson.students = students; | ||||
|    | ||||
|   // Generate random reactions for those students
 | ||||
|   baseTemplate.body.lesson.reactions = generateReactions(students); | ||||
|    | ||||
|   return baseTemplate; | ||||
| } | ||||
| 
 | ||||
| // Function to generate a dynamic lesson response
 | ||||
| function generateDynamicLessonResponse(lessonId) { | ||||
|   // Base template for lesson response
 | ||||
|   const baseTemplate = { | ||||
|     "success": true, | ||||
|     "body": { | ||||
|       "_id": lessonId || "65df996c584b172772d69706", | ||||
|       "name": "ВВОДНАЯ ПО JS.ПРИМЕНЕНИЕ И СПОСОБЫ ПОДКЛЮЧЕНИЯ НА СТРАНИЦЕ. LET, CONST. БАЗОВЫЕ ТИПЫ ДАННЫХ, ПРИВЕДЕНИЕ ТИПОВ. ПЕРЕМЕННЫЕ, ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ", | ||||
|       "date": new Date().toISOString(), | ||||
|       "created": new Date().toISOString(), | ||||
|       "__v": 0 | ||||
|     } | ||||
|   }; | ||||
|    | ||||
|   // Generate random students
 | ||||
|   const students = getRandomStudents(); | ||||
|   baseTemplate.body.students = students; | ||||
|    | ||||
|   // Generate random reactions for those students
 | ||||
|   baseTemplate.body.reactions = generateReactions(students); | ||||
|    | ||||
|   return baseTemplate; | ||||
| } | ||||
| 
 | ||||
| // Function to generate a dynamic access code lookup response
 | ||||
| function generateDynamicAccessLookupResponse(accessCode) { | ||||
|   // Generate a lesson with students and reactions
 | ||||
|   const lessonData = generateDynamicLessonResponse(); | ||||
|    | ||||
|   // Create a mock user
 | ||||
|   const mockUser = { | ||||
|     sub: `user-${Date.now()}`, | ||||
|     email_verified: true, | ||||
|     name: "Текущий Пользователь", | ||||
|     preferred_username: "current.user@example.com", | ||||
|     email: "current.user@example.com" | ||||
|   }; | ||||
|    | ||||
|   // Combine into the expected format
 | ||||
|   return { | ||||
|     "success": true, | ||||
|     "body": { | ||||
|       "user": mockUser, | ||||
|       "accessCode": { | ||||
|         "expires": new Date(Date.now() + 60 * 60 * 1000).toISOString(), | ||||
|         "lesson": lessonData.body, | ||||
|         "_id": accessCode || `access-${Date.now()}`, | ||||
|         "created": new Date().toISOString(), | ||||
|         "__v": 0 | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @ -1,264 +0,0 @@ | ||||
| // Database of potential students
 | ||||
| const potentialStudents = [ | ||||
|   { | ||||
|     "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|     "email_verified": true, | ||||
|     "name": "Мария Капитанова", | ||||
|     "preferred_username": "maryaKapitan@gmail.com", | ||||
|     "given_name": "Мария", | ||||
|     "family_name": "Капитанова", | ||||
|     "email": "maryaKapitan@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJgIjjOFD2YUSyRF5kH4jaysE6X5p-kq0Cg0CFncfMi=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|     "email_verified": true, | ||||
|     "name": "Евгения Жужова", | ||||
|     "preferred_username": "zhuzhova@gmail.com", | ||||
|     "given_name": "Евгения", | ||||
|     "family_name": "Жужова", | ||||
|     "email": "zhuzhova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJUtJBAVBm642AxoGpMDDMV8CPu3MEoLjU3hmO7oisG=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "a723b8c2-f1d7-4620-9c35-1d48c821afb7", | ||||
|     "email_verified": true, | ||||
|     "name": "Иван Петров", | ||||
|     "preferred_username": "ivan.petrov@gmail.com", | ||||
|     "given_name": "Иван", | ||||
|     "family_name": "Петров", | ||||
|     "email": "ivan.petrov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJKHmMLFXY1s0Lkj_KKf9ZEsHl-rW6FnDs4vPHUl2aF=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "e4f9d328-7b2e-49c1-b5e8-12f78c54a63d", | ||||
|     "email_verified": true, | ||||
|     "name": "Алексей Смирнов", | ||||
|     "preferred_username": "alexey.smirnov@gmail.com", | ||||
|     "given_name": "Алексей", | ||||
|     "family_name": "Смирнов", | ||||
|     "email": "alexey.smirnov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocK9Nfj_jT4DLjG5hVQWS2bz8_QTZ3cHVJ6K8mD8aqWr=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "b9d7e1f5-6a3c-47d0-9bce-3c54e28a0ef2", | ||||
|     "email_verified": true, | ||||
|     "name": "Ольга Иванова", | ||||
|     "preferred_username": "olga.ivanova@gmail.com", | ||||
|     "given_name": "Ольга", | ||||
|     "family_name": "Иванова", | ||||
|     "email": "olga.ivanova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocI48DY7C2ZXbMvHrEjKmY6w9JdF5PLKwEDgTR9x1jY2=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "c5e8d4f3-2b1a-4c9d-8e7f-6a5b4c3d2e1f", | ||||
|     "email_verified": true, | ||||
|     "name": "Дмитрий Кузнецов", | ||||
|     "preferred_username": "dmitry.kuznetsov@gmail.com", | ||||
|     "given_name": "Дмитрий", | ||||
|     "family_name": "Кузнецов", | ||||
|     "email": "dmitry.kuznetsov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocLqZD7KjXy3B1P2VsRn6Z9tY8XMhCJ6F5gK7sD1qB3t=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "d6f9e8d7-3c2b-4a1d-9e8f-7a6b5c4d3e2f", | ||||
|     "email_verified": true, | ||||
|     "name": "Анна Соколова", | ||||
|     "preferred_username": "anna.sokolova@gmail.com", | ||||
|     "given_name": "Анна", | ||||
|     "family_name": "Соколова", | ||||
|     "email": "anna.sokolova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocK3dN5mYwLjE1qFvX9pZ8rY1hJ5L2mN3oP6gR7tUb4s=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "e7f8g9h0-4d3c-2b1a-0f9e-8d7c6b5a4e3d", | ||||
|     "email_verified": true, | ||||
|     "name": "Сергей Новиков", | ||||
|     "preferred_username": "sergey.novikov@gmail.com", | ||||
|     "given_name": "Сергей", | ||||
|     "family_name": "Новиков", | ||||
|     "email": "sergey.novikov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocI7P2dF3vQ5wR9jH6tN8bZ1cM4kD6yL2jN5oR8tYb5r=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "f8g9h0i1-5e4d-3c2b-1a0f-9e8d7c6b5a4e", | ||||
|     "email_verified": true, | ||||
|     "name": "Екатерина Морозова", | ||||
|     "preferred_username": "ekaterina.morozova@gmail.com", | ||||
|     "given_name": "Екатерина", | ||||
|     "family_name": "Морозова", | ||||
|     "email": "ekaterina.morozova@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocJ6N5oR7sD8tUb4rY1hJ5L2mN3oP6gR7tUb4s9pZ8=s96-c" | ||||
|   }, | ||||
|   { | ||||
|     "sub": "g9h0i1j2-6f5e-4d3c-2b1a-0f9e8d7c6b5a", | ||||
|     "email_verified": true, | ||||
|     "name": "Андрей Волков", | ||||
|     "preferred_username": "andrey.volkov@gmail.com", | ||||
|     "given_name": "Андрей", | ||||
|     "family_name": "Волков", | ||||
|     "email": "andrey.volkov@gmail.com", | ||||
|     "picture": "https://lh3.googleusercontent.com/a/ACg8ocK4e3d2c1b0a9f8e7d6c5b4a3e2d1c0b9a8f7e6d5=s96-c" | ||||
|   } | ||||
| ]; | ||||
| 
 | ||||
| // Available reaction types
 | ||||
| const reactionTypes = ['thumbs_up', 'heart', 'laugh', 'wow', 'clap']; | ||||
| 
 | ||||
| // Function to generate a random integer between min and max (inclusive)
 | ||||
| function getRandomInt(min, max) { | ||||
|   return Math.floor(Math.random() * (max - min + 1)) + min; | ||||
| } | ||||
| 
 | ||||
| // Function to generate a random subset of students
 | ||||
| function getRandomStudents() { | ||||
|   const totalStudents = potentialStudents.length; | ||||
|   const count = getRandomInt(1, Math.min(8, totalStudents)); | ||||
|    | ||||
|   // Shuffle array and take a subset
 | ||||
|   const shuffled = [...potentialStudents].sort(() => 0.5 - Math.random()); | ||||
|   return shuffled.slice(0, count); | ||||
| } | ||||
| 
 | ||||
| // Function to generate random reactions for each student
 | ||||
| function generateReactions(students) { | ||||
|   const reactions = []; | ||||
|   let reactionIndex = 0; | ||||
|    | ||||
|   students.forEach(student => { | ||||
|     // Small chance (20%) of a "reaction burst" - multiple reactions in rapid succession
 | ||||
|     const hasBurst = Math.random() < 0.2; | ||||
|      | ||||
|     if (hasBurst) { | ||||
|       // Generate a burst of 2-5 rapid reactions
 | ||||
|       const burstCount = getRandomInt(2, 5); | ||||
|       const now = Date.now(); | ||||
|        | ||||
|       for (let i = 0; i < burstCount; i++) { | ||||
|         // Reactions spaced 0.5-2 seconds apart
 | ||||
|         const timeOffset = i * getRandomInt(500, 2000); | ||||
|         const reactionTime = new Date(now - timeOffset); | ||||
|          | ||||
|         reactions.push({ | ||||
|           "_id": `r-burst-${now}-${i}-${reactionIndex++}`, | ||||
|           "sub": student.sub, | ||||
|           "reaction": reactionTypes[getRandomInt(0, reactionTypes.length - 1)], | ||||
|           "created": reactionTime.toISOString() | ||||
|         }); | ||||
|       } | ||||
|     } else { | ||||
|       // Each student may have 0-3 random reactions
 | ||||
|       const reactionCount = getRandomInt(0, 3); | ||||
|        | ||||
|       for (let i = 0; i < reactionCount; i++) { | ||||
|         // Space out regular reactions by 5-30 seconds
 | ||||
|         const timeOffset = getRandomInt(5000, 30000); | ||||
|         const reactionTime = new Date(Date.now() - timeOffset); | ||||
|          | ||||
|         reactions.push({ | ||||
|           "_id": `r-${Date.now()}-${reactionIndex++}`, | ||||
|           "sub": student.sub, | ||||
|           "reaction": reactionTypes[getRandomInt(0, reactionTypes.length - 1)], | ||||
|           "created": reactionTime.toISOString() | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|    | ||||
|   // Sort reactions by creation time (newest first)
 | ||||
|   return reactions.sort((a, b) => new Date(b.created) - new Date(a.created)); | ||||
| } | ||||
| 
 | ||||
| // Function to generate the entire dynamic response
 | ||||
| function generateDynamicAccessCodeResponse() { | ||||
|   // Base template from the static file
 | ||||
|   const baseTemplate = { | ||||
|     "success": true, | ||||
|     "body": { | ||||
|       "expires": new Date(Date.now() + 60 * 60 * 1000).toISOString(), // 1 hour from now
 | ||||
|       "lesson": { | ||||
|         "_id": "65df996c584b172772d69706", | ||||
|         "name": "ВВОДНАЯ ПО JS.ПРИМЕНЕНИЕ И СПОСОБЫ ПОДКЛЮЧЕНИЯ НА СТРАНИЦЕ. LET, CONST. БАЗОВЫЕ ТИПЫ ДАННЫХ, ПРИВЕДЕНИЕ ТИПОВ. ПЕРЕМЕННЫЕ, ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ", | ||||
|         "date": new Date().toISOString(), | ||||
|         "created": new Date().toISOString(), | ||||
|         "__v": 0 | ||||
|       }, | ||||
|       "_id": `access-${Date.now()}`, | ||||
|       "created": new Date().toISOString(), | ||||
|       "__v": 0 | ||||
|     } | ||||
|   }; | ||||
|    | ||||
|   // Generate random students
 | ||||
|   const students = getRandomStudents(); | ||||
|   baseTemplate.body.lesson.students = students; | ||||
|    | ||||
|   // Generate random reactions for those students
 | ||||
|   baseTemplate.body.lesson.reactions = generateReactions(students); | ||||
|    | ||||
|   return baseTemplate; | ||||
| } | ||||
| 
 | ||||
| // Function to generate a dynamic lesson response
 | ||||
| function generateDynamicLessonResponse(lessonId) { | ||||
|   // Base template for lesson response
 | ||||
|   const baseTemplate = { | ||||
|     "success": true, | ||||
|     "body": { | ||||
|       "_id": lessonId || "65df996c584b172772d69706", | ||||
|       "name": "ВВОДНАЯ ПО JS.ПРИМЕНЕНИЕ И СПОСОБЫ ПОДКЛЮЧЕНИЯ НА СТРАНИЦЕ. LET, CONST. БАЗОВЫЕ ТИПЫ ДАННЫХ, ПРИВЕДЕНИЕ ТИПОВ. ПЕРЕМЕННЫЕ, ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ", | ||||
|       "date": new Date().toISOString(), | ||||
|       "created": new Date().toISOString(), | ||||
|       "__v": 0 | ||||
|     } | ||||
|   }; | ||||
|    | ||||
|   // Generate random students
 | ||||
|   const students = getRandomStudents(); | ||||
|   baseTemplate.body.students = students; | ||||
|    | ||||
|   // Generate random reactions for those students
 | ||||
|   baseTemplate.body.reactions = generateReactions(students); | ||||
|    | ||||
|   return baseTemplate; | ||||
| } | ||||
| 
 | ||||
| // Function to generate a dynamic access code lookup response
 | ||||
| function generateDynamicAccessLookupResponse(accessCode) { | ||||
|   // Generate a lesson with students and reactions
 | ||||
|   const lessonData = generateDynamicLessonResponse(); | ||||
|    | ||||
|   // Create a mock user
 | ||||
|   const mockUser = { | ||||
|     sub: `user-${Date.now()}`, | ||||
|     email_verified: true, | ||||
|     name: "Текущий Пользователь", | ||||
|     preferred_username: "current.user@example.com", | ||||
|     email: "current.user@example.com" | ||||
|   }; | ||||
|    | ||||
|   // Combine into the expected format
 | ||||
|   return { | ||||
|     "success": true, | ||||
|     "body": { | ||||
|       "user": mockUser, | ||||
|       "accessCode": { | ||||
|         "expires": new Date(Date.now() + 60 * 60 * 1000).toISOString(), | ||||
|         "lesson": lessonData.body, | ||||
|         "_id": accessCode || `access-${Date.now()}`, | ||||
|         "created": new Date().toISOString(), | ||||
|         "__v": 0 | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| // Export all the necessary functions
 | ||||
| module.exports = { | ||||
|   getRandomStudents, | ||||
|   generateReactions, | ||||
|   generateDynamicAccessCodeResponse, | ||||
|   generateDynamicLessonResponse, | ||||
|   generateDynamicAccessLookupResponse, | ||||
|   reactionTypes | ||||
| };  | ||||
| @ -1,100 +0,0 @@ | ||||
| { | ||||
|   "success": true, | ||||
|   "body": { | ||||
|       "expires": "2024-03-01T07:52:16.374Z", | ||||
|       "lesson": { | ||||
|           "_id": "65df996c584b172772d69706", | ||||
|           "name": "ВВОДНАЯ ПО JS.ПРИМЕНЕНИЕ И СПОСОБЫ ПОДКЛЮЧЕНИЯ НА СТРАНИЦЕ. LET, CONST. БАЗОВЫЕ ТИПЫ ДАННЫХ, ПРИВЕДЕНИЕ ТИПОВ. ПЕРЕМЕННЫЕ, ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ", | ||||
|           "students": [ | ||||
|               { | ||||
|                 "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|                 "email_verified": true, | ||||
|                 "name": "Мария Капитанова", | ||||
|                 "preferred_username": "maryaKapitan@gmail.com", | ||||
|                 "given_name": "Мария", | ||||
|                 "family_name": "Капитанова", | ||||
|                 "email": "maryaKapitan@gmail.com", | ||||
|                 "picture": "https://lh3.googleusercontent.com/a/ACg8ocJgIjjOFD2YUSyRF5kH4jaysE6X5p-kq0Cg0CFncfMi=s96-c" | ||||
|             }, | ||||
|             { | ||||
|                 "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|                 "email_verified": true, | ||||
|                 "name": "Евгения Жужова", | ||||
|                 "preferred_username": "zhuzhova@gmail.com", | ||||
|                 "given_name": "Евгения", | ||||
|                 "family_name": "Жужова", | ||||
|                 "email": "zhuzhova@gmail.com", | ||||
|                 "picture": "https://lh3.googleusercontent.com/a/ACg8ocJUtJBAVBm642AxoGpMDDMV8CPu3MEoLjU3hmO7oisG=s96-c" | ||||
|             } | ||||
|           ], | ||||
|           "reactions": [ | ||||
|             { | ||||
|               "_id": "r1-rapid-001", | ||||
|               "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|               "reaction": "thumbs_up", | ||||
|               "created": "2024-03-08T10:00:00.000Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r1-rapid-002", | ||||
|               "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|               "reaction": "heart", | ||||
|               "created": "2024-03-08T10:00:01.500Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r1-rapid-003", | ||||
|               "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|               "reaction": "laugh", | ||||
|               "created": "2024-03-08T10:00:02.800Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r1-rapid-004", | ||||
|               "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|               "reaction": "wow", | ||||
|               "created": "2024-03-08T10:00:04.200Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r1-rapid-005", | ||||
|               "sub": "fcde3f22-d9ba-412a-a572-c59e515a290f", | ||||
|               "reaction": "clap", | ||||
|               "created": "2024-03-08T10:00:05.500Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r2-rapid-001", | ||||
|               "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|               "reaction": "thumbs_up", | ||||
|               "created": "2024-03-08T10:01:00.000Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r2-rapid-002", | ||||
|               "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|               "reaction": "heart", | ||||
|               "created": "2024-03-08T10:01:01.200Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r2-rapid-003", | ||||
|               "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|               "reaction": "wow", | ||||
|               "created": "2024-03-08T10:01:02.300Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r2-rapid-004", | ||||
|               "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|               "reaction": "laugh", | ||||
|               "created": "2024-03-08T10:01:04.100Z" | ||||
|             }, | ||||
|             { | ||||
|               "_id": "r2-rapid-005", | ||||
|               "sub": "8555885b-715c-4dee-a7c5-9563a6a05211", | ||||
|               "reaction": "clap", | ||||
|               "created": "2024-03-08T10:01:05.300Z" | ||||
|             } | ||||
|           ], | ||||
|           "date": "2024-02-28T20:37:00.057Z", | ||||
|           "created": "2024-02-28T20:37:00.057Z", | ||||
|           "__v": 0 | ||||
|       }, | ||||
|       "_id": "65e18926584b172772d69722", | ||||
|       "created": "2024-03-01T07:52:06.375Z", | ||||
|       "__v": 0 | ||||
|   } | ||||
| }  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user