1 /*
2  * Copyright (C) 2017-2018 Matthias Fehring <kontakt@buschmann23.de>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include "validatorbetween_p.h"
20 
21 using namespace Cutelyst;
22 
ValidatorBetween(const QString & field,QMetaType::Type type,const QVariant & min,const QVariant & max,const ValidatorMessages & messages,const QString & defValKey)23 ValidatorBetween::ValidatorBetween(const QString &field, QMetaType::Type type, const QVariant &min, const QVariant &max, const ValidatorMessages &messages, const QString &defValKey) :
24     ValidatorRule(*new ValidatorBetweenPrivate(field, type, min, max, messages, defValKey))
25 {
26 }
27 
~ValidatorBetween()28 ValidatorBetween::~ValidatorBetween()
29 {
30 }
31 
validate(Context * c,const ParamsMultiMap & params) const32 ValidatorReturnType ValidatorBetween::validate(Context *c, const ParamsMultiMap &params) const
33 {
34     ValidatorReturnType result;
35 
36     const QString v = value(params);
37 
38     Q_D(const ValidatorBetween);
39 
40     if (!v.isEmpty()) {
41         bool ok = false;
42         bool valid = false;
43 
44         switch (d->type) {
45         case QMetaType::Char:
46         case QMetaType::Short:
47         case QMetaType::Int:
48         case QMetaType::Long:
49         case QMetaType::LongLong:
50         {
51             const qlonglong val = c->locale().toLongLong(v, &ok);
52             if (Q_UNLIKELY(!ok)) {
53                 result.errorMessage = parsingError(c);
54                 qCWarning(C_VALIDATOR, "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
55             } else {
56                 const qlonglong min = d->extractLongLong(c, params, d->min, &ok);
57                 if (Q_UNLIKELY(!ok)) {
58                     result.errorMessage = validationDataError(c, -1);
59                     qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
60                 } else {
61                     const qlonglong max = d->extractLongLong(c, params, d->max, &ok);
62                     if (Q_UNLIKELY(!ok)) {
63                         result.errorMessage = validationDataError(c, 1);
64                         qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
65                     } else {
66                         if ((val < min) || (val > max)) {
67                             result.errorMessage = validationError(c, QVariantMap{
68                                                                       {QStringLiteral("val"), val},
69                                                                       {QStringLiteral("min"), min},
70                                                                       {QStringLiteral("max"), max}
71                                                                   });
72                             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);
73                         } else {
74                             valid = true;
75                         }
76                     }
77                 }
78             }
79         }
80             break;
81         case QMetaType::UChar:
82         case QMetaType::UShort:
83         case QMetaType::UInt:
84         case QMetaType::ULong:
85         case QMetaType::ULongLong:
86         {
87             const qulonglong val = v.toULongLong(&ok);
88             if (Q_UNLIKELY(!ok)) {
89                 result.errorMessage = parsingError(c);
90                 qCWarning(C_VALIDATOR, "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
91             } else {
92                 const qulonglong min = d->extractULongLong(c, params, d->min, &ok);
93                 if (Q_UNLIKELY(!ok)) {
94                     result.errorMessage = validationDataError(c, -1);
95                     qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
96                 } else {
97                     const qulonglong max = d->extractULongLong(c, params, d->max, &ok);
98                     if (Q_UNLIKELY(!ok)) {
99                         result.errorMessage = validationDataError(c, 1);
100                         qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
101                     } else {
102                         if ((val < min) || (val > max)) {
103                             result.errorMessage = validationError(c, QVariantMap{
104                                                                       {QStringLiteral("val"), val},
105                                                                       {QStringLiteral("min"), min},
106                                                                       {QStringLiteral("max"), max}
107                                                                   });
108                             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);
109                         } else {
110                             valid = true;
111                         }
112                     }
113                 }
114             }
115         }
116             break;
117         case QMetaType::Float:
118         case QMetaType::Double:
119         {
120             const double val = v.toDouble(&ok);
121             if (Q_UNLIKELY(!ok)) {
122                 result.errorMessage = parsingError(c);
123                 qCWarning(C_VALIDATOR, "ValidatorBetween: Failed to parse value of field %s into number at %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
124             } else {
125                 const double min = d->extractDouble(c, params, d->min, &ok);
126                 if (Q_UNLIKELY(!ok)) {
127                     result.errorMessage = validationDataError(c, -1);
128                     qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
129                 } else {
130                     const double max = d->extractDouble(c, params, d->max, &ok);
131                     if (Q_UNLIKELY(!ok)) {
132                         result.errorMessage = validationDataError(c, 1);
133                         qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
134                     } else {
135                         if ((val < min) || (val > max)) {
136                             result.errorMessage = validationError(c, QVariantMap{
137                                                                       {QStringLiteral("val"), val},
138                                                                       {QStringLiteral("min"), min},
139                                                                       {QStringLiteral("max"), max}
140                                                                   });
141                             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);
142                         } else {
143                             valid = true;
144                         }
145                     }
146                 }
147             }
148         }
149             break;
150         case QMetaType::QString:
151         {
152             const qlonglong val = static_cast<qlonglong>(v.length());
153             const qlonglong min = d->extractLongLong(c, params, d->min, &ok);
154             if (Q_UNLIKELY(!ok)) {
155                 result.errorMessage = validationDataError(c, -1);
156                 qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid minimum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
157             } else {
158                 const qlonglong max = d->extractLongLong(c, params, d->max, &ok);
159                 if (Q_UNLIKELY(!ok)) {
160                     result.errorMessage = validationDataError(c, 1);
161                     qCWarning(C_VALIDATOR, "ValidatorBetween: Invalid maximum comparison value for field %s in %s::%s.", qPrintable(field()), qPrintable(c->controllerName()), qPrintable(c->actionName()));
162                 } else {
163                     if ((val < min) || (val > max)) {
164                         result.errorMessage = validationError(c, QVariantMap{
165                                                                   {QStringLiteral("val"), val},
166                                                                   {QStringLiteral("min"), min},
167                                                                   {QStringLiteral("max"), max}
168                                                               });
169                         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);
170                     } else {
171                         valid = true;
172                     }
173                 }
174             }
175         }
176             break;
177         default:
178             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()));
179             result.errorMessage = validationDataError(c, 0);
180             break;
181         }
182 
183         if (valid) {
184             if (d->type != QMetaType::QString) {
185                 const QVariant _v = d->valueToNumber(c, v, d->type);
186                 if (_v.isValid()) {
187                     result.value = _v;
188                 } else {
189                     result.errorMessage = parsingError(c);
190                 }
191             } else {
192                 result.value.setValue(v);
193             }
194         }
195     } else {
196         defaultValue(c, &result, "ValidatorBetween");
197     }
198 
199     return result;
200 }
201 
genericValidationError(Cutelyst::Context * c,const QVariant & errorData) const202 QString ValidatorBetween::genericValidationError(Cutelyst::Context *c, const QVariant &errorData) const
203 {
204     QString error;
205 
206     Q_D(const ValidatorBetween);
207 
208     const QVariantMap map = errorData.toMap();
209     QString min, max;
210     switch (d->type) {
211     case QMetaType::Char:
212     case QMetaType::Short:
213     case QMetaType::Int:
214     case QMetaType::Long:
215     case QMetaType::LongLong:
216     case QMetaType::QString:
217         min = c->locale().toString(map.value(QStringLiteral("min")).toLongLong());
218         max = c->locale().toString(map.value(QStringLiteral("max")).toLongLong());
219         break;
220     case QMetaType::UChar:
221     case QMetaType::UShort:
222     case QMetaType::UInt:
223     case QMetaType::ULong:
224     case QMetaType::ULongLong:
225         min = c->locale().toString(map.value(QStringLiteral("min")).toULongLong());
226         max = c->locale().toString(map.value(QStringLiteral("max")).toULongLong());
227         break;
228     case QMetaType::Float:
229     case QMetaType::Double:
230         min = c->locale().toString(map.value(QStringLiteral("min")).toDouble());
231         max = c->locale().toString(map.value(QStringLiteral("max")).toDouble());
232         break;
233     default:
234         error = validationDataError(c);
235         return error;
236     }
237 
238     const QString _label = label(c);
239 
240     if (_label.isEmpty()) {
241         if (d->type == QMetaType::QString) {
242             error = c->translate("Cutelyst::ValidatorBetween", "The text must be between %1 and %2 characters long.").arg(min, max);
243         } else {
244             error = c->translate("Cutelyst::ValidatorBetween", "The value must be between %1 and %2.").arg(min, max);
245         }
246     } else {
247         if (d->type == QMetaType::QString) {
248             error = c->translate("Cutelyst::ValidatorBetween", "The text in the “%1“ field must be between %2 and %3 characters long.").arg(_label, min, max);
249         } else {
250             error = c->translate("Cutelyst::ValidatorBetween", "The value in the “%1” field must be between %2 and %3.").arg(_label, min, max);
251         }
252     }
253 
254     return error;
255 }
256 
genericValidationDataError(Context * c,const QVariant & errorData) const257 QString ValidatorBetween::genericValidationDataError(Context *c, const QVariant &errorData) const
258 {
259     QString error;
260 
261     int field = errorData.toInt();
262     const QString _label = label(c);
263 
264     if (field == -1) {
265         if (_label.isEmpty()) {
266             error = c->translate("Cutelyst::ValidatorBetween", "The minimum comparison value is not valid.");
267         } else {
268             //: %1 will be replaced by the field label
269             error = c->translate("Cutelyst::ValidatorBetween", "The minimum comparison value for the “%1” field is not valid.").arg(_label);
270         }
271     } else if (field == 0) {
272         Q_D(const ValidatorBetween);
273         if (_label.isEmpty()) {
274             error = c->translate("Cutelyst::ValidatorBetween", "The comparison type with ID %1 is not supported.").arg(static_cast<int>(d->type));
275         } else {
276             //: %1 will be replaced by the type id, %2 will be replaced by the field label
277             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);
278         }
279     } else if (field == 1) {
280         if (_label.isEmpty()) {
281             error = c->translate("Cutelyst::ValidatorBetween", "The maximum comparison value is not valid.");
282         } else {
283             //: %1 will be replaced by the field label
284             error = c->translate("Cutelyst::ValidatorBetween", "The maximum comparison value for the “%1” field is not valid.").arg(_label);
285         }
286     }
287 
288     return error;
289 }
290 
genericParsingError(Context * c,const QVariant & errorData) const291 QString ValidatorBetween::genericParsingError(Context *c, const QVariant &errorData) const
292 {
293     QString error;
294     Q_UNUSED(errorData)
295     Q_D(const ValidatorBetween);
296 
297     const QString _label = label(c);
298     if ((d->type == QMetaType::Float) || (d->type == QMetaType::Double)) {
299         if (_label.isEmpty()) {
300             error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value into a floating point number.");
301         } else {
302             //: %1 will be replaced by the field label
303             error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value for the “%1” field into a floating point number.").arg(_label);
304         }
305     } else {
306         if (_label.isEmpty()) {
307             error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value into an integer number.");
308         } else {
309             //: %1 will be replaced by the field label
310             error = c->translate("Cutelyst::ValidatorBetween", "Failed to parse the input value for the “%1” field into an integer number.").arg(_label);
311         }
312     }
313 
314     return error;
315 }
316