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 #ifndef CUTELYSTVALIDATORRULE_P_H
19 #define CUTELYSTVALIDATORRULE_P_H
20 
21 #include "validatorrule.h"
22 #include <QDate>
23 #include <QTime>
24 #include <QDateTime>
25 #include <QTimeZone>
26 #include <QLocale>
27 #include <Cutelyst/Context>
28 #include <limits>
29 
30 namespace Cutelyst {
31 
32 class ValidatorRulePrivate
33 {
Q_DISABLE_COPY(ValidatorRulePrivate)34     Q_DISABLE_COPY(ValidatorRulePrivate)
35 public:
36     ValidatorRulePrivate() {}
37 
ValidatorRulePrivate(const QString & f,const ValidatorMessages & m,const QString & dvk)38     ValidatorRulePrivate(const QString &f, const ValidatorMessages &m, const QString &dvk) :
39         field(f),
40         defValKey(dvk),
41         messages(m)
42     {}
43 
~ValidatorRulePrivate()44     virtual ~ValidatorRulePrivate() {}
45 
46     QDate extractDate(Context *c, const QString &date, const char *format = nullptr) const
47     {
48         QDate d;
49 
50         Q_ASSERT(c);
51 
52         if (format) {
53             const QString _format = translationContext.size() ? c->translate(translationContext.data(), format) : QString::fromUtf8(format);
54             d = QDate::fromString(date, _format);
55             if (d.isValid()) {
56                 return d;
57             }
58             d = c->locale().toDate(date, _format);
59             if (d.isValid()) {
60                 return d;
61             }
62         }
63 
64         for (QLocale::FormatType f : {QLocale::ShortFormat, QLocale::LongFormat}) {
65             d = c->locale().toDate(date, f);
66             if (d.isValid()) {
67                 return d;
68             }
69         }
70 
71         for (Qt::DateFormat f : {Qt::ISODate, Qt::RFC2822Date, Qt::TextDate}) {
72             d = QDate::fromString(date, f);
73             if (d.isValid()) {
74                 return d;
75             }
76         }
77 
78         return d;
79     }
80 
81 
82     QTime extractTime(Context *c, const QString &time, const char *format = nullptr) const
83     {
84         QTime t;
85 
86         Q_ASSERT(c);
87 
88         if (format) {
89             const QString _format = translationContext.size() ? c->translate(translationContext.data(), format) : QString::fromUtf8(format);
90             t = QTime::fromString(time, _format);
91             if (t.isValid()) {
92                 return t;
93             }
94             t = c->locale().toTime(time, _format);
95             if (t.isValid()) {
96                 return t;
97             }
98         }
99 
100         for (QLocale::FormatType f : {QLocale::ShortFormat, QLocale::LongFormat}) {
101             t = c->locale().toTime(time, f);
102             if (t.isValid()) {
103                 return t;
104             }
105         }
106 
107         for (Qt::DateFormat f : {Qt::ISODate, Qt::RFC2822Date, Qt::TextDate}) {
108             t = QTime::fromString(time, f);
109             if (t.isValid()) {
110                 return t;
111             }
112         }
113 
114         return t;
115     }
116 
117 
118     QDateTime extractDateTime(Context *c, const QString &dateTime, const char *format = nullptr, const QTimeZone &tz = QTimeZone()) const
119     {
120         QDateTime dt;
121 
122         Q_ASSERT(c);
123 
124         if (format) {
125             const QString _format = translationContext.size() ? c->translate(translationContext.data(), format) : QString::fromUtf8(format);
126             dt = QDateTime::fromString(dateTime, _format);
127             if (dt.isValid()) {
128                 if (tz.isValid()) {
129                     dt.setTimeZone(tz);
130                 }
131                 return dt;
132             }
133 
134             dt = c->locale().toDateTime(dateTime, _format);
135             if (dt.isValid()) {
136                 if (tz.isValid()) {
137                     dt.setTimeZone(tz);
138                 }
139                 return dt;
140             }
141         }
142 
143         for (QLocale::FormatType f : {QLocale::ShortFormat, QLocale::LongFormat}) {
144             dt = c->locale().toDateTime(dateTime, f);
145             if (dt.isValid()) {
146                 if (tz.isValid()) {
147                     dt.setTimeZone(tz);
148                 }
149                 return dt;
150             }
151         }
152 
153         for (Qt::DateFormat f : {Qt::ISODate, Qt::RFC2822Date, Qt::TextDate}) {
154             dt = QDateTime::fromString(dateTime, f);
155             if (dt.isValid()) {
156                 if (tz.isValid()) {
157                     dt.setTimeZone(tz);
158                 }
159                 return dt;
160             }
161         }
162 
163         return dt;
164     }
165 
166     QVariant extractOtherDateTime(Context *c, const ParamsMultiMap &params, const QString &field, const QTimeZone &tz = QTimeZone(), const char *format = nullptr) const
167     {
168         QVariant var;
169 
170         Q_ASSERT(c);
171 
172         int sepPos = field.indexOf(QLatin1Char('|'));
173         if (sepPos > -1) {
174             const QString fieldName = field.left(sepPos);
175             const QString value = params.value(fieldName);
176             if (!value.isEmpty()) {
177                 const QString type = field.mid(sepPos + 1);
178                 if (type.startsWith(QLatin1String("dt"))) {
179                     QDateTime dt = extractDateTime(c, value, format);
180                     if (dt.isValid()) {
181                         if (tz.isValid()) {
182                             dt.setTimeZone(tz);
183                         }
184                         var = dt;
185                     }
186                 } else if (type.startsWith(QLatin1Char('t'))) {
187                     const QTime t = extractTime(c, value, format);
188                     if (t.isValid()) {
189                         var = t;
190                     }
191                 } else if (type.startsWith(QLatin1Char('d'))) {
192                     const QDate d = extractDate(c, value, format);
193                     if (d.isValid()) {
194                         var = d;
195                     }
196                 }
197             }
198         } else {
199             var = c->stash(field);
200         }
201 
202         return var;
203     }
204 
extractTimeZone(Context * c,const ParamsMultiMap & params,const QString & field)205     static QTimeZone extractTimeZone(Context *c, const ParamsMultiMap &params, const QString &field)
206     {
207         QTimeZone tz;
208 
209         Q_ASSERT(c);
210         Q_UNUSED(params)
211 
212         tz = QTimeZone(field.toLatin1());
213 
214         if (!tz.isValid()) {
215             const QString tzString = params.value(field, c->stash(field).toString());
216 //            const QString tzString = c->stash(field).toString();
217             if (!tzString.isEmpty()) {
218                 tz = QTimeZone(tzString.toLatin1());
219                 if (!tz.isValid()) {
220                     tz = QTimeZone(tzString.toInt());
221                 }
222             }
223         }
224 
225         return tz;
226     }
227 
extractLongLong(Context * c,const ParamsMultiMap & params,const QVariant & value,bool * ok)228     static qlonglong extractLongLong(Context *c, const ParamsMultiMap &params, const QVariant &value, bool *ok)
229     {
230         qlonglong val = 0;
231 
232         Q_ASSERT(c);
233         Q_ASSERT(ok);
234         Q_UNUSED(params)
235 
236         if (value.userType() == QMetaType::QString) {
237             const QString field = value.toString();
238 /*            if (params.contains(field)) {
239                 const QString v = params.value(field);
240                 val = v.toLongLong(ok);
241 //                if (!*ok) {
242 //                    val = c->locale().toLongLong(v, ok);
243 //                }
244             } else */if (c->stash().contains(field)) {
245                 val = c->stash(field).toLongLong(ok);
246             } else {
247                 *ok = false;
248             }
249         } else {
250             val = value.toLongLong(ok);
251         }
252 
253         return val;
254     }
255 
extractULongLong(Context * c,const ParamsMultiMap & params,const QVariant & value,bool * ok)256     static qulonglong extractULongLong(Context *c, const ParamsMultiMap &params, const QVariant &value, bool *ok)
257     {
258         qulonglong val = 0;
259 
260         Q_ASSERT(c);
261         Q_ASSERT(ok);
262         Q_UNUSED(params)
263 
264         if (value.userType() == QMetaType::QString) {
265             const QString field = value.toString();
266 /*            if (params.contains(field)) {
267                 const QString v = params.value(field);
268                 val = v.toULongLong(ok);
269 //                if (!*ok) {
270 //                    val = c->locale().toULongLong(v, ok);
271 //                }
272             } else */if (c->stash().contains(field)) {
273                 val = c->stash(field).toULongLong(ok);
274             } else {
275                 *ok = false;
276             }
277         } else {
278             val = value.toULongLong(ok);
279         }
280 
281         return val;
282     }
283 
extractDouble(Context * c,const ParamsMultiMap & params,const QVariant & value,bool * ok)284     static double extractDouble(Context *c, const ParamsMultiMap &params, const QVariant &value, bool *ok)
285     {
286         double val = 0.0;
287 
288         Q_ASSERT(c);
289         Q_ASSERT(ok);
290         Q_UNUSED(params)
291 
292         if (value.userType() == QMetaType::QString) {
293             const QString field = value.toString();
294 /*            if (params.contains(field)) {
295                 const QString v = params.value(field);
296                 val = v.toDouble(ok);
297 //                if (!*ok) {
298 //                    val = c->locale().toDouble(v, ok);
299 //                }
300             } else*/ if (c->stash().contains(field)) {
301                 val = c->stash(field).toDouble(ok);
302             } else {
303                 *ok = false;
304             }
305         } else {
306             val = value.toDouble(ok);
307         }
308 
309         return val;
310     }
311 
extractInt(Context * c,const ParamsMultiMap & params,const QVariant & value,bool * ok)312     static int extractInt(Context *c, const ParamsMultiMap &params, const QVariant &value, bool *ok)
313     {
314         int val = 0;
315 
316         Q_ASSERT(c);
317         Q_ASSERT(ok);
318         Q_UNUSED(params)
319 
320         if (value.userType() == QMetaType::QString) {
321             const QString field = value.toString();
322 /*            if (params.contains(field)) {
323                 const QString _val = params.value(field);
324                 val = _val.toInt(ok);
325 //                if (!*ok) {
326 //                    val = c->locale().toInt(_val, ok);
327 //                }
328             } else*/ if (c->stash().contains(field)) {
329                 val = c->stash(field).toInt(ok);
330             } else {
331                 *ok = false;
332             }
333         } else {
334             val = value.toInt(ok);
335         }
336 
337         return val;
338     }
339 
valueToNumber(Context * c,const QString & value,QMetaType::Type type)340     static QVariant valueToNumber(Context *c, const QString &value, QMetaType::Type type)
341     {
342         QVariant var;
343 
344         Q_UNUSED(c)
345 
346         bool ok = false;
347 
348         switch (type) {
349         case QMetaType::Char:
350         {
351             const short _v = value.toShort(&ok);
352             if (ok) {
353                 if ((_v < static_cast<short>(std::numeric_limits<char>::max())) && (_v > static_cast<short>(std::numeric_limits<char>::min()))) {
354                     var.setValue<char>(static_cast<char>(_v));
355                 }
356             }
357         }
358             break;
359         case QMetaType::Short:
360         {
361 //            const short v = c->locale().toShort(value, &ok);
362             const short v = value.toShort(&ok);
363             if (ok) {
364                 var.setValue(v);
365             }
366         }
367             break;
368         case QMetaType::Int:
369         {
370 //            const int v = c->locale().toInt(value, &ok);
371             const int v = value.toInt(&ok);
372             if (ok) {
373                 var.setValue(v);
374             }
375         }
376             break;
377         case QMetaType::Long:
378         {
379             const long v = value.toLong(&ok);
380             if (ok) {
381                 var.setValue(v);
382             }
383         }
384             break;
385         case QMetaType::LongLong:
386         {
387 //            const qlonglong v = c->locale().toLongLong(value, &ok);
388 //            if (ok) {
389 //                if (type == QMetaType::Long) {
390 //                    if (v < static_cast<qlonglong>(std::numeric_limits<long>::max())) {
391 //                        var.setValue<long>(static_cast<long>(v));
392 //                    }
393 //                } else {
394 //                    var.setValue<qlonglong>(v);
395 //                }
396 //            }
397             const qlonglong v = value.toLongLong(&ok);
398             if (ok) {
399                 var.setValue(v);
400             }
401         }
402             break;
403         case QMetaType::UChar:
404         {
405             const ushort _v = value.toUShort(&ok);
406             if (ok) {
407                 if ((_v < static_cast<ushort>(std::numeric_limits<uchar>::max())) && (_v > static_cast<ushort>(std::numeric_limits<uchar>::min()))) {
408                     var.setValue<uchar>(static_cast<uchar>(_v));
409                 }
410             }
411         }
412             break;
413         case QMetaType::UShort:
414         {
415 //            const ushort v = c->locale().toUShort(value, &ok);
416             const ushort v = value.toUShort(&ok);
417             if (ok) {
418                 var.setValue(v);
419             }
420         }
421             break;
422         case QMetaType::UInt:
423         {
424 //            const uint v = c->locale().toUInt(value, &ok);
425             const uint v = value.toUInt(&ok);
426             if (ok) {
427                 var.setValue(v);
428             }
429         }
430             break;
431         case QMetaType::ULong:
432         {
433             const ulong v = value.toULong(&ok);
434             if (ok) {
435                 var.setValue(v);
436             }
437         }
438             break;
439         case QMetaType::ULongLong:
440         {
441 //            const qulonglong v = c->locale().toULongLong(value, &ok);
442 //            if (ok) {
443 //                if (type == QMetaType::ULong) {
444 //                    if ((v > static_cast<qulonglong>(std::numeric_limits<ulong>::min())) && (v < static_cast<qulonglong>(std::numeric_limits<ulong>::max()))) {
445 //                        var.setValue<ulong>(static_cast<ulong>(v));
446 //                    }
447 //                } else {
448 //                    var.setValue<qulonglong>(v);
449 //                }
450 //            }
451             const qulonglong v = value.toULongLong(&ok);
452             if (ok) {
453                 var.setValue(v);
454             }
455         }
456             break;
457         case QMetaType::Float:
458         {
459 //            const float v = c->locale().toFloat(value, &ok);
460             const float v = value.toFloat(&ok);
461             if (ok) {
462                 var.setValue(v);
463             }
464         }
465             break;
466         case QMetaType::Double:
467         {
468 //            const double v = c->locale().toDouble(value, &ok);
469             const double v = value.toDouble(&ok);
470             if (ok) {
471                 var.setValue(v);
472             }
473         }
474             break;
475         default:
476             break;
477         }
478 
479         return var;
480     }
481 
482     QLatin1String translationContext;
483     QString field;
484     QString defValKey;
485     ValidatorMessages messages;
486     bool trimBefore = true;
487 };
488 
489 }
490 
491 #endif //CUTELYSTVALIDATORRULE_P_H
492 
493