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.
QString toString(qlonglong i) 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
The Cutelyst Context.
Definition: context.h:38
QString number(int n, int base)
~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.
qlonglong toLongLong(const QString &s, bool *ok) const const
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.
void setValue(const T &value)
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.
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
int 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
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 ...