Warning, file /pim/kitinerary/src/lib/extractorvalidator.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "extractorvalidator.h" 0008 #include "validator-logging.h" 0009 0010 #include <KItinerary/BoatTrip> 0011 #include <KItinerary/BusTrip> 0012 #include <KItinerary/Event> 0013 #include <KItinerary/Flight> 0014 #include <KItinerary/Place> 0015 #include <KItinerary/ProgramMembership> 0016 #include <KItinerary/RentalCar> 0017 #include <KItinerary/Reservation> 0018 #include <KItinerary/Taxi> 0019 #include <KItinerary/Ticket> 0020 #include <KItinerary/TrainTrip> 0021 #include <KItinerary/Visit> 0022 0023 #include <QDateTime> 0024 0025 using namespace KItinerary; 0026 0027 namespace KItinerary { 0028 class ExtractorValidatorPrivate { 0029 public: 0030 bool isSupportedTopLevelType(const QVariant &elem) const; 0031 bool filterElement(const QVariant &elem) const; 0032 0033 bool filterLodgingReservation(const LodgingReservation &res) const; 0034 bool filterAirport(const Airport &airport) const; 0035 bool filterFlight(const Flight &flight) const; 0036 bool filterTrainTrip(const TrainTrip &trip) const; 0037 bool filterBusTrip(const BusTrip &trip) const; 0038 bool filterBoatTrip(const BoatTrip &trip) const; 0039 bool filterEvent(const Event &event) const; 0040 bool filterFoodReservation(const FoodEstablishmentReservation &res) const; 0041 bool filterLocalBusiness(const LocalBusiness &business) const; 0042 bool filterReservation(const Reservation &res) const; 0043 bool filterProgramMembership(const ProgramMembership &program) const; 0044 bool filterTicket(const Ticket &ticket) const; 0045 0046 std::vector<const QMetaObject*> m_acceptedTypes; 0047 bool m_onlyComplete = true; 0048 }; 0049 } 0050 0051 ExtractorValidator::ExtractorValidator() : 0052 d(new ExtractorValidatorPrivate) 0053 {} 0054 0055 ExtractorValidator::~ExtractorValidator() = default; 0056 0057 void ExtractorValidator::setAcceptedTypes(std::vector<const QMetaObject*> &&accptedTypes) 0058 { 0059 d->m_acceptedTypes = std::move(accptedTypes); 0060 } 0061 0062 void ExtractorValidator::setAcceptOnlyCompleteElements(bool completeOnly) 0063 { 0064 d->m_onlyComplete = completeOnly; 0065 } 0066 0067 0068 bool ExtractorValidatorPrivate::filterLodgingReservation(const LodgingReservation &res) const 0069 { 0070 return res.checkinTime().isValid() && res.checkoutTime().isValid() && res.checkinTime() <= res.checkoutTime(); 0071 } 0072 0073 bool ExtractorValidatorPrivate::filterAirport(const Airport &airport) const 0074 { 0075 return !airport.iataCode().isEmpty() || !airport.name().isEmpty(); 0076 } 0077 0078 bool ExtractorValidatorPrivate::filterFlight(const Flight &flight) const 0079 { 0080 // this will be valid if either boarding time, departure time or departure day is set 0081 const auto validDate = flight.departureDay().isValid(); 0082 return filterAirport(flight.departureAirport()) 0083 && filterAirport(flight.arrivalAirport()) 0084 && validDate; 0085 } 0086 0087 template <typename T> 0088 static bool filterPlace(const T &place) 0089 { 0090 return !place.name().isEmpty(); 0091 } 0092 0093 bool ExtractorValidatorPrivate::filterTrainTrip(const TrainTrip &trip) const 0094 { 0095 return filterPlace(trip.departureStation()) 0096 && filterPlace(trip.arrivalStation()) 0097 && trip.departureDay().isValid(); 0098 } 0099 0100 bool ExtractorValidatorPrivate::filterBusTrip(const BusTrip &trip) const 0101 { 0102 return filterPlace(trip.departureBusStop()) 0103 && filterPlace(trip.arrivalBusStop()) 0104 && trip.departureTime().isValid(); 0105 } 0106 0107 bool ExtractorValidatorPrivate::filterBoatTrip(const BoatTrip &trip) const 0108 { 0109 return filterPlace(trip.departureBoatTerminal()) 0110 && filterPlace(trip.arrivalBoatTerminal()) 0111 && trip.departureTime().isValid() 0112 && trip.arrivalTime().isValid(); 0113 } 0114 0115 bool ExtractorValidatorPrivate::filterEvent(const Event &event) const 0116 { 0117 return !event.name().isEmpty() && event.startDate().isValid(); 0118 } 0119 0120 bool ExtractorValidatorPrivate::filterFoodReservation(const FoodEstablishmentReservation &res) const 0121 { 0122 return res.startTime().isValid(); 0123 } 0124 0125 bool ExtractorValidatorPrivate::filterLocalBusiness(const LocalBusiness &business) const 0126 { 0127 return !business.name().isEmpty(); 0128 } 0129 0130 bool ExtractorValidatorPrivate::filterReservation(const Reservation &res) const 0131 { 0132 if (!m_onlyComplete) { // accept minimal cancellation elements 0133 if (res.reservationFor().isNull() 0134 && res.modifiedTime().isValid() 0135 && !res.reservationNumber().isEmpty() 0136 && res.reservationStatus() == Reservation::ReservationCancelled) 0137 { 0138 return true; 0139 } 0140 } 0141 0142 if (!filterElement(res.reservationFor())) { 0143 qCDebug(ValidatorLog) << "Reservation element discarded due to rejected reservationFor property:" << res.reservationFor().typeName(); 0144 return false; 0145 } 0146 return true; 0147 } 0148 0149 bool ExtractorValidatorPrivate::filterProgramMembership(const ProgramMembership &program) const 0150 { 0151 return (!program.membershipNumber().isEmpty() || !program.token().isEmpty()) && !program.programName().isEmpty(); 0152 } 0153 0154 bool ExtractorValidatorPrivate::filterTicket(const Ticket &ticket) const 0155 { 0156 return !ticket.ticketToken().isEmpty() && !ticket.name().isEmpty(); 0157 } 0158 0159 template <typename T, bool (ExtractorValidatorPrivate::*F)(const T&) const> 0160 static inline bool callFilterWithType(const ExtractorValidatorPrivate *d, const QVariant &v) 0161 { 0162 // JsonLd::canConvert<T>(v) is guaranteed by walking up the meta object tree here 0163 return (d->*F)(JsonLd::convert<T>(v)); 0164 } 0165 0166 #define FILTER(Type, Func) { &Type::staticMetaObject, callFilterWithType<Type, &ExtractorValidatorPrivate::Func> } 0167 struct { 0168 const QMetaObject *metaObject; 0169 bool (*filter)(const ExtractorValidatorPrivate *d, const QVariant &v); 0170 } static const filter_func_map[] { 0171 FILTER(Flight, filterFlight), 0172 FILTER(TrainTrip, filterTrainTrip), 0173 FILTER(BusTrip, filterBusTrip), 0174 FILTER(BoatTrip, filterBoatTrip), 0175 FILTER(KItinerary::Event, filterEvent), 0176 FILTER(LocalBusiness, filterLocalBusiness), 0177 FILTER(FoodEstablishmentReservation, filterFoodReservation), 0178 FILTER(LodgingReservation, filterLodgingReservation), 0179 FILTER(Reservation, filterReservation), 0180 FILTER(ProgramMembership, filterProgramMembership), 0181 FILTER(Ticket, filterTicket), 0182 }; 0183 #undef FILTER 0184 0185 bool ExtractorValidatorPrivate::filterElement(const QVariant &elem) const 0186 { 0187 auto mo = QMetaType(elem.userType()).metaObject(); 0188 if (!mo) { 0189 qCDebug(ValidatorLog) << "Element discarded due to non-gadget type:" << elem.typeName(); 0190 return false; 0191 } 0192 while (mo) { 0193 for (const auto &f : filter_func_map) { 0194 if (f.metaObject != mo) { 0195 continue; 0196 } 0197 if (!f.filter(this, elem)) { 0198 return false; 0199 } 0200 break; 0201 } 0202 mo = mo->superClass(); 0203 } 0204 return true; 0205 } 0206 0207 bool ExtractorValidatorPrivate::isSupportedTopLevelType(const QVariant &elem) const 0208 { 0209 if (m_acceptedTypes.empty()) { // nothing configured, we accept everything 0210 return true; 0211 } 0212 0213 auto mo = QMetaType(elem.userType()).metaObject(); 0214 if (!mo) { 0215 qCDebug(ValidatorLog) << "Element discarded due to non-gadget top-level type:" << elem.typeName(); 0216 return false; 0217 } 0218 while (mo) { 0219 const auto it = std::find(m_acceptedTypes.begin(), m_acceptedTypes.end(), mo); 0220 if (it != m_acceptedTypes.end()) { 0221 return true; 0222 } 0223 mo = mo->superClass(); 0224 } 0225 return false; 0226 } 0227 0228 bool ExtractorValidator::isValidElement(const QVariant &elem) const 0229 { 0230 // check this is an allowed top-level type 0231 if (!d->isSupportedTopLevelType(elem)) { 0232 qCDebug(ValidatorLog) << "Element discarded due to unsupported top-level type:" << elem.typeName(); 0233 return false; 0234 } 0235 0236 // apply type-specific filter functions 0237 return d->filterElement(elem); 0238 }