Cutelyst  3.5.0
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 
10 ValidatorBetween::ValidatorBetween(const QString &field, QMetaType::Type type, const QVariant &min, const QVariant &max, const ValidatorMessages &messages, const QString &defValKey) :
11  ValidatorRule(*new ValidatorBetweenPrivate(field, type, min, max, messages, defValKey))
12 {
13 }
14 
16 {
17 }
18 
20 {
21  ValidatorReturnType result;
22 
23  const QString v = value(params);
24 
25  Q_D(const ValidatorBetween);
26 
27  if (!v.isEmpty()) {
28  bool ok = false;
29  bool valid = false;
30 
31  switch (d->type) {
32  case QMetaType::Char:
33  case QMetaType::Short:
34  case QMetaType::Int:
35  case QMetaType::Long:
36  case QMetaType::LongLong:
37  {
38  const qlonglong val = c->locale().toLongLong(v, &ok);
39  if (Q_UNLIKELY(!ok)) {
40  result.errorMessage = parsingError(c);
41  qCWarning(C_VALIDATOR, "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
42  } else {
43  const qlonglong min = d->extractLongLong(c, params, d->min, &ok);
44  if (Q_UNLIKELY(!ok)) {
45  result.errorMessage = validationDataError(c, -1);
46  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
47  } else {
48  const qlonglong max = d->extractLongLong(c, params, d->max, &ok);
49  if (Q_UNLIKELY(!ok)) {
50  result.errorMessage = validationDataError(c, 1);
51  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
52  } else {
53  if ((val < min) || (val > max)) {
54  result.errorMessage = validationError(c, QVariantMap{
55  {QStringLiteral("val"), val},
56  {QStringLiteral("min"), min},
57  {QStringLiteral("max"), max}
58  });
59  qCDebug(C_VALIDATOR, "ValidatorBetween: Validation failed for field %s in %s::%s: %lli is not between %lli and %lli.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()), val, min, max);
60  } else {
61  valid = true;
62  }
63  }
64  }
65  }
66  }
67  break;
68  case QMetaType::UChar:
69  case QMetaType::UShort:
70  case QMetaType::UInt:
71  case QMetaType::ULong:
72  case QMetaType::ULongLong:
73  {
74  const qulonglong val = v.toULongLong(&ok);
75  if (Q_UNLIKELY(!ok)) {
76  result.errorMessage = parsingError(c);
77  qCWarning(C_VALIDATOR, "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
78  } else {
79  const qulonglong min = d->extractULongLong(c, params, d->min, &ok);
80  if (Q_UNLIKELY(!ok)) {
81  result.errorMessage = validationDataError(c, -1);
82  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
83  } else {
84  const qulonglong max = d->extractULongLong(c, params, d->max, &ok);
85  if (Q_UNLIKELY(!ok)) {
86  result.errorMessage = validationDataError(c, 1);
87  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
88  } else {
89  if ((val < min) || (val > max)) {
90  result.errorMessage = validationError(c, QVariantMap{
91  {QStringLiteral("val"), val},
92  {QStringLiteral("min"), min},
93  {QStringLiteral("max"), max}
94  });
95  qCDebug(C_VALIDATOR, "ValidatorBetween: Validation failed for field %s in %s::%s: %llu is not between %llu and %llu.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()), val, min, max);
96  } else {
97  valid = true;
98  }
99  }
100  }
101  }
102  }
103  break;
104  case QMetaType::Float:
105  case QMetaType::Double:
106  {
107  const double val = v.toDouble(&ok);
108  if (Q_UNLIKELY(!ok)) {
109  result.errorMessage = parsingError(c);
110  qCWarning(C_VALIDATOR, "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
111  } else {
112  const double min = d->extractDouble(c, params, d->min, &ok);
113  if (Q_UNLIKELY(!ok)) {
114  result.errorMessage = validationDataError(c, -1);
115  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
116  } else {
117  const double max = d->extractDouble(c, params, d->max, &ok);
118  if (Q_UNLIKELY(!ok)) {
119  result.errorMessage = validationDataError(c, 1);
120  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
121  } else {
122  if ((val < min) || (val > max)) {
123  result.errorMessage = validationError(c, QVariantMap{
124  {QStringLiteral("val"), val},
125  {QStringLiteral("min"), min},
126  {QStringLiteral("max"), max}
127  });
128  qCDebug(C_VALIDATOR, "ValidatorBetween: Validation failed for field %s in %s::%s: %f is not between %f and %f.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()), val, min, max);
129  } else {
130  valid = true;
131  }
132  }
133  }
134  }
135  }
136  break;
137  case QMetaType::QString:
138  {
139  const qlonglong val = static_cast<qlonglong>(v.length());
140  const qlonglong min = d->extractLongLong(c, params, d->min, &ok);
141  if (Q_UNLIKELY(!ok)) {
142  result.errorMessage = validationDataError(c, -1);
143  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
144  } else {
145  const qlonglong max = d->extractLongLong(c, params, d->max, &ok);
146  if (Q_UNLIKELY(!ok)) {
147  result.errorMessage = validationDataError(c, 1);
148  qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
149  } else {
150  if ((val < min) || (val > max)) {
151  result.errorMessage = validationError(c, QVariantMap{
152  {QStringLiteral("val"), val},
153  {QStringLiteral("min"), min},
154  {QStringLiteral("max"), max}
155  });
156  qCDebug(C_VALIDATOR, "ValidatorBetween: Validation failed for field %s in %s::%s: string length %lli is not between %lli and %lli.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()), val, min, max);
157  } else {
158  valid = true;
159  }
160  }
161  }
162  }
163  break;
164  default:
165  qCWarning(C_VALIDATOR, "ValidatorBetween: The comparison type with ID %i for field %s at %s::%s is not supported.", static_cast<int>(d->type), qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
166  result.errorMessage = validationDataError(c, 0);
167  break;
168  }
169 
170  if (valid) {
171  if (d->type != QMetaType::QString) {
172  const QVariant _v = d->valueToNumber(c, v, d->type);
173  if (_v.isValid()) {
174  result.value = _v;
175  } else {
176  result.errorMessage = parsingError(c);
177  }
178  } else {
179  result.value.setValue(v);
180  }
181  }
182  } else {
183  defaultValue(c, &result, "ValidatorBetween");
184  }
185 
186  return result;
187 }
188 
190 {
191  QString error;
192 
193  Q_D(const ValidatorBetween);
194 
195  const QVariantMap map = errorData.toMap();
196  QString min, max;
197  switch (d->type) {
198  case QMetaType::Char:
199  case QMetaType::Short:
200  case QMetaType::Int:
201  case QMetaType::Long:
202  case QMetaType::LongLong:
203  case QMetaType::QString:
204  min = c->locale().toString(map.value(QStringLiteral("min")).toLongLong());
205  max = c->locale().toString(map.value(QStringLiteral("max")).toLongLong());
206  break;
207  case QMetaType::UChar:
208  case QMetaType::UShort:
209  case QMetaType::UInt:
210  case QMetaType::ULong:
211  case QMetaType::ULongLong:
212  min = c->locale().toString(map.value(QStringLiteral("min")).toULongLong());
213  max = c->locale().toString(map.value(QStringLiteral("max")).toULongLong());
214  break;
215  case QMetaType::Float:
216  case QMetaType::Double:
217  min = c->locale().toString(map.value(QStringLiteral("min")).toDouble());
218  max = c->locale().toString(map.value(QStringLiteral("max")).toDouble());
219  break;
220  default:
221  error = validationDataError(c);
222  return error;
223  }
224 
225  const QString _label = label(c);
226 
227  if (_label.isEmpty()) {
228  if (d->type == QMetaType::QString) {
229  error = c->translate("Cutelyst::ValidatorBetween", "The text must be between %1 and %2 characters long.").arg(min, max);
230  } else {
231  error = c->translate("Cutelyst::ValidatorBetween", "The value must be between %1 and %2.").arg(min, max);
232  }
233  } else {
234  if (d->type == QMetaType::QString) {
235  error = c->translate("Cutelyst::ValidatorBetween", "The text in the “%1“ field must be between %2 and %3 characters long.").arg(_label, min, max);
236  } else {
237  error = c->translate("Cutelyst::ValidatorBetween", "The value in the “%1” field must be between %2 and %3.").arg(_label, min, max);
238  }
239  }
240 
241  return error;
242 }
243 
245 {
246  QString error;
247 
248  int field = errorData.toInt();
249  const QString _label = label(c);
250 
251  if (field == -1) {
252  if (_label.isEmpty()) {
253  error = c->translate("Cutelyst::ValidatorBetween", "The minimum comparison value is not valid.");
254  } else {
255  //: %1 will be replaced by the field label
256  error = c->translate("Cutelyst::ValidatorBetween", "The minimum comparison value for the “%1” field is not valid.").arg(_label);
257  }
258  } else if (field == 0) {
259  Q_D(const ValidatorBetween);
260  if (_label.isEmpty()) {
261  error = c->translate("Cutelyst::ValidatorBetween", "The comparison type with ID %1 is not supported.").arg(static_cast<int>(d->type));
262  } else {
263  //: %1 will be replaced by the type id, %2 will be replaced by the field label
264  error = c->translate("Cutelyst::ValidatorBetween", "The comparison type with ID %1 for the “%2” field is not supported.").arg(QString::number(static_cast<int>(d->type)), _label);
265  }
266  } else if (field == 1) {
267  if (_label.isEmpty()) {
268  error = c->translate("Cutelyst::ValidatorBetween", "The maximum comparison value is not valid.");
269  } else {
270  //: %1 will be replaced by the field label
271  error = c->translate("Cutelyst::ValidatorBetween", "The maximum comparison value for the “%1” field is not valid.").arg(_label);
272  }
273  }
274 
275  return error;
276 }
277 
279 {
280  QString error;
281  Q_UNUSED(errorData)
282  Q_D(const ValidatorBetween);
283 
284  const QString _label = label(c);
285  if ((d->type == QMetaType::Float) || (d->type == QMetaType::Double)) {
286  if (_label.isEmpty()) {
287  error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value into a floating point number.");
288  } else {
289  //: %1 will be replaced by the field label
290  error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value for the “%1” field into a floating point number.").arg(_label);
291  }
292  } else {
293  if (_label.isEmpty()) {
294  error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value into an integer number.");
295  } else {
296  //: %1 will be replaced by the field label
297  error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value for the “%1” field into an integer number.").arg(_label);
298  }
299  }
300 
301  return error;
302 }
QString parsingError(Context *c, const QVariant &errorData=QVariant()) const
Returns an error message if an error occured 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:471
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:447
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.
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
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) 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 ...