cutelyst 5.0.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
validator.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2017-2025 Matthias Fehring <mf@huessenbergnetz.de>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#include "validator_p.h"
7
8#include <Cutelyst/application.h>
9#include <Cutelyst/context.h>
10#include <Cutelyst/request.h>
11
12#include <QLoggingCategory>
13
14using namespace Cutelyst;
15using namespace Qt::Literals::StringLiterals;
16
17Q_LOGGING_CATEGORY(C_VALIDATOR, "cutelyst.utils.validator", QtWarningMsg)
18
19Validator::Validator(const char *translationContext)
20 : d_ptr(new ValidatorPrivate(translationContext))
21{
22}
23
24Validator::Validator(std::initializer_list<ValidatorRule *> validators,
25 const char *translationContext)
26 : d_ptr(new ValidatorPrivate(validators, translationContext))
27{
28}
29
30Validator::~Validator() = default;
31
33{
34 Q_D(Validator);
35 if (!d->validators.empty()) {
36 qDeleteAll(d->validators.begin(), d->validators.end());
37 d->validators.clear();
38 }
39}
40
42{
43 ValidatorResult result;
44
45 Q_ASSERT(c);
46
47 ParamsMultiMap params;
48 if (flags.testFlag(BodyParamsOnly)) {
49 params = c->req()->bodyParameters();
50 } else if (flags.testFlag(QueryParamsOnly)) {
51 params = c->req()->queryParameters();
52 } else {
53 params = c->req()->queryParameters();
54 params.unite(c->req()->bodyParameters());
55 }
56
57 result = validate(c, params, flags);
58
59 return result;
60}
61
63 Validator::validate(Context *c, const ParamsMultiMap &params, ValidatorFlags flags) const
64{
65 ValidatorResult result;
66
67 Q_ASSERT(c);
68 Q_D(const Validator);
69
70 if (d->validators.empty()) {
71 qCWarning(C_VALIDATOR) << "Validation started with empty validator list.";
72 return result;
73 }
74
75 if (params.empty()) {
76 qCWarning(C_VALIDATOR) << "Validation started with empty parameters.";
77 }
78
79 const bool stopOnFirstError = flags.testFlag(StopOnFirstError);
80 const bool noTrimming = flags.testFlag(NoTrimming);
81
82 for (ValidatorRule *v : d->validators) {
83
84 if (noTrimming) {
85 v->setTrimBefore(false);
86 }
87
88 const ValidatorReturnType singleResult = v->validate(c, params);
89
90 if (singleResult.extra.isValid()) {
91 result.addExtra(v->field(), singleResult.extra);
92 }
93
94 if (singleResult) {
95 result.addValue(v->field(), singleResult.value);
96 } else {
97 result.addError(v->field(), singleResult.errorMessage);
98 if (stopOnFirstError) {
99 break;
100 }
101 }
102 }
103
104 return result;
105}
106
108{
110 auto cb = avr.callback;
111
112 Q_D(const Validator);
113
114 ParamsMultiMap params;
115 if (flags.testFlag(BodyParamsOnly)) {
116 params = c->req()->bodyParameters();
117 } else if (flags.testFlag(QueryParamsOnly)) {
118 params = c->req()->queryParameters();
119 } else {
120 params = c->req()->queryParameters();
121 params.unite(c->req()->bodyParameters());
122 }
123
124 auto async = new AsyncValidator{c};
125 QObject::connect(async,
126 &AsyncValidator::finished,
127 [cb](const Cutelyst::ValidatorResult &result) { cb(result); });
128 async->start(d->validators, flags, params);
129
130 return avr;
131}
132
134 Validator::coValidate(Context *c, const ParamsMultiMap &params, ValidatorFlags flags) const
135{
137 auto cb = avr.callback;
138
139 Q_D(const Validator);
140
141 auto async = new AsyncValidator{c};
142 QObject::connect(async,
143 &AsyncValidator::finished,
144 [cb](const Cutelyst::ValidatorResult &result) { cb(result); });
145 async->start(d->validators, flags, params);
146
147 return avr;
148}
149
151{
152 Q_D(Validator);
153 v->setTranslationContext(d->translationContext);
154 d->validators.push_back(v);
155}
156
158{
159 app->loadTranslations(u"plugin_utils_validator"_s);
160}
161
162void AsyncValidator::start(const std::vector<ValidatorRule *> &validators,
163 Validator::ValidatorFlags flags,
164 const ParamsMultiMap &params)
165{
166 if (validators.empty()) {
167 qCWarning(C_VALIDATOR) << "Validation started with empty validator list.";
168 Q_EMIT finished(m_result);
169 return;
170 }
171
172 if (params.empty()) {
173 qCWarning(C_VALIDATOR) << "Validation started with empty parameters.";
174 }
175
176 m_params = params;
177
178 for (auto validator : validators) {
179 m_validators.enqueue(validator);
180 }
181
182 m_stopOnFirstError = flags.testFlag(Validator::StopOnFirstError);
183 m_noTrimming = flags.testFlag(Validator::NoTrimming);
184
185 QMetaObject::invokeMethod(this, "doValidation", Qt::DirectConnection);
186}
187
188void AsyncValidator::doValidation()
189{
190 if (m_validators.empty() || m_cancelValidation) {
191 Q_EMIT finished(m_result);
192 return;
193 }
194
195 auto v = m_validators.dequeue();
196
197 if (m_context.isNull()) {
198 qCCritical(C_VALIDATOR)
199 << "Cutelyst context object was destroyed while performing validation";
200 m_result.addError(v->field(),
201 u"Cutelyst context object was destroyed while performing validation."_s);
202 Q_EMIT finished(m_result);
203 return;
204 }
205
206 v->validateCb(m_context.get(), m_params, [this, v](ValidatorReturnType &&singleResult) {
207 if (singleResult.extra.isValid()) {
208 m_result.addExtra(v->field(), singleResult.extra);
209 }
210
211 if (singleResult) {
212 m_result.addValue(v->field(), singleResult.value);
213 } else {
214 m_result.addError(v->field(), singleResult.errorMessage);
215 if (m_stopOnFirstError) {
216 m_cancelValidation = true;
217 }
218 }
219 doValidation();
220 });
221}
The Cutelyst application.
Definition application.h:66
void loadTranslations(const QString &filename, const QString &directory={}, const QString &prefix={}, const QString &suffix={})
Coroutine awaitable for ValidatorResult.
The Cutelyst Context.
Definition context.h:42
Request * req
Definition context.h:66
ParamsMultiMap bodyParameters() const
Definition request.cpp:219
ParamsMultiMap queryParameters() const
Definition request.cpp:255
Provides information about performed validations.
void addExtra(const QString &field, const QVariant &extra)
void addValue(const QString &field, const QVariant &value)
void addError(const QString &field, const QString &message)
Base class for all validator rules.
Validation processor for input data.
Definition validator.h:309
AwaitedValidatorResult coValidate(Context *c, ValidatorFlags flags=NoSpecialBehavior) const
ValidatorResult validate(Context *c, ValidatorFlags flags=NoSpecialBehavior) const
Definition validator.cpp:41
Validator(const char *translationContext=nullptr)
Definition validator.cpp:19
void addValidator(ValidatorRule *v)
static void loadTranslations(Application *app)
The Cutelyst namespace holds all public Cutelyst API.
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
bool empty() const const
QMultiMap< Key, T > & unite(QMultiMap< Key, T > &&other)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
DirectConnection
bool isValid() const const
Contains the result of a single input parameter validation.