UGATU SDO ANSWERS SCRIPT

Показ верных ответов на сайте СДО УГАТУ!

// ==UserScript==
// @name         UGATU SDO ANSWERS SCRIPT
// @namespace    https://t.me/+AzlTc2COncJmYzAy
// @version      2.2.3
// @description  Показ верных ответов на сайте СДО УГАТУ!
// @author       GuFFy_OwO
// @match        https://sdo.uust.ru/*
// @icon         https://sdo.uust.ru/pluginfile.php/1/theme_opentechnology/settings_setugatu_header_logoimage/1664187092/Z3_222.png
// @grant        GM_xmlhttpRequest
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ([
/* 0 */
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const getAnswersData_module_1 = __importDefault(__webpack_require__(1));
const getQuizPercent_module_1 = __importDefault(__webpack_require__(6));
const postQuizzesData_module_1 = __importDefault(__webpack_require__(7));
const responseFormPatch_module_1 = __importDefault(__webpack_require__(8));
const getCmId_util_1 = __importDefault(__webpack_require__(9));
const cmId = (0, getCmId_util_1.default)();
const responseForm = document.getElementById('responseform');
if (cmId && responseForm) {
    (0, responseFormPatch_module_1.default)(cmId, responseForm);
    (0, getAnswersData_module_1.default)(cmId, responseForm);
}
const quizAttemptSummaryTable = document.querySelector('.generaltable.quizattemptsummary');
if (cmId && quizAttemptSummaryTable) {
    (0, getQuizPercent_module_1.default)(cmId, quizAttemptSummaryTable);
    (0, postQuizzesData_module_1.default)();
}


/***/ }),
/* 1 */
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const getQuestionsData_util_1 = __importDefault(__webpack_require__(2));
const createAnswerTable_module_1 = __importDefault(__webpack_require__(5));
exports["default"] = (cmId, responseForm) => {
    const questionsData = (0, getQuestionsData_util_1.default)(responseForm);
    if (!questionsData)
        return;
    questionsData.forEach((questionData) => {
        GM_xmlhttpRequest({
            method: 'POST',
            url: 'https://vernibabki.ru/usatu-sdo-answers/api/v1/getAnswerData',
            data: JSON.stringify({
                cmId,
                question: questionData.question,
                answersOptions: questionData.answersOptions,
            }),
            headers: {
                'Content-Type': 'application/json',
            },
            onload: function (response) {
                if (response) {
                    if (response.status === 200) {
                        (0, createAnswerTable_module_1.default)(JSON.parse(response.responseText), questionData.questionParams);
                    }
                    console.log('Get Answer response =>', response);
                }
            },
        });
    });
};


/***/ }),
/* 2 */
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const innerHtmlParser_util_1 = __importDefault(__webpack_require__(3));
const questionDataParsers_util_1 = __webpack_require__(4);
exports["default"] = (responseForm) => {
    return Array.from(responseForm.querySelectorAll('div > *[id^="question"]')).reduce((questionsData, questionBlockElement) => {
        var _a;
        const question = (_a = questionBlockElement.querySelector('.qtext')) === null || _a === void 0 ? void 0 : _a.innerHTML;
        if (!question)
            return questionsData;
        const choiceQuestion = (0, questionDataParsers_util_1.choiceQuestionParser)(questionBlockElement);
        const textQuestion = (0, questionDataParsers_util_1.textQuestionParser)(questionBlockElement);
        const matchQuestion = (0, questionDataParsers_util_1.matchQuestionParser)(questionBlockElement);
        const essayQuestion = (0, questionDataParsers_util_1.essayQuestionParser)(questionBlockElement);
        questionsData.push({
            question: (0, innerHtmlParser_util_1.default)(question),
            questionParams: {
                questionId: questionBlockElement.id.split('-')[1],
                questionNumber: questionBlockElement.id.split('-')[2],
            },
            answersOptions: [
                ...choiceQuestion.answersOptions,
                ...textQuestion.answersOptions,
                ...matchQuestion.answersOptions,
                ...essayQuestion.answersOptions,
            ].sort(),
            answers: [
                ...choiceQuestion.answers,
                ...textQuestion.answers,
                ...matchQuestion.answers,
                ...essayQuestion.answers,
            ].sort(),
        });
        return questionsData;
    }, []);
};


/***/ }),
/* 3 */
/***/ ((__unused_webpack_module, exports) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports["default"] = (innerHTML) => {
    return replaceHtmlEntities(innerHTML
        .replace(/<span class="answernumber">\w. <\/span>/g, '')
        .replace(/<img[^>]+src="([^">]+)".*>/g, '$1')
        .replace(/<\/?[^>]+(>|$)/g, ' ')
        .replace(/\/question\/questiontext\/\d+\/\d+\//g, '/question/questiontext/QUESTIONID/QUESTIONNUMBER/')
        .replace(/\/question\/answer\/\d+\/\d+\//g, '/question/answer/QUESTIONID/QUESTIONNUMBER/'))
        .replace(/\s\s+/g, ' ')
        .trim();
};
const translate_re = /&(nbsp|amp|quot|lt|gt);/g;
const translate = {
    nbsp: ' ',
    amp: '&',
    quot: '"',
    lt: '<',
    gt: '>',
};
const replaceHtmlEntities = (string) => {
    return string.replace(translate_re, (match, entity) => {
        return translate[entity];
    });
};


/***/ }),
/* 4 */
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.essayQuestionParser = exports.matchQuestionParser = exports.textQuestionParser = exports.choiceQuestionParser = void 0;
const innerHtmlParser_util_1 = __importDefault(__webpack_require__(3));
const arrayToString = (array) => {
    return '[' + array.map((el) => `"${(0, innerHtmlParser_util_1.default)(el.innerHTML)}"`).join(', ') + ']';
};
const choiceQuestionParser = (questionBlockElement) => {
    return Array.from(questionBlockElement.querySelectorAll('.answer input[type="checkbox"], .answer input[type="radio"]')).reduce((result = { answersOptions: [], answers: [] }, item) => {
        if (!item.nextElementSibling)
            return result;
        const innerHTML = (0, innerHtmlParser_util_1.default)(item.nextElementSibling.innerHTML);
        result.answersOptions.push(innerHTML);
        if (item.checked)
            result.answers.push(innerHTML);
        return result;
    }, { answersOptions: [], answers: [] });
};
exports.choiceQuestionParser = choiceQuestionParser;
const textQuestionParser = (questionBlockElement) => {
    return Array.from(questionBlockElement.querySelectorAll('.answer input[type="text"]')).reduce((result = { answersOptions: [], answers: [] }, item) => {
        result.answers.push((0, innerHtmlParser_util_1.default)(item.value));
        return result;
    }, { answersOptions: [], answers: [] });
};
exports.textQuestionParser = textQuestionParser;
const matchQuestionParser = (questionBlockElement) => {
    return Array.from(questionBlockElement.querySelectorAll('.answer select')).reduce((result = { answersOptions: [], answers: [] }, item) => {
        if (!item.parentElement || !item.parentElement.previousElementSibling)
            return result;
        result.answersOptions.push(`${(0, innerHtmlParser_util_1.default)(item.parentElement.previousElementSibling.innerHTML)}: ${arrayToString(Array.from(item.options))}`);
        result.answers.push(`${(0, innerHtmlParser_util_1.default)(item.parentElement.previousElementSibling.innerHTML)}: ${(0, innerHtmlParser_util_1.default)(item.options[item.selectedIndex].innerHTML)}`);
        return result;
    }, { answersOptions: [], answers: [] });
};
exports.matchQuestionParser = matchQuestionParser;
const essayQuestionParser = (questionBlockElement) => {
    return Array.from(questionBlockElement.querySelectorAll('.answer textarea')).reduce((result = { answersOptions: [], answers: [] }, item) => {
        result.answers.push((0, innerHtmlParser_util_1.default)(item.value));
        return result;
    }, { answersOptions: [], answers: [] });
};
exports.essayQuestionParser = essayQuestionParser;


/***/ }),
/* 5 */
/***/ ((__unused_webpack_module, exports) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports["default"] = (answersData, { questionId, questionNumber }) => {
    const table = document.createElement('table');
    table.classList.add('styled-table');
    const thead = document.createElement('thead');
    const tr = document.createElement('tr');
    const thPercent = document.createElement('th');
    thPercent.textContent = 'Процент';
    thPercent.style.color = 'white';
    const thUsage = document.createElement('th');
    thUsage.textContent = 'Количество использований';
    thUsage.style.color = 'white';
    const thLastUsage = document.createElement('th');
    thLastUsage.textContent = 'Дата последнего использования';
    thLastUsage.style.color = 'white';
    const thAnswer = document.createElement('th');
    thAnswer.textContent = 'Ответ';
    thAnswer.style.color = 'white';
    tr.appendChild(thPercent);
    tr.appendChild(thUsage);
    tr.appendChild(thLastUsage);
    tr.appendChild(thAnswer);
    thead.appendChild(tr);
    table.appendChild(thead);
    const tbody = document.createElement('tbody');
    answersData.forEach((answerData) => {
        const tr = document.createElement('tr');
        const tdPercent = document.createElement('td');
        tdPercent.textContent = answerData.percent ? answerData.percent.toString() : 'Не известен';
        const tdUsage = document.createElement('td');
        tdUsage.textContent = answerData.count.toString();
        const tdLastUsage = document.createElement('td');
        tdLastUsage.textContent = new Date(answerData.updatedAt).toLocaleString('en-GB');
        const tdAnswers = document.createElement('td');
        tdAnswers.textContent = JSON.stringify(answerData._id.map((answer) => answer.replace('QUESTIONID', questionId).replace('QUESTIONNUMBER', questionNumber)));
        tr.appendChild(tdPercent);
        tr.appendChild(tdUsage);
        tr.appendChild(tdLastUsage);
        tr.appendChild(tdAnswers);
        tbody.appendChild(tr);
    });
    table.appendChild(tbody);
    table.style.borderCollapse = 'collapse';
    table.style.margin = '25px auto';
    table.style.fontSize = '0.9em';
    table.style.fontFamily = 'sans-serif';
    table.style.minWidth = '400px';
    table.style.boxShadow = '0 0 20px rgba(0, 0, 0, 0.15)';
    thead.style.backgroundColor = '#009879';
    thead.style.color = '#009879';
    thead.style.textAlign = 'left';
    const ths = tr.querySelectorAll('th');
    const tds = tr.querySelectorAll('td');
    ths.forEach((th) => {
        th.style.padding = '12px 15px';
    });
    tds.forEach((td) => {
        td.style.padding = '12px 15px';
    });
    const trs = tbody.querySelectorAll('tr');
    trs.forEach((tr, index) => {
        if (index % 2 === 0) {
            tr.style.backgroundColor = '#f3f3f3';
        }
        tr.style.borderBottom = '1px solid #dddddd';
    });
    const lastRow = document.querySelector('tr:last-of-type');
    if (lastRow) {
        lastRow.style.borderBottom = '2px solid #009879';
    }
    const activeRow = document.querySelector('.active-row');
    if (activeRow) {
        activeRow.style.fontWeight = 'bold';
        activeRow.style.color = '#009879';
    }
    document.body.appendChild(table);
};


/***/ }),
/* 6 */
/***/ ((__unused_webpack_module, exports) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports["default"] = (cmId, quizAttemptSummaryTable) => {
    var _a;
    if (!localStorage.quizzesData)
        localStorage.quizzesData = JSON.stringify({});
    const quizzesData = JSON.parse(localStorage.quizzesData);
    const rateColumn = quizAttemptSummaryTable.querySelectorAll('td.cell.c2');
    const score = rateColumn[rateColumn.length - 1].innerHTML.replace(',', '.');
    const rateHeader = (_a = quizAttemptSummaryTable.querySelector('th.header.c2')) === null || _a === void 0 ? void 0 : _a.textContent;
    if (!rateHeader)
        return "Can't find rate header";
    const maxScoreRegexp = rateHeader.match(/\d+,\d+/);
    if (!maxScoreRegexp)
        return "Can't find max score";
    const maxScore = maxScoreRegexp[0].replace(',', '.');
    const percent = (parseFloat(score) / parseFloat(maxScore)) * 100;
    if (!Object.keys(quizzesData).includes(cmId)) {
        return "Can't find quiz data, maybe you haven't passed the quiz";
    }
    else if (score === '') {
        return "Can't find score, quiz is not finished";
    }
    else if (score === 'Еще не оценено') {
        quizzesData[cmId].percent = undefined;
    }
    else if (!isNaN(percent)) {
        quizzesData[cmId].percent = percent;
    }
    else {
        return "Can't parse score, table is broken";
    }
    localStorage.quizzesData = JSON.stringify(quizzesData);
};


/***/ }),
/* 7 */
/***/ ((__unused_webpack_module, exports) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports["default"] = () => {
    if (!localStorage.quizzesData)
        localStorage.quizzesData = JSON.stringify({});
    const quizzesData = JSON.parse(localStorage.quizzesData);
    Object.keys(quizzesData).forEach((cmId) => {
        if (quizzesData[cmId].percent === null)
            return `Quiz with cmId ${cmId} is not finished`;
        GM_xmlhttpRequest({
            method: 'POST',
            url: 'https://vernibabki.ru/usatu-sdo-answers/api/v1/postQuizData',
            data: JSON.stringify({
                cmId,
                percent: quizzesData[cmId].percent,
                questionsData: quizzesData[cmId].questionsData,
            }),
            headers: {
                'Content-Type': 'application/json',
            },
            onload: function (response) {
                if (response && response.status !== 429) {
                    delete quizzesData[cmId];
                    localStorage.quizzesData = JSON.stringify(quizzesData);
                }
                console.log('Post Quiz Data response =>', response);
            },
        });
    });
};


/***/ }),
/* 8 */
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {


var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const getQuestionsData_util_1 = __importDefault(__webpack_require__(2));
exports["default"] = (cmId, responseForm) => {
    responseForm.addEventListener('submit', () => {
        if (!localStorage.quizzesData)
            localStorage.quizzesData = JSON.stringify({});
        const quizzesData = JSON.parse(localStorage.quizzesData);
        if (!quizzesData[cmId]) {
            quizzesData[cmId] = {
                percent: null,
                questionsData: [],
            };
        }
        const quizData = quizzesData[cmId];
        const questionsData = (0, getQuestionsData_util_1.default)(responseForm);
        if (!questionsData)
            return "Can't get questions data";
        questionsData.forEach((questionData) => {
            const foundedQuestionData = quizData.questionsData.find((item) => item.question === questionData.question &&
                JSON.stringify(item.answersOptions) === JSON.stringify(questionData.answersOptions));
            if (foundedQuestionData) {
                foundedQuestionData.answers = questionData.answers;
            }
            else {
                quizData.questionsData.push(questionData);
            }
        });
        localStorage.quizzesData = JSON.stringify(quizzesData);
    });
};


/***/ }),
/* 9 */
/***/ ((__unused_webpack_module, exports) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports["default"] = () => {
    var _a;
    return (_a = Array.from(document.body.classList)
        .find((className) => className.includes('cmid-'))) === null || _a === void 0 ? void 0 : _a.split('-')[1];
};


/***/ })
/******/ 	]);
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/************************************************************************/
/******/
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	// This entry module is referenced by other modules so it can't be inlined
/******/ 	var __webpack_exports__ = __webpack_require__(0);
/******/
/******/ })()
;