cutelyst  3.9.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-2022 Matthias Fehring <mf@huessenbergnetz.de>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include "validatorbetween_p.h"
7 
8 using namespace Cutelyst;
9 
11  QMetaType::Type type,
12  const QVariant &min,
13  const QVariant &max,
14  const ValidatorMessages &messages,
15  const QString &defValKey)
16  : ValidatorRule(*new ValidatorBetweenPrivate(field, type, min, max, messages, defValKey))
17 {
18 }
19 
21 {
22 }
23 
25 {
26  ValidatorReturnType result;
27 
28  const QString v = value(params);
29 
30  Q_D(const ValidatorBetween);
31 
32  if (!v.isEmpty()) {
33  bool ok = false;
34  bool valid = false;
35 
36  switch (d->type) {
37  case QMetaType::Char:
38  case QMetaType::Short:
39  case QMetaType::Int:
40  case QMetaType::Long:
42  {
43  const qlonglong val = c->locale().toLongLong(v, &ok);
44  if (Q_UNLIKELY(!ok)) {
45  result.errorMessage = parsingError(c);
46  qCWarning(
47  C_VALIDATOR,
48  "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.",
49  qPrintable(field()),
50  qPrintable(c->controllerName()),
51  qPrintable(c->actionName()));
52  } else {
53  const qlonglong min = d->extractLongLong(c, params, d->min, &ok);
54  if (Q_UNLIKELY(!ok)) {
55  result.errorMessage = validationDataError(c, -1);
56  qCWarning(C_VALIDATOR,
57  "ValidatorBetween: Invalid minimum comparison value for field %s in "
58  "%s::%s.",
59  qPrintable(field()),
60  qPrintable(c->controllerName()),
61  qPrintable(c->actionName()));
62  } else {
63  const qlonglong max = d->extractLongLong(c, params, d->max, &ok);
64  if (Q_UNLIKELY(!ok)) {
65  result.errorMessage = validationDataError(c, 1);
66  qCWarning(C_VALIDATOR,
67  "ValidatorBetween: Invalid maximum comparison value for field %s "
68  "in %s::%s.",
69  qPrintable(field()),
70  qPrintable(c->controllerName()),
71  qPrintable(c->actionName()));
72  } else {
73  if ((val < min) || (val > max)) {
74  result.errorMessage =
76  QVariantMap{{QStringLiteral("val"), val},
77  {QStringLiteral("min"), min},
78  {QStringLiteral("max"), max}});
79  qCDebug(C_VALIDATOR,
80  "ValidatorBetween: Validation failed for field %s in %s::%s: "
81  "%lli is not between %lli and %lli.",
82  qPrintable(field()),
83  qPrintable(c->controllerName()),
84  qPrintable(c->actionName()),
85  val,
86  min,
87  max);
88  } else {
89  valid = true;
90  }
91  }
92  }
93  }
94  } break;
95  case QMetaType::UChar:
96  case QMetaType::UShort:
97  case QMetaType::UInt:
98  case QMetaType::ULong:
100  {
101  const qulonglong val = v.toULongLong(&ok);
102  if (Q_UNLIKELY(!ok)) {
103  result.errorMessage = parsingError(c);
104  qCWarning(
105  C_VALIDATOR,
106  "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.",
107  qPrintable(field()),
108  qPrintable(c->controllerName()),
109  qPrintable(c->actionName()));
110  } else {
111  const qulonglong min = d->extractULongLong(c, params, d->min, &ok);
112  if (Q_UNLIKELY(!ok)) {
113  result.errorMessage = validationDataError(c, -1);
114  qCWarning(C_VALIDATOR,
115  "ValidatorBetween: Invalid minimum comparison value for field %s in "
116  "%s::%s.",
117  qPrintable(field()),
118  qPrintable(c->controllerName()),
119  qPrintable(c->actionName()));
120  } else {
121  const qulonglong max = d->extractULongLong(c, params, d->max, &ok);
122  if (Q_UNLIKELY(!ok)) {
123  result.errorMessage = validationDataError(c, 1);
124  qCWarning(C_VALIDATOR,
125  "ValidatorBetween: Invalid maximum comparison value for field %s "
126  "in %s::%s.",
127  qPrintable(field()),
128  qPrintable(c->controllerName()),
129  qPrintable(c->actionName()));
130  } else {
131  if ((val < min) || (val > max)) {
132  result.errorMessage =
133  validationError(c,
134  QVariantMap{{QStringLiteral("val"), val},
135  {QStringLiteral("min"), min},
136  {QStringLiteral("max"), max}});
137  qCDebug(C_VALIDATOR,
138  "ValidatorBetween: Validation failed for field %s in %s::%s: "
139  "%llu is not between %llu and %llu.",
140  qPrintable(field()),
141  qPrintable(c->controllerName()),
142  qPrintable(c->actionName()),
143  val,
144  min,
145  max);
146  } else {
147  valid = true;
148  }
149  }
150  }
151  }
152  } break;
153  case QMetaType::Float:
154  case QMetaType::Double:
155  {
156  const double val = v.toDouble(&ok);
157  if (Q_UNLIKELY(!ok)) {
158  result.errorMessage = parsingError(c);
159  qCWarning(
160  C_VALIDATOR,
161  "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.",
162  qPrintable(field()),
163  qPrintable(c->controllerName()),
164  qPrintable(c->actionName()));
165  } else {
166  const double min = d->extractDouble(c, params, d->min, &ok);
167  if (Q_UNLIKELY(!ok)) {
168  result.errorMessage = validationDataError(c, -1);
169  qCWarning(C_VALIDATOR,
170  "ValidatorBetween: Invalid minimum comparison value for field %s in "
171  "%s::%s.",
172  qPrintable(field()),
173  qPrintable(c->controllerName()),
174  qPrintable(c->actionName()));
175  } else {
176  const double max = d->extractDouble(c, params, d->max, &ok);
177  if (Q_UNLIKELY(!ok)) {
178  result.errorMessage = validationDataError(c, 1);
179  qCWarning(C_VALIDATOR,
180  "ValidatorBetween: Invalid maximum comparison value for field %s "
181  "in %s::%s.",
182  qPrintable(field()),
183  qPrintable(c->controllerName()),
184  qPrintable(c->actionName()));
185  } else {
186  if ((val < min) || (val > max)) {
187  result.errorMessage =
188  validationError(c,
189  QVariantMap{{QStringLiteral("val"), val},
190  {QStringLiteral("min"), min},
191  {QStringLiteral("max"), max}});
192  qCDebug(C_VALIDATOR,
193  "ValidatorBetween: Validation failed for field %s in %s::%s: "
194  "%f is not between %f and %f.",
195  qPrintable(field()),
196  qPrintable(c->controllerName()),
197  qPrintable(c->actionName()),
198  val,
199  min,
200  max);
201  } else {
202  valid = true;
203  }
204  }
205  }
206  }
207  } break;
208  case QMetaType::QString:
209  {
210  const qlonglong val = static_cast<qlonglong>(v.length());
211  const qlonglong min = d->extractLongLong(c, params, d->min, &ok);
212  if (Q_UNLIKELY(!ok)) {
213  result.errorMessage = validationDataError(c, -1);
214  qCWarning(
215  C_VALIDATOR,
216  "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.",
217  qPrintable(field()),
218  qPrintable(c->controllerName()),
219  qPrintable(c->actionName()));
220  } else {
221  const qlonglong max = d->extractLongLong(c, params, d->max, &ok);
222  if (Q_UNLIKELY(!ok)) {
223  result.errorMessage = validationDataError(c, 1);
224  qCWarning(C_VALIDATOR,
225  "ValidatorBetween: Invalid maximum comparison value for field %s in "
226  "%s::%s.",
227  qPrintable(field()),
228  qPrintable(c->controllerName()),
229  qPrintable(c->actionName()));
230  } else {
231  if ((val < min) || (val > max)) {
232  result.errorMessage =
233  validationError(c,
234  QVariantMap{{QStringLiteral("val"), val},
235  {QStringLiteral("min"), min},
236  {QStringLiteral("max"), max}});
237  qCDebug(C_VALIDATOR,
238  "ValidatorBetween: Validation failed for field %s in %s::%s: "
239  "string length %lli is not between %lli and %lli.",
240  qPrintable(field()),
241  qPrintable(c->controllerName()),
242  qPrintable(c->actionName()),
243  val,
244  min,
245  max);
246  } else {
247  valid = true;
248  }
249  }
250  }
251  } break;
252  default:
253  qCWarning(C_VALIDATOR,
254  "ValidatorBetween: The comparison type with ID %i for field %s at %s::%s is "
255  "not supported.",
256  static_cast<int>(d->type),
257  qPrintable(field()),
258  qPrintable(c->controllerName()),
259  qPrintable(c->actionName()));
260  result.errorMessage = validationDataError(c, 0);
261  break;
262  }
263 
264  if (valid) {
265  if (d->type != QMetaType::QString) {
266  const QVariant _v = d->valueToNumber(c, v, d->type);
267  if (_v.isValid()) {
268  result.value = _v;
269  } else {
270  result.errorMessage = parsingError(c);
271  }
272  } else {
273  result.value.setValue(v);
274  }
275  }
276  } else {
277  defaultValue(c, &result, "ValidatorBetween");
278  }
279 
280  return result;
281 }
282 
284  const QVariant &errorData) const
285 {
286  QString error;
287 
288  Q_D(const ValidatorBetween);
289 
290  const QVariantMap map = errorData.toMap();
291  QString min, max;
292  switch (d->type) {
293  case QMetaType::Char:
294  case QMetaType::Short:
295  case QMetaType::Int:
296  case QMetaType::Long:
297  case QMetaType::LongLong:
298  case QMetaType::QString:
299  min = c->locale().toString(map.value(QStringLiteral("min")).toLongLong());
300  max = c->locale().toString(map.value(QStringLiteral("max")).toLongLong());
301  break;
302  case QMetaType::UChar:
303  case QMetaType::UShort:
304  case QMetaType::UInt:
305  case QMetaType::ULong:
307  min = c->locale().toString(map.value(QStringLiteral("min")).toULongLong());
308  max = c->locale().toString(map.value(QStringLiteral("max")).toULongLong());
309  break;
310  case QMetaType::Float:
311  case QMetaType::Double:
312  min = c->locale().toString(map.value(QStringLiteral("min")).toDouble());
313  max = c->locale().toString(map.value(QStringLiteral("max")).toDouble());
314  break;
315  default:
316  error = validationDataError(c);
317  return error;
318  }
319 
320  const QString _label = label(c);
321 
322  if (_label.isEmpty()) {
323  if (d->type == QMetaType::QString) {
324  error = c->translate("Cutelyst::ValidatorBetween",
325  "The text must be between %1 and %2 characters long.")
326  .arg(min, max);
327  } else {
328  error =
329  c->translate("Cutelyst::ValidatorBetween", "The value must be between %1 and %2.")
330  .arg(min, max);
331  }
332  } else {
333  if (d->type == QMetaType::QString) {
334  error = c->translate(
335  "Cutelyst::ValidatorBetween",
336  "The text in the “%1“ field must be between %2 and %3 characters long.")
337  .arg(_label, min, max);
338  } else {
339  error = c->translate("Cutelyst::ValidatorBetween",
340  "The value in the “%1” field must be between %2 and %3.")
341  .arg(_label, min, max);
342  }
343  }
344 
345  return error;
346 }
347 
349 {
350  QString error;
351 
352  int field = errorData.toInt();
353  const QString _label = label(c);
354 
355  if (field == -1) {
356  if (_label.isEmpty()) {
357  error = c->translate("Cutelyst::ValidatorBetween",
358  "The minimum comparison value is not valid.");
359  } else {
360  //: %1 will be replaced by the field label
361  error = c->translate("Cutelyst::ValidatorBetween",
362  "The minimum comparison value for the “%1” field is not valid.")
363  .arg(_label);
364  }
365  } else if (field == 0) {
366  Q_D(const ValidatorBetween);
367  if (_label.isEmpty()) {
368  error = c->translate("Cutelyst::ValidatorBetween",
369  "The comparison type with ID %1 is not supported.")
370  .arg(static_cast<int>(d->type));
371  } else {
372  //: %1 will be replaced by the type id, %2 will be replaced by the field label
373  error =
374  c->translate("Cutelyst::ValidatorBetween",
375  "The comparison type with ID %1 for the “%2” field is not supported.")
376  .arg(QString::number(static_cast<int>(d->type)), _label);
377  }
378  } else if (field == 1) {
379  if (_label.isEmpty()) {
380  error = c->translate("Cutelyst::ValidatorBetween",
381  "The maximum comparison value is not valid.");
382  } else {
383  //: %1 will be replaced by the field label
384  error = c->translate("Cutelyst::ValidatorBetween",
385  "The maximum comparison value for the “%1” field is not valid.")
386  .arg(_label);
387  }
388  }
389 
390  return error;
391 }
392 
394 {
395  QString error;
396  Q_UNUSED(errorData)
397  Q_D(const ValidatorBetween);
398 
399  const QString _label = label(c);
400  if ((d->type == QMetaType::Float) || (d->type == QMetaType::Double)) {
401  if (_label.isEmpty()) {
402  error = c->translate("Cutelyst::ValidatorBetween",
403  "Failed to parse the input value into a floating point number.");
404  } else {
405  //: %1 will be replaced by the field label
406  error = c->translate("Cutelyst::ValidatorBetween",
407  "Failed to parse the input value for the “%1” field into a "
408  "floating point number.")
409  .arg(_label);
410  }
411  } else {
412  if (_label.isEmpty()) {
413  error = c->translate("Cutelyst::ValidatorBetween",
414  "Failed to parse the input value into an integer number.");
415  } else {
416  //: %1 will be replaced by the field label
417  error =
418  c->translate(
419  "Cutelyst::ValidatorBetween",
420  "Failed to parse the input value for the “%1” field into an integer number.")
421  .arg(_label);
422  }
423  }
424 
425  return error;
426 }
QString parsingError(Context *c, const QVariant &errorData=QVariant()) const
Returns an error message if an error occurred while parsing input.
Checks if a value or text length is between a minimum and maximum value.
QString validationError(Context *c, const QVariant &errorData=QVariant()) const
Returns a descriptive error message if validation failed.
qlonglong toLongLong(QStringView s, bool *ok) const const
ValidatorReturnType validate(Context *c, const ParamsMultiMap &params) const override
Performs the validation and returns the result.
Stores custom error messages and the input field label.
QString genericValidationError(Context *c, const QVariant &errorData=QVariant()) const override
Returns a generic error message.
double toDouble(bool *ok) const const
QString toString(QDate date, FormatType format) const const
The Cutelyst Context.
Definition: context.h:38
QString number(double n, char format, int precision)
~ValidatorBetween() override
Deconstructs the between validator.
int toInt(bool *ok) const const
QString genericParsingError(Context *c, const QVariant &errorData) const override
Returns a generic error message for input value parsing errors.
bool isEmpty() const const
QString translate(const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
Definition: context.cpp:490
QString validationDataError(Context *c, const QVariant &errorData=QVariant()) const
Returns an error message if any validation data is missing or invalid.
QString genericValidationDataError(Context *c, const QVariant &errorData) const override
Returns a generic error message for validation data errors.
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
Base class for all validator rules.
qulonglong toULongLong(bool *ok, int base) const const
QLocale locale() const noexcept
Definition: context.cpp:466
QString label(Context *c) const
Returns the human readable field label used for generic error messages.
QString value(const ParamsMultiMap &params) const
Returns the value of the field from the input params.
QMap< QString, QVariant > toMap() const const
ValidatorBetween(const QString &field, QMetaType::Type type, const QVariant &min, const QVariant &max, const ValidatorMessages &messages=ValidatorMessages(), const QString &defValKey=QString())
Constructs a new between validator.
qsizetype length() const const
QString field() const
Returns the name of the field to validate.
bool isValid() const const
Contains the result of a single input parameter validation.
Definition: validatorrule.h:49
QString arg(Args &&... args) const const
void defaultValue(Context *c, ValidatorReturnType *result, const char *validatorName) const
I a defValKey has been set in the constructor, this will try to get the default value from the stash ...
void setValue(QVariant &&value)