#include "responsecheck.h" #include #include #include namespace { QString jsonValueToString(const QJsonValue &value) { if (value.isString()) return value.toString(); if (value.isDouble()) return QString::number(value.toDouble()); if (value.isBool()) return value.toBool() ? QStringLiteral("true") : QStringLiteral("false"); if (value.isNull() || value.isUndefined()) return QString(); if (value.isArray()) return QString::fromUtf8(QJsonDocument(value.toArray()).toJson(QJsonDocument::Compact)); if (value.isObject()) return QString::fromUtf8(QJsonDocument(value.toObject()).toJson(QJsonDocument::Compact)); return value.toVariant().toString(); } QJsonValue valueAtPath(const QJsonValue &root, const QString &dotPath) { if (dotPath.isEmpty()) return QJsonValue(); const QStringList parts = dotPath.split(QLatin1Char('.'), QString::SkipEmptyParts); QJsonValue current = root; for (const QString &part : parts) { if (!current.isObject()) return QJsonValue(); current = current.toObject().value(part); } return current; } QString defaultMessage(ResponseOutcome outcome, const QJsonObject &feedback) { switch (outcome) { case ResponseOutcome::Ok: return feedback.value(QStringLiteral("successText")).toString(); case ResponseOutcome::Pending: return feedback.value(QStringLiteral("pendingText")).toString(QStringLiteral("...")); case ResponseOutcome::Error: default: return feedback.value(QStringLiteral("errorText")).toString(QStringLiteral("Ошибка")); } } ResponseOutcome outcomeFromString(const QString &value) { const QString v = value.trimmed().toLower(); if (v == QLatin1String("ok")) return ResponseOutcome::Ok; if (v == QLatin1String("pending")) return ResponseOutcome::Pending; return ResponseOutcome::Error; } bool conditionMatches(const QJsonObject &condition, const QJsonValue &root) { const QString field = condition.value(QStringLiteral("field")).toString(); if (field.isEmpty()) return false; const QString actual = jsonValueToString(valueAtPath(root, field)); if (condition.contains(QStringLiteral("equals"))) return actual == condition.value(QStringLiteral("equals")).toString(); if (condition.contains(QStringLiteral("contains"))) return actual.contains(condition.value(QStringLiteral("contains")).toString()); return false; } bool ruleMatches(const QJsonObject &rule, const QJsonValue &root) { if (rule.contains(QStringLiteral("match"))) { const QJsonArray conditions = rule.value(QStringLiteral("match")).toArray(); if (conditions.isEmpty()) return false; for (const QJsonValue &value : conditions) { if (!conditionMatches(value.toObject(), root)) return false; } return true; } QJsonObject condition; condition.insert(QStringLiteral("field"), rule.value(QStringLiteral("field"))); if (rule.contains(QStringLiteral("equals"))) condition.insert(QStringLiteral("equals"), rule.value(QStringLiteral("equals"))); if (rule.contains(QStringLiteral("contains"))) condition.insert(QStringLiteral("contains"), rule.value(QStringLiteral("contains"))); return conditionMatches(condition, root); } ResponseEvaluation makeEvaluation(ResponseOutcome outcome, const QJsonObject &feedback, const QString &message = QString(), const QString &matchedRule = QString()) { ResponseEvaluation result; result.outcome = outcome; result.matchedRule = matchedRule; result.message = message.isEmpty() ? defaultMessage(outcome, feedback) : message; return result; } } // namespace ResponseEvaluation evaluateResponse(const QByteArray &body, int httpStatus, const QJsonObject &responseCheck, const QJsonObject &feedbackDefaults) { if (!responseCheck.value(QStringLiteral("enabled")).toBool(false)) return ResponseEvaluation(); if (responseCheck.value(QStringLiteral("requireHttpSuccess")).toBool(true) && httpStatus >= 400) { return makeEvaluation(ResponseOutcome::Error, feedbackDefaults); } QJsonParseError parseError; const QJsonDocument doc = QJsonDocument::fromJson(body, &parseError); if (parseError.error != QJsonParseError::NoError || !doc.isObject()) { return makeEvaluation(ResponseOutcome::Error, feedbackDefaults, feedbackDefaults.value(QStringLiteral("errorText")) .toString(QStringLiteral("Ошибка"))); } const QJsonValue root = doc.object(); const QJsonArray rules = responseCheck.value(QStringLiteral("rules")).toArray(); for (const QJsonValue &value : rules) { const QJsonObject rule = value.toObject(); if (!ruleMatches(rule, root)) continue; const ResponseOutcome outcome = outcomeFromString(rule.value(QStringLiteral("result")).toString()); const QString matchedRule = rule.value(QStringLiteral("field")).toString(); const QString message = rule.value(QStringLiteral("message")).toString(); return makeEvaluation(outcome, feedbackDefaults, message, matchedRule); } const ResponseOutcome fallback = outcomeFromString( responseCheck.value(QStringLiteral("defaultResult")).toString(QStringLiteral("error"))); return makeEvaluation(fallback, feedbackDefaults); } ResponseEvaluation evaluateBodyMatch(const QByteArray &body, int httpStatus, const QString &successMatch, const QJsonObject &feedbackDefaults) { const QString bodyText = QString::fromUtf8(body); const QString needle = successMatch.trimmed(); bool ok = false; if (httpStatus > 0 && httpStatus < 400) ok = true; if (!needle.isEmpty() && bodyText.contains(needle, Qt::CaseInsensitive)) ok = true; if (ok) return makeEvaluation(ResponseOutcome::Ok, feedbackDefaults, QString(), QStringLiteral("bodyMatch")); return makeEvaluation(ResponseOutcome::Error, feedbackDefaults); }