Thông tin | Giá trị |
---|---|
Server backend | nginx-1.20.1 |
API endpoint | https://vio.edu.vn/graphql |
Mô tả
Lấy thời gian trước khi vào thi để đề phòng thí sinh đổi giờ đồng hồ trên máy nhằm qua mặt lịch thi.
Action
POST
Request
{
"operationName": "getCurrentTimeServerQuery",
"variables": {},
"query": "
query getCurrentTimeServerQuery {
getCurrentTimeServer
}
"
}
Response
{
"data": {
// Server trả về UnixTimestamp
"getCurrentTimeServer": "<timestamp>"
}
}
Mô tả
Lấy thông tin trận đấu sắp tham gia. Có thêm key của trận để chống tham gia nhầm.
Action
POST
Request
{
"operationName": "getMatchDetail",
"variables": {
"matchKey": "<id>",
"browserSessionID": "<id>"
},
"query": "
query getMatchDetail($matchKey: String, $browserSessionID: String) {
getMatchDetail(matchKey: $matchKey, browserSessionID: $browserSessionID) {
listQuestionId
matchId
code
arenaType
isMath
matchType
timeType
matchName
startTime
battleEnd
endTime
numberCorrect
numberWrong
totalTimeThink
listPlayer
totalQuestion
listPlayerInformation
matchResult
resultSummary
__typename
}
"
}
Response
{
"data": {
"getMatchDetail": {
// Danh sách ID các câu hỏi trong bài
// Với vòng thi chính thức là 30 câu.
"listQuestionId": ["<id>", "..."],
// ID trận đấu
"matchId": "62500e8f603ac8028b28cdbb",
"code": 0,
// Thể loại
"arenaType": "ALL",
// Là môn toán
"isMath": true,
"matchType": "P",
"timeType": 2,
// Tên vòng thi
"matchName": "<tên có dấu>",
// Thời gian bắt đầu (UnixTimestamp)
"startTime": "<timestamp>",
// Trận đấu đã kết thúc chưa
"battleEnd": "<boolean>",
// Thời gian kết thúc (UnixTimestamp)
"endTime": "<timestamp>",
// Số câu đúng
"numberCorrect": 0,
// Số câu sai
"numberWrong": 0,
// Thời gian suy nghĩ tối đa
"totalTimeThink": 16,
// Danh sách người đang thi
"listPlayer": ["<username>"],
// Tổng câu hỏi
"totalQuestion": 30,
// Thông tin người dùng
"listPlayerInformation": {},
// Kết quả làm bài
"matchResult": {
"<username>": {}
},
// Tổng kết
"resultSummary": null,
// Thể loại
"__typename": "ArenaMatchDetailType"
}
}
}
Mô tả
Client của VioEdu (không hiểu tại sao) lại request từng câu hỏi một lên database mà không lấy hết luôn một thể (chắc là để destribute load). Client sẽ request lên database với những ID câu hỏi có trong trận đấu ở trên.
Hay ở chỗ là response không gửi kèm đáp án (khó exploit).
Action
POST
Request
{
"operationName": "getQuestionDetail",
"variables": {
"questionId": "5fd05434aede1b001c902fc2",
"matchId": "62500e8f603ac8028b28cdbb",
"isMath": true
},
"query": "
query getQuestionDetail($questionId: String, $matchId: String, $isMath: Boolean) {
getQuestionArenaById(questionId: $questionId, matchId: $matchId, isMath: $isMath) {
_id
content
childrenQuestions {
_id
content
q_index
q_type
isConsider
numberRow
numberColumn
styleAnswer
autoConvert
answerColumnNo
score
answers {
_id
id
text
subText
selected
answerType
partType
position
order
inputLength
__typename
}
__typename
}
q_index
q_type
isConsider
numberRow
numberColumn
totalPart
colorPart
styleAnswer
autoConvert
answerColumnNo
score
audio {
content
explanation
__typename
}
rightMatching {
_id
right_answer_id: id
textContent
__typename
}
leftMatching {
id
textContent
__typename
}
listSubAnswer {
_id
textContent
__typename
}
answers {
_id
id
text
subText
selected
answerType
partType
position
order
inputLength
listSubAnswer {
_id
textContent
__typename
}
__typename
}
textDropdownAnswers {
_id
list {
value: _id
label: text
__typename
}
order
__typename
}
__typename
}
}
"
}
Response
{
"data": {
"getQuestionArenaById": {
// ID câu hỏi (string)
"_id": "<qid>",
// Nội dung câu hỏi (string -> html + mathml)
"content": "<html>",
// Câu hỏi con (?)
"childrenQuestions": null,
"q_index": null,
"q_type": "3",
"isConsider": null,
"numberRow": null,
"numberColumn": null,
"totalPart": null,
"colorPart": 0,
"styleAnswer": 1,
"autoConvert": true,
"answerColumnNo": 0,
// Điểm câu hỏi
"score": "10",
// Âm thanh cho câu hỏi
"audio": null,
"rightMatching": null,
"leftMatching": null,
"listSubAnswer": null,
// Những đáp án để chọn (đây là điền vào ô trống)
"answers": [
{
"_id": "5fd15b70e103bb0b2e2ae938",
"id": "5fd15b70e103bb0b2e2ae938",
"text": null,
"subText": null,
"selected": null,
"answerType": null,
"partType": null,
"position": null,
"order": 1,
// Độ dài đáp án tối đa cho phép
"inputLength": 1,
"listSubAnswer": null,
// Luôn luôn là "AnswerInExam"
"__typename": "AnswerInExam"
}
],
// Answer cho bài chọn trắc nghiệm
"answers": [
{
"_id": "5fd0ea2c30fb0508d4d1efea",
"id": "5fd0ea2c30fb0508d4d1efea",
// Câu hỏi (string -> html + mathml)
"text": "<html>",
"subText": null,
"selected": null,
"answerType": null,
"partType": null,
"position": null,
"order": 0,
// Là null khi là câu hỏi trắc nghiệm
"inputLength": null,
"listSubAnswer": [],
"__typename": "AnswerInExam"
},
"..."
],
"textDropdownAnswers": [],
"__typename": "QuestionInExam"
}
}
}
Mô tả
Kiểm tra đáp án của người dùng sau khi làm bài.
Action
POST
Request
{
"operationName": "submitQuestion",
"variables": {
// Bê nguyên xi question object từ trên xuống luôn. Tốn băng thông +100
"question": "<QuestionObject>",
// ID phòng thi (string)
"arenaMathId": "<id>",
// Key phòng thi (string)
"arenaKey": "<key>",
// Thời gian suy nghĩ
"timeThinking": 16
},
"query": "
mutation submitQuestion($question: AnswerInExamResultSubmit, $arenaMathId: String, $arenaKey: String, $timeThinking: Int) {
checkAnswerQuestionArena(question: $question, arenaMathId: $arenaMathId, arenaKey: $arenaKey, timeThinking: $timeThinking) {
isCorrect
numberWrong
numberCorrect
timeThinkAll
__typename
}
}
"
}
Response
{
"data": {
"checkAnswerQuestionArena": {
// Đúng/sai (boolean)
"isCorrect": false,
// Số câu đã làm sai
"numberWrong": "1",
// Số câu đã làm đúng
"numberCorrect": "1",
// Thời gian đã trôi qua
"timeThinkAll": "71",
// Object type
"__typename": "checkAnswerQuestionArenaResult"
}
}
}