diff --git a/gui/index.html b/gui/index.html index 3c66c71..bbc0f4a 100644 --- a/gui/index.html +++ b/gui/index.html @@ -41,6 +41,10 @@

+
+
+ +

diff --git a/main.py b/main.py index 9bf4658..fc442c9 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,7 @@ import socket from settings import WAVE, END_TEST_PASSWORD, QUIZ_LENGTH, QUESTIONS_FILE, STUDENTS_FILE -app = FastAPI() +app = FastAPI(debug=True) origins = [ # CORS "*", @@ -25,9 +25,9 @@ app.add_middleware( # CORS # open files once and use variables after with open(QUESTIONS_FILE, "r", encoding="UTF-8") as f: - content = json.load(f) + questions_json = json.load(f) # TODO reassign questions id since mistakes are possible and checking is based on id - all_questions = content["questions"] + all_questions = questions_json["questions"] # if you want to use topics 1) filter all questions with topics 2) use topic questions to construct quiz_questions (when removing service keys from all_questions dict) # topics = ["теодолит"] # move topics to VARIABLES # topics_questions = [q for q in all_questions if q.get("topic") in topics] @@ -37,8 +37,8 @@ with open(QUESTIONS_FILE, "r", encoding="UTF-8") as f: quiz_questions = [{key: value for key, value in q.items() if key not in remove_keys} for q in typed_questions] # all_questions can be replaced with topic_questions with open(STUDENTS_FILE, "r", encoding="UTF-8") as f: - content = json.load(f) - students = content["students"] + students_json = json.load(f) + students = students_json["students"] # create folders if they don't exist Path("answers").mkdir(parents=True, exist_ok=True) @@ -62,6 +62,22 @@ def check_answers(student_answers: dict): return checked_answers +@app.get("/check_questions") +def check_questions(): + unique_ids = [] + errors = [] + for q in all_questions: + if q["id"] in unique_ids: + errors.append(f'"id": {q["id"]} — идентификатор не уникален') + else: + unique_ids.append(q["id"]) + + if q.get("options") and not (set(q["answer"]).issubset(set(q["options"])) or q["answer"] in q["options"]): + errors.append(f"В вопросе '{q['question']}' нет корректного варианта ответа") + return errors if errors else "Вопросы в порядке!" + + + @app.get("/hostip") def show_host_ip(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) diff --git a/questions_invalid.json b/questions_invalid.json new file mode 100644 index 0000000..c714d13 --- /dev/null +++ b/questions_invalid.json @@ -0,0 +1,69 @@ +{ + "version": 1, + "questions": [ + { + "id": 1, + "topic": "теодолит", + "author": "GT", + "question": "Что такое теодолит?", + "picture": "pictures/teodolit.png", + "options": [ + "Прибор для измерения земли", + "Прибор для измерения углов", + "Прибор для измерения расстояний", + "Прибор для измерения высот" + ], + "answer": "Прибор для измерения" + }, + { + "id": 1, + "topic": "геометрия", + "author": "GT", + "question": "Сумма углов выпуклого пятиугольника составляет?", + "answer": "540" + }, + { + "id": 3, + "topic": "нивелир", + "author": "GT", + "question": "Как называется прибор для измерения превышений?", + "answer": "нивелир" + }, + { + "id": 4, + "topic": "теодолит", + "author": "GT", + "question": "Сколько винтов у теодолита?", + "answer": "520" + }, + { + "id": 5, + "topic": "нивелир", + "author": "GT", + "question": "Что такое нивелир?", + "options": [ + "Прибор для измерения земли", + "Прибор для измерения углов", + "Прибор для измерения расстояний", + "Прибор для измерения высот" + ], + "answer": "Прибор для измерения углов" + }, + { + "id": 6, + "topic": "нивелир", + "author": "GT", + "question": "Что такое нивелир 2.0?", + "options": [ + "Прибор для измерения земли", + "Прибор для измерения углов", + "Прибор для измерения расстояний", + "Прибор для измерения высот" + ], + "answer": [ + "Прибор для измерения расстояний", + "Прибор для измерения углов" + ] + } + ] +} \ No newline at end of file diff --git a/questions_schema.json b/questions_schema.json new file mode 100644 index 0000000..62ba1c2 --- /dev/null +++ b/questions_schema.json @@ -0,0 +1,23 @@ +{ + "type": "object", + "properties": { + "version": {"type": "number"}, + "questions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": {"type": "number"}, + "topic": {"type": "string"}, + "author": {"type": "string"}, + "question": {"type": "string"}, + "picture": {"type": "string"}, + "options": {"type": "array"}, + "answer": {} + }, + "required": ["id", "question", "answer"] + } + } + }, + "required": ["questions"] +} \ No newline at end of file diff --git a/readme.md b/readme.md index dbcce3d..f209210 100644 --- a/readme.md +++ b/readme.md @@ -78,4 +78,19 @@ PolicyStore : ActiveStore ### Доступ к тесту -Для доступа к тесту с компьютера в локальной сети перейти по URL такого вида `ip-адрес:порт`, например, `123.32.43.54:8000` \ No newline at end of file +Для доступа к тесту с компьютера в локальной сети перейти по URL такого вида `ip-адрес:порт`, например, `123.32.43.54:8000` + + +## Возможные проблемы 🔧 + +### Не открывается страница в браузере + +В консоли, которая отвечает за запуск приложения, (окно, которое открылось после запуска файла `run.cmd`) должно быть выведено сообщение об ошибке + +В случае, если приложение не запустилось из-за ошибки синтаксиса в JSON-файлах `questions.json` или `students.json`, то в последней строке сообщения об ошибке будет указано, что именно в этих файлах не так, например, `json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 18 column 9 (char 523)` + +В случае, если приложение не запустилось из-за отсутсвия обязательных полей в JSON-файлах `questions.json` или `students.json`, то в последней строке сообщения об ошибке будет указано, что именно в этих файлах не так, например, `KeyError: 'answer'` + +### Проверка корректности вопросов + +Корректность вопросов на предмет 1) уникальности идентификаторов, 2) наличия правильного ответа среди вариантов ответа можно проверить \ No newline at end of file