cutelyst  5.0.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
validatorbetween.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2017-2025 Matthias Fehring <mf@huessenbergnetz.de>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include "validatorbetween_p.h"
7 
8 #include <QMetaType>
9 
10 using namespace Cutelyst;
11 using namespace Qt::StringLiterals;
12 
14  QMetaType::Type type,
15  const QVariant &min,
16  const QVariant &max,
17  const ValidatorMessages &messages,
18  const QString &defValKey)
19  : ValidatorRule(*new ValidatorBetweenPrivate(field, type, min, max, messages, defValKey))
20 {
21 }
22 
24 
26 {
27  ValidatorReturnType result;
28 
29  const QString v = value(params);
30 
31  Q_D(const ValidatorBetween);
32 
33  if (!v.isEmpty()) {
34  bool ok = false;
35  bool valid = false;
36 
37  switch (d->type) {
38  case QMetaType::Char:
39  case QMetaType::Short:
40  case QMetaType::Int:
41  case QMetaType::Long:
43  {
44  const qlonglong val = c->locale().toLongLong(v, &ok);
45  if (Q_UNLIKELY(!ok)) {
46  result.errorMessage = parsingError(c);
47  qCWarning(C_VALIDATOR).noquote().nospace()
48  << debugString(c) << " Can not parse input \"" << v
49  << "\" into an integer number";
50  } else {
51  const qlonglong min =
52  ValidatorBetweenPrivate::extractLongLong(c, params, d->min, &ok);
53  if (Q_UNLIKELY(!ok)) {
55  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMin));
56  qCWarning(C_VALIDATOR).noquote()
57  << "Invalid mininum comparison value:" << d->min;
58  } else {
59  const qlonglong max =
60  ValidatorBetweenPrivate::extractLongLong(c, params, d->max, &ok);
61  if (Q_UNLIKELY(!ok)) {
63  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMax));
64  qCWarning(C_VALIDATOR).noquote()
65  << "Invalid maximum comparison value:" << d->max;
66  } else {
67  if ((val < min) || (val > max)) {
69  c, QVariantMap{{u"val"_s, val}, {u"min"_s, min}, {u"max"_s, max}});
70  qCDebug(C_VALIDATOR).noquote()
71  << debugString(c) << val << "is not between" << min << "and" << max;
72  } else {
73  valid = true;
74  }
75  }
76  }
77  }
78  } break;
79  case QMetaType::UChar:
80  case QMetaType::UShort:
81  case QMetaType::UInt:
82  case QMetaType::ULong:
84  {
85  const qulonglong val = v.toULongLong(&ok);
86  if (Q_UNLIKELY(!ok)) {
87  result.errorMessage = parsingError(c);
88  qCWarning(C_VALIDATOR).noquote().nospace()
89  << debugString(c) << " Can not parse input \"" << v
90  << "\" into an unsigned integer number";
91  } else {
92  const qulonglong min =
93  ValidatorBetweenPrivate::extractULongLong(c, params, d->min, &ok);
94  if (Q_UNLIKELY(!ok)) {
96  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMin));
97  qCWarning(C_VALIDATOR).noquote()
98  << debugString(c) << "Invalid mininum comparison value:" << d->min;
99  } else {
100  const qulonglong max =
101  ValidatorBetweenPrivate::extractULongLong(c, params, d->max, &ok);
102  if (Q_UNLIKELY(!ok)) {
104  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMax));
105  qCWarning(C_VALIDATOR).noquote()
106  << debugString(c) << "Invalid maximum comparison value:" << d->max;
107  } else {
108  if ((val < min) || (val > max)) {
109  result.errorMessage = validationError(
110  c, QVariantMap{{u"val"_s, val}, {u"min"_s, min}, {u"max"_s, max}});
111  qCDebug(C_VALIDATOR).noquote()
112  << debugString(c) << val << "is not between" << min << "and" << max;
113  } else {
114  valid = true;
115  }
116  }
117  }
118  }
119  } break;
120  case QMetaType::Float:
121  case QMetaType::Double:
122  {
123  const double val = v.toDouble(&ok);
124  if (Q_UNLIKELY(!ok)) {
125  result.errorMessage = parsingError(c);
126  qCWarning(C_VALIDATOR).noquote().nospace()
127  << debugString(c) << " Can not parse input \"" << v
128  << "\" into a floating point number";
129  } else {
130  const double min = ValidatorBetweenPrivate::extractDouble(c, params, d->min, &ok);
131  if (Q_UNLIKELY(!ok)) {
133  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMin));
134  qCWarning(C_VALIDATOR).noquote()
135  << debugString(c) << "Invalid mininum comparison value:" << d->min;
136  } else {
137  const double max =
138  ValidatorBetweenPrivate::extractDouble(c, params, d->max, &ok);
139  if (Q_UNLIKELY(!ok)) {
141  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMax));
142  qCWarning(C_VALIDATOR).noquote()
143  << debugString(c) << "Invalid maximum comparison value:" << d->max;
144  } else {
145  if ((val < min) || (val > max)) {
146  result.errorMessage = validationError(
147  c, QVariantMap{{u"val"_s, val}, {u"min"_s, min}, {u"max"_s, max}});
148  qCDebug(C_VALIDATOR).noquote()
149  << debugString(c) << val << "is not between" << min << "and" << max;
150  } else {
151  valid = true;
152  }
153  }
154  }
155  }
156  } break;
157  case QMetaType::QString:
158  {
159  const auto val = static_cast<qlonglong>(v.length());
160  const qlonglong min = ValidatorBetweenPrivate::extractLongLong(c, params, d->min, &ok);
161  if (Q_UNLIKELY(!ok)) {
163  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMin));
164  qCWarning(C_VALIDATOR).noquote()
165  << debugString(c) << "Invalid mininum comparison value:" << d->min;
166  } else {
167  const qlonglong max =
168  ValidatorBetweenPrivate::extractLongLong(c, params, d->max, &ok);
169  if (Q_UNLIKELY(!ok)) {
171  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidMax));
172  qCWarning(C_VALIDATOR).noquote()
173  << debugString(c) << "Invalid maximum comparison value:" << d->max;
174  } else {
175  if ((val < min) || (val > max)) {
176  result.errorMessage = validationError(
177  c, QVariantMap{{u"val"_s, val}, {u"min"_s, min}, {u"max"_s, max}});
178  qCDebug(C_VALIDATOR).noquote() << debugString(c) << "String length" << val
179  << "is not between" << min << "and" << max;
180  } else {
181  valid = true;
182  }
183  }
184  }
185  } break;
186  default:
187  qCWarning(C_VALIDATOR).noquote()
188  << debugString(c) << "The comparison type" << d->type << "is not supported";
190  c, static_cast<int>(ValidatorRulePrivate::ErrorType::InvalidType));
191  break;
192  }
193 
194  if (valid) {
195  if (d->type != QMetaType::QString) {
196  const QVariant _v = ValidatorBetweenPrivate::valueToNumber(c, v, d->type);
197  if (_v.isValid()) {
198  result.value = _v;
199  } else {
200  result.errorMessage = parsingError(c);
201  }
202  } else {
203  result.value.setValue(v);
204  }
205  }
206  } else {
207  defaultValue(c, &result);
208  }
209 
210  return result;
211 }
212 
214 {
215  cb(validate(c, params));
216 }
217 
219  const QVariant &errorData) const
220 {
221  Q_D(const ValidatorBetween);
222 
223  const QVariantMap map = errorData.toMap();
224  QString min;
225  QString max;
226  switch (d->type) {
227  case QMetaType::Char:
228  case QMetaType::Short:
229  case QMetaType::Int:
230  case QMetaType::Long:
231  case QMetaType::LongLong:
232  case QMetaType::QString:
233  min = c->locale().toString(map.value(u"min"_s).toLongLong());
234  max = c->locale().toString(map.value(u"max"_s).toLongLong());
235  break;
236  case QMetaType::UChar:
237  case QMetaType::UShort:
238  case QMetaType::UInt:
239  case QMetaType::ULong:
241  min = c->locale().toString(map.value(u"min"_s).toULongLong());
242  max = c->locale().toString(map.value(u"max"_s).toULongLong());
243  break;
244  case QMetaType::Float:
245  case QMetaType::Double:
246  min = c->locale().toString(map.value(u"min"_s).toDouble());
247  max = c->locale().toString(map.value(u"max"_s).toDouble());
248  break;
249  default:
250  return validationDataError(c);
251  }
252 
253  const QString _label = label(c);
254 
255  if (_label.isEmpty()) {
256  if (d->type == QMetaType::QString) {
257  //: %1 will be replaced by the minimum, %2 by the maximum value
258  //% "The text must be between %1 and %2 characters long."
259  return c->qtTrId("cutelyst-valbetween-genvalerr-string").arg(min, max);
260  } else {
261  //: %1 will be replaced by the minimum, %2 by the maximum value
262  //% "The value must be between %1 and %2."
263  return c->qtTrId("cutelyst-valbetween-genvalerr-num").arg(min, max);
264  }
265  } else {
266  if (d->type == QMetaType::QString) {
267  //: %1 will be replaced by the field label, %2 by the minimum and %3 by the
268  //: maximum value
269  //% "The text in the “%1“ field must be between %2 and %3 characters long."
270  return c->qtTrId("cutelyst-valbetween-genvalerr-string-label").arg(_label, min, max);
271  } else {
272  //: %1 will be replaced by the field label, %2 by the minimum and %3 by the
273  //: maximum value
274  //% "The value in the “%1” field must be between %2 and %3."
275  return c->qtTrId("cutelyst-valbetween-genvalerr-num-label").arg(_label, min, max);
276  }
277  }
278 
279  return {};
280 }
281 
283 {
284  const auto errorType = static_cast<ValidatorRulePrivate::ErrorType>(errorData.toInt());
285  const QString _label = label(c);
286 
287  if (_label.isEmpty()) {
288  switch (errorType) {
289  case ValidatorRulePrivate::ErrorType::InvalidMin:
290  //% "The minimum comparison value is not valid."
291  return c->qtTrId("cutelyst-validator-genvaldataerr-min");
292  case ValidatorRulePrivate::ErrorType::InvalidType:
293  {
294  Q_D(const ValidatorBetween);
295  QMetaType _type(d->type);
296  //: %1 will be replaced by the name of the comparison type
297  //% "The comparison type %1 is not supported."
298  return c->qtTrId("cutelyst-validator-genvaldataerr-type")
299  .arg(QString::fromLatin1(_type.name()));
300  }
301  case ValidatorRulePrivate::ErrorType::InvalidMax:
302  //% "The maximum comparison value is not valid."
303  return c->qtTrId("cutelyst-validator-genvaldataerr-max");
304  }
305  } else {
306  switch (errorType) {
307  case ValidatorRulePrivate::ErrorType::InvalidMin:
308  //: %1 will be replaced by the field label
309  //% "The minimum comparison value for the “%1” field is not valid."
310  return c->qtTrId("cutelyst-validator-genvaldataerr-min-label").arg(_label);
311  case ValidatorRulePrivate::ErrorType::InvalidType:
312  {
313  Q_D(const ValidatorBetween);
314  QMetaType _type(d->type);
315  //: %1 will be replaced by the type name, %2 will be replaced by the field label
316  //% "The comparison type %1 for the “%2” field is not supported."
317  return c->qtTrId("cutelyst-validator-genvaldataerr-type-label")
318  .arg(QString::fromLatin1(_type.name()), _label);
319  }
320  case ValidatorRulePrivate::ErrorType::InvalidMax:
321  //: %1 will be replaced by the field label
322  //% "The maximum comparison value for the “%1” field is not valid."
323  return c->qtTrId("cutelyst-validator-genvaldataerr-max-label").arg(_label);
324  }
325  }
326 
327  return {};
328 }
329 
331 {
332  Q_UNUSED(errorData)
333  Q_D(const ValidatorBetween);
334 
335  const QString _label = label(c);
336  if ((d->type == QMetaType::Float) || (d->type == QMetaType::Double)) {
337  if (_label.isEmpty()) {
338  //% "Failed to parse the input value into a floating point number."
339  return c->qtTrId("cutelyst-validator-genparseerr-float");
340  } else {
341  //: %1 will be replaced by the field label
342  //% "Failed to parse the input value for the “%1” field into a "
343  //% "floating point number."
344  return c->qtTrId("cutelyst-validator-genparseerr-float-label").arg(_label);
345  }
346  } else {
347  if (_label.isEmpty()) {
348  //% "Failed to parse the input value into an integer number."
349  return c->qtTrId("cutelyst-validator-genparseerr-int");
350  } else {
351  //: %1 will be replaced by the field label
352  //% "Failed to parse the input value for the “%1” field into an integer number."
353  return c->qtTrId("cutelyst-validator-genparseerr-int-label").arg(_label);
354  }
355  }
356 }
Checks if a value or text length is between a minimum and maximum value.
qlonglong toLongLong(QStringView s, bool *ok) const const
ValidatorReturnType validate(Context *c, const ParamsMultiMap &params) const override
Stores custom error messages and the input field label.
QString genericValidationError(Context *c, const QVariant &errorData=QVariant()) const override
double toDouble(bool *ok) const const
QString toString(QDate date, FormatType format) const const
The Cutelyst Context.
Definition: context.h:42
void defaultValue(Context *c, ValidatorReturnType *result) const
int toInt(bool *ok) const const
ValidatorBetween(const QString &field, QMetaType::Type type, const QVariant &min, const QVariant &max, const ValidatorMessages &messages=ValidatorMessages(), const QString &defValKey={})
QString genericParsingError(Context *c, const QVariant &errorData) const override
bool isEmpty() const const
QString parsingError(Context *c, const QVariant &errorData={}) const
QString genericValidationDataError(Context *c, const QVariant &errorData) const override
The Cutelyst namespace holds all public Cutelyst API.
QString debugString(const Context *c) const
Base class for all validator rules.
qulonglong toULongLong(bool *ok, int base) const const
QLocale locale() const noexcept
Definition: context.cpp:461
QString value(const ParamsMultiMap &params) const
void validateCb(Context *c, const ParamsMultiMap &params, ValidatorRtFn cb) const override
QString label(const Context *c) const
std::function< void(ValidatorReturnType &&result)> ValidatorRtFn
Void callback function for validator rules that processes the ValidatorReturnType.
Definition: validatorrule.h:82
QString fromLatin1(QByteArrayView str)
const char * name() const const
QString validationError(Context *c, const QVariant &errorData={}) const
QMap< QString, QVariant > toMap() const const
QString validationDataError(Context *c, const QVariant &errorData={}) const
QString qtTrId(const char *id, int n=-1) const
Definition: context.h:658
qsizetype length() const const
bool isValid() const const
Contains the result of a single input parameter validation.
Definition: validatorrule.h:52
QString arg(Args &&... args) const const
void setValue(QVariant &&value)