LCOV - code coverage report
Current view: top level - core/db - SPDbField.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 266 481 55.3 %
Date: 2024-05-12 00:16:13 Functions: 19 32 59.4 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPDbField.h"
      25             : #include "SPMemUuid.h"
      26             : #include "SPString.h"
      27             : #include "SPValid.h"
      28             : #include "SPCrypto.h"
      29             : #include "SPDbScheme.h"
      30             : 
      31             : #ifdef _MSC_VER
      32             : #define strncasecmp _strnicmp
      33             : #define strcasecmp _stricmp
      34             : #endif
      35             : 
      36             : namespace STAPPLER_VERSIONIZED stappler::db {
      37             : 
      38          75 : AutoFieldScheme::AutoFieldScheme(const Scheme &s, ReqVec &&vec, ViewLinkageFn &&fn, ReqVec &&lvec)
      39          75 : : scheme(s), requiresForAuto(std::move(vec)), linkage(std::move(fn)), requiresForLinking(std::move(lvec)) { }
      40             : 
      41           0 : AutoFieldScheme::AutoFieldScheme(const Scheme &s, ReqVec &&vec, ReqVec &&lvec)
      42           0 : : scheme(s), requiresForAuto(std::move(vec)), linkage(nullptr), requiresForLinking(std::move(lvec)) { }
      43             : 
      44       37375 : bool Field::Slot::isProtected() const {
      45       37375 :         return hasFlag(Flags::Protected) || hasFlag(Flags::Admin);
      46             : }
      47             : 
      48         975 : bool Field::isReference() const {
      49         975 :         if (slot->type == Type::Object || slot->type == Type::Set) {
      50         975 :                 auto ref = static_cast<const FieldObject *>(slot);
      51         975 :                 return ref->onRemove == RemovePolicy::Reference || ref->onRemove == RemovePolicy::StrongReference;
      52             :         }
      53           0 :         return false;
      54             : }
      55             : 
      56       28625 : const Scheme * Field::getForeignScheme() const {
      57       28625 :         if (slot->type == Type::Object || slot->type == Type::Set) {
      58         675 :                 auto ref = static_cast<const FieldObject *>(slot);
      59         675 :                 return ref->scheme;
      60       27950 :         } else if (slot->type == Type::View) {
      61         150 :                 auto ref = static_cast<const FieldView *>(slot);
      62         150 :                 return ref->scheme;
      63             :         }
      64       27800 :         return nullptr;
      65             : }
      66             : 
      67         475 : bool Field::transform(const Scheme &scheme, int64_t id, Value &val, bool isCreate) const {
      68         475 :         return transform(scheme, Value(id), val, isCreate);
      69             : }
      70             : 
      71       44275 : bool Field::transform(const Scheme &scheme, const Value &obj, Value &val, bool isCreate) const {
      72       44275 :         if (slot->writeFilterFn) {
      73          25 :                 if (!slot->writeFilterFn(scheme, obj, val, isCreate)) {
      74           0 :                         return false;
      75             :                 }
      76             :         }
      77       44275 :         if (slot->transformValue(scheme, obj, val, isCreate)) {
      78       41775 :                 return true;
      79             :         }
      80        2500 :         return false;
      81             : }
      82             : 
      83        3300 : Value Field::getTypeDesc() const {
      84        3300 :         Value ret;
      85        3300 :         if (slot->flags != Flags::None) {
      86        1050 :                 auto &f = ret.emplace("flags");
      87        1050 :                 if ((slot->flags & Flags::Required) != Flags::None) { f.addString("required"); }
      88        1050 :                 if ((slot->flags & Flags::Protected) != Flags::None) { f.addString("protected"); }
      89        1050 :                 if ((slot->flags & Flags::ReadOnly) != Flags::None) { f.addString("readonly"); }
      90        1050 :                 if ((slot->flags & Flags::Reference) != Flags::None) { f.addString("reference"); }
      91        1050 :                 if ((slot->flags & Flags::Unique) != Flags::None) { f.addString("unique"); }
      92        1050 :                 if ((slot->flags & Flags::AutoCTime) != Flags::None) { f.addString("auto-ctime"); }
      93        1050 :                 if ((slot->flags & Flags::AutoMTime) != Flags::None) { f.addString("auto-mtime"); }
      94        1050 :                 if ((slot->flags & Flags::AutoUser) != Flags::None) { f.addString("auto-user"); }
      95        1050 :                 if ((slot->flags & Flags::Indexed) != Flags::None) { f.addString("indexed"); }
      96        1050 :                 if ((slot->flags & Flags::Admin) != Flags::None) { f.addString("admin"); }
      97        1050 :                 if ((slot->flags & Flags::ForceInclude) != Flags::None) { f.addString("forceinclude"); }
      98             :         }
      99             : 
     100        3300 :         if (slot->transform != Transform::None) {
     101         400 :                 switch (slot->transform) {
     102           0 :                 case Transform::Text: ret.setString("text", "transform"); break;
     103          25 :                 case Transform::Identifier: ret.setString("identifier", "transform"); break;
     104         125 :                 case Transform::Alias: ret.setString("alias", "transform"); break;
     105          25 :                 case Transform::Url: ret.setString("url", "transform"); break;
     106         100 :                 case Transform::Email: ret.setString("email", "transform"); break;
     107           0 :                 case Transform::Number: ret.setString("number", "transform"); break;
     108           0 :                 case Transform::Hexadecimial: ret.setString("hexadecimal", "transform"); break;
     109           0 :                 case Transform::Base64: ret.setString("base64", "transform"); break;
     110           0 :                 case Transform::Uuid: ret.setString("uuid", "transform"); break;
     111          50 :                 case Transform::PublicKey: ret.setString("publickey", "transform"); break;
     112          50 :                 case Transform::Password: ret.setString("password", "transform"); break;
     113          25 :                 default: break;
     114             :                 }
     115             :         }
     116             : 
     117        3300 :         if (slot->defaultFn) {
     118          25 :                 ret.setString("(functional)", "default");
     119        3275 :         } else if (slot->def) {
     120         100 :                 ret.setValue(slot->def, "default");
     121             :         }
     122             : 
     123        3300 :         switch (slot->type) {
     124           0 :         case Type::None: ret.setString("none", "type"); break;
     125         700 :         case Type::Integer: ret.setString("integer", "type"); break;
     126          25 :         case Type::Float: ret.setString("float", "type"); break;
     127         150 :         case Type::Boolean: ret.setString("boolean", "type"); break;
     128         900 :         case Type::Text:
     129         900 :                 ret.setString("text", "type");
     130         900 :                 if (auto t = static_cast<const FieldText *>(slot)) {
     131         900 :                         ret.setInteger(t->minLength, "min");
     132         900 :                         ret.setInteger(t->maxLength, "max");
     133             :                 }
     134         900 :                 break;
     135         150 :         case Type::Bytes:
     136         150 :                 ret.setString("bytes", "type");
     137         150 :                 if (auto t = static_cast<const FieldText *>(slot)) {
     138         150 :                         ret.setInteger(t->minLength, "min");
     139         150 :                         ret.setInteger(t->maxLength, "max");
     140             :                 }
     141         150 :                 break;
     142         250 :         case Type::Data: ret.setString("data", "type"); break;
     143         225 :         case Type::Extra:
     144         225 :                 ret.setString("extra", "type");
     145         225 :                 if (auto e = static_cast<const FieldExtra *>(slot)) {
     146         225 :                         auto &f = ret.emplace("fields");
     147         775 :                         for (auto &it : e->fields) {
     148         550 :                                 f.setValue(it.second.getTypeDesc(), it.first);
     149             :                         }
     150             :                 }
     151         225 :                 break;
     152         175 :         case Type::Object:
     153         175 :                 ret.setString("object", "type");
     154         175 :                 if (auto o = static_cast<const FieldObject *>(slot)) {
     155         175 :                         if (o->scheme) {
     156         175 :                                 ret.setString(o->scheme->getName(), "scheme");
     157             :                         }
     158         175 :                         switch (o->onRemove) {
     159          25 :                         case RemovePolicy::Cascade: ret.setString("cascade", "onRemove"); break;
     160           0 :                         case RemovePolicy::Restrict: ret.setString("cascade", "onRemove"); break;
     161           0 :                         case RemovePolicy::Reference: ret.setString("reference", "onRemove"); break;
     162          25 :                         case RemovePolicy::StrongReference: ret.setString("strongReference", "onRemove"); break;
     163         125 :                         case RemovePolicy::Null: ret.setString("null", "onRemove"); break;
     164             :                         }
     165             : 
     166         175 :                         switch (o->linkage) {
     167         150 :                         case Linkage::Auto: ret.setString("auto", "linkage"); break;
     168          25 :                         case Linkage::Manual: ret.setString("manual", "linkage"); break;
     169           0 :                         case Linkage::None: ret.setString("none", "linkage"); break;
     170             :                         }
     171             :                 }
     172         175 :                 break;
     173         150 :         case Type::Set:
     174         150 :                 ret.setString("set", "type");
     175         150 :                 if (auto o = static_cast<const FieldObject *>(slot)) {
     176         150 :                         if (o->scheme) {
     177         150 :                                 ret.setString(o->scheme->getName(), "scheme");
     178             :                         }
     179         150 :                         switch (o->onRemove) {
     180           0 :                         case RemovePolicy::Cascade: ret.setString("cascade", "onRemove"); break;
     181           0 :                         case RemovePolicy::Restrict: ret.setString("cascade", "onRemove"); break;
     182          25 :                         case RemovePolicy::Reference: ret.setString("reference", "onRemove"); break;
     183          50 :                         case RemovePolicy::StrongReference: ret.setString("strongReference", "onRemove"); break;
     184          75 :                         case RemovePolicy::Null: ret.setString("null", "onRemove"); break;
     185             :                         }
     186             : 
     187         150 :                         switch (o->linkage) {
     188         125 :                         case Linkage::Auto: ret.setString("auto", "linkage"); break;
     189          25 :                         case Linkage::Manual: ret.setString("manual", "linkage"); break;
     190           0 :                         case Linkage::None: ret.setString("none", "linkage"); break;
     191             :                         }
     192             :                 }
     193         150 :                 break;
     194         100 :         case Type::Array:
     195         100 :                 ret.setString("array", "type");
     196         100 :                 if (auto a = static_cast<const FieldArray *>(slot)) {
     197         100 :                         ret.setValue(a->tfield.getTypeDesc(), "field");
     198             :                 }
     199         100 :                 break;
     200          75 :         case Type::File:
     201          75 :                 ret.setString("file", "type");
     202          75 :                 if (auto f = static_cast<const FieldFile *>(slot)) {
     203          75 :                         ret.setInteger(f->maxSize, "maxFileSize");
     204          75 :                         if (!f->allowedTypes.empty()) {
     205           0 :                                 auto &t = ret.emplace("allowed");
     206           0 :                                 for (auto &it : f->allowedTypes) {
     207           0 :                                         t.addString(it);
     208             :                                 }
     209             :                         }
     210             :                 }
     211          75 :                 break;
     212         200 :         case Type::Image:
     213         200 :                 if (auto f = static_cast<const FieldImage *>(slot)) {
     214         200 :                         if (f->primary) {
     215          50 :                                 ret.setString("image", "type");
     216          50 :                                 ret.setInteger(f->maxSize, "maxFileSize");
     217          50 :                                 if (!f->allowedTypes.empty()) {
     218           0 :                                         auto &t = ret.emplace("allowed");
     219           0 :                                         for (auto &it : f->allowedTypes) {
     220           0 :                                                 t.addString(it);
     221             :                                         }
     222             :                                 }
     223             : 
     224          50 :                                 auto &min = ret.emplace("minImageSize");
     225          50 :                                 min.setInteger(f->minImageSize.width, "width");
     226          50 :                                 min.setInteger(f->minImageSize.width, "height");
     227          50 :                                 switch (f->minImageSize.policy) {
     228           0 :                                 case ImagePolicy::Resize: min.setString("resize", "policy"); break;
     229          50 :                                 case ImagePolicy::Reject: min.setString("resize", "policy"); break;
     230             :                                 }
     231             : 
     232          50 :                                 auto &max = ret.emplace("maxImageSize");
     233          50 :                                 max.setInteger(f->maxImageSize.width, "width");
     234          50 :                                 max.setInteger(f->maxImageSize.width, "height");
     235          50 :                                 switch (f->maxImageSize.policy) {
     236          50 :                                 case ImagePolicy::Resize: max.setString("resize", "policy"); break;
     237           0 :                                 case ImagePolicy::Reject: max.setString("resize", "policy"); break;
     238             :                                 }
     239             : 
     240          50 :                                 if (!f->thumbnails.empty()) {
     241          50 :                                         auto &t = ret.emplace("thumbnails");
     242         200 :                                         for (auto &it : f->thumbnails) {
     243         150 :                                                 auto &tb = t.emplace(it.name);
     244         150 :                                                 tb.setInteger(it.width, "width");
     245         150 :                                                 tb.setInteger(it.height, "height");
     246             :                                         }
     247             :                                 }
     248             :                         }
     249             :                 }
     250         200 :                 break;
     251          50 :         case Type::View:
     252          50 :                 ret.setString("view", "type");
     253          50 :                 if (auto v = static_cast<const FieldView *>(slot)) {
     254          50 :                         if (v->scheme) {
     255          50 :                                 ret.setString(v->scheme->getName(), "scheme");
     256             :                         }
     257             : 
     258          50 :                         if (!v->requireFields.empty()) {
     259          25 :                                 auto &f = ret.emplace("requires");
     260          50 :                                 for (auto &it : v->requireFields) {
     261          25 :                                         f.addString(it);
     262             :                                 }
     263             :                         }
     264             : 
     265          50 :                         if (v->delta) {
     266          25 :                                 ret.setBool(true, "delta");
     267             :                         }
     268             :                 }
     269          50 :                 break;
     270         150 :         default: break;
     271             :         }
     272             : 
     273        3300 :         if (!slot->documentation.empty()) {
     274           0 :                 ret.setString(slot->documentation, "documentation");
     275             :         }
     276             : 
     277        3300 :         return ret;
     278           0 : }
     279             : 
     280       42200 : bool Field::Slot::hasDefault() const {
     281       42200 :         return defaultFn || !def.isNull() || (transform == Transform::Uuid && type == Type::Bytes);
     282             : }
     283             : 
     284         250 : Value Field::Slot::getDefault(const Value &patch) const {
     285         250 :         if (defaultFn) {
     286          75 :                 return defaultFn(patch);
     287         175 :         } else if (transform == Transform::Uuid && type == Type::Bytes) {
     288           0 :                 return Value(stappler::memory::uuid::generate().bytes());
     289             :         } else {
     290         175 :                 return def;
     291             :         }
     292             : }
     293             : 
     294       20575 : bool Field::Slot::transformValue(const Scheme &scheme, const Value &obj, Value &val, bool isCreate) const {
     295       20575 :         if (!val.isBasicType() && type != Type::Data) {
     296           0 :                 return false;
     297             :         }
     298             : 
     299       20575 :         switch (type) {
     300        4575 :         case Type::Data: break;
     301       10625 :         case Type::Integer: val.setInteger(val.asInteger()); break;
     302        2500 :         case Type::Float: val.setDouble(val.asDouble()); break;
     303        2875 :         case Type::Boolean:
     304        2875 :                 if (val.isString()) {
     305           0 :                         auto &str = val.getString();
     306           0 :                         if (str == "1" || str == "on" || str == "true") {
     307           0 :                                 val.setBool(true);
     308             :                         } else {
     309           0 :                                 val.setBool(false);
     310             :                         }
     311             :                 } else {
     312        2875 :                         val.setBool(val.asBool());
     313             :                 }
     314        2875 :                 break;
     315           0 :         case Type::Object:
     316           0 :                 if (val.isBasicType()) {
     317           0 :                         val.setInteger(val.asInteger());
     318             :                 } else {
     319           0 :                         return false;
     320             :                 }
     321           0 :                 break;
     322           0 :         case Type::Set:
     323           0 :                 if (!val.isArray()) {
     324           0 :                         return false;
     325             :                 }
     326           0 :                 break;
     327           0 :         case Type::File:
     328             :         case Type::Image:
     329           0 :                 if (val.isInteger()) {
     330           0 :                         return true;
     331             :                 }
     332           0 :                 break;
     333           0 :         default:
     334           0 :                 return false;
     335             :                 break;
     336             :         }
     337             : 
     338       20575 :         return true;
     339             : }
     340             : 
     341           0 : void Field::Slot::hash(StringStream &stream, ValidationLevel l) const {
     342           0 :         if (l == ValidationLevel::NamesAndTypes) {
     343           0 :                 stream << name << stappler::toInt(type);
     344             :         } else {
     345           0 :                 stream << name << stappler::toInt(flags) << stappler::toInt(type) << stappler::toInt(transform);
     346             :         }
     347           0 : }
     348             : 
     349       10325 : bool FieldText::transformValue(const Scheme &scheme, const Value &obj, Value &val, bool isCreate) const {
     350       10325 :         switch (type) {
     351        7850 :         case Type::Text: {
     352        7850 :                 if (!val.isBasicType()) {
     353           0 :                         return false;
     354             :                 }
     355        7850 :                 if (!val.isString()) {
     356         100 :                         if (val.isBool()) {
     357           0 :                                 val.setValue(Value());
     358           0 :                                 return true;
     359             :                         } else {
     360         100 :                                 val.setString(val.asString());
     361             :                         }
     362             :                 }
     363        7850 :                 if (val.isString()) {
     364        7850 :                         auto &str = val.getString();
     365        7850 :                         if (str.size() < minLength || str.size() > maxLength) {
     366          75 :                                 if (str.size() == 0) {
     367          50 :                                         val.setValue(Value());
     368          50 :                                         return true;
     369             :                                 }
     370          25 :                                 return false;
     371             :                         }
     372             :                 }
     373        7775 :                 auto &str = val.getString();
     374        7775 :                 if (str.empty()) {
     375           0 :                         if (minLength == 0) {
     376           0 :                                 return true;
     377             :                         } else {
     378           0 :                                 val.setValue(Value());
     379           0 :                                 return true;
     380             :                         }
     381             :                 }
     382        7775 :                 switch (transform) {
     383        5100 :                 case Transform::None:
     384             :                 case Transform::Text:
     385        5100 :                         if ( !stappler::valid::validateText(str)) {
     386           0 :                                 return false;
     387             :                         }
     388        5100 :                         break;
     389        2650 :                 case Transform::Identifier:
     390             :                 case Transform::Alias:
     391        2650 :                         if (!stappler::valid::validateIdentifier(str)) {
     392           0 :                                 return false;
     393             :                         }
     394        2650 :                         break;
     395          25 :                 case Transform::Url:
     396          25 :                         if (!stappler::valid::validateUrl(str)) {
     397           0 :                                 return false;
     398             :                         }
     399          25 :                         break;
     400           0 :                 case Transform::Email:
     401           0 :                         if (!stappler::valid::validateEmail(str)) {
     402           0 :                                 return false;
     403             :                         }
     404           0 :                         break;
     405           0 :                 case Transform::Number:
     406           0 :                         if (!stappler::valid::validateNumber(str)) {
     407           0 :                                 return false;
     408             :                         }
     409           0 :                         break;
     410           0 :                 case Transform::Hexadecimial:
     411           0 :                         if (!stappler::valid::validateHexadecimial(str)) {
     412           0 :                                 return false;
     413             :                         }
     414           0 :                         break;
     415           0 :                 case Transform::Base64:
     416           0 :                         if (!stappler::valid::validateBase64(str)) {
     417           0 :                                 return false;
     418             :                         }
     419           0 :                         break;
     420           0 :                 default:
     421           0 :                         break;
     422             :                 }
     423        7775 :                 break;
     424             :         }
     425        2475 :         case Type::Bytes:
     426        2475 :                 if (val.isString()) {
     427           0 :                         auto &str = val.getString();
     428           0 :                         if (str.size() > 4 && strncasecmp(str.data(), "hex:", 4) == 0) {
     429           0 :                                 auto len = (str.size() - 4) / 2;
     430           0 :                                 if (len < minLength || len > maxLength) {
     431           0 :                                         return false;
     432             :                                 }
     433             : 
     434           0 :                                 val.setBytes(stappler::base16::decode<Interface>(StringView(str.data() + 4, str.size() - 4)));
     435           0 :                         } else if (str.size() > 7 && strncasecmp(str.data(), "base64:", 7) == 0) {
     436           0 :                                 auto len = stappler::base64::decodeSize(str.size() - 7);
     437           0 :                                 if (len < minLength || len > maxLength) {
     438           0 :                                         return false;
     439             :                                 }
     440             : 
     441           0 :                                 val.setBytes(stappler::base64::decode<Interface>(StringView(str.data() + 7, str.size() - 7)));
     442           0 :                         } else if (transform == Transform::Uuid) {
     443           0 :                                 auto b = stappler::memory::uuid(str).bytes();
     444           0 :                                 if (b.empty()) {
     445           0 :                                         return false;
     446             :                                 }
     447             : 
     448           0 :                                 val.setBytes(std::move(b));
     449           0 :                         } else if (transform == Transform::PublicKey) {
     450           0 :                                 if (StringView(str).starts_with("ssh-")) {
     451           0 :                                         crypto::PublicKey key;
     452           0 :                                         if (key.importOpenSSH(str)) {
     453           0 :                                                 return key.exportDer([&] (BytesView bytes) {
     454           0 :                                                         val.setBytes(bytes);
     455           0 :                                                 });
     456             :                                         }
     457           0 :                                         return false;
     458           0 :                                 }
     459             : 
     460           0 :                                 stappler::crypto::PublicKey pk(BytesView((const uint8_t *)str.data(), str.size()));
     461           0 :                                 if (!pk) {
     462           0 :                                         return false;
     463             :                                 }
     464             : 
     465           0 :                                 return pk.exportDer([&] (BytesView bytes) {
     466           0 :                                         val.setBytes(bytes);
     467           0 :                                 });
     468           0 :                         }
     469        2475 :                 } else if (val.isBytes()) {
     470        2475 :                         auto &bytes = val.getBytes();
     471        2475 :                         if (transform == Transform::PublicKey) {
     472           0 :                                 stappler::crypto::PublicKey pk(bytes);
     473           0 :                                 if (!pk) {
     474           0 :                                         return false;
     475             :                                 }
     476             : 
     477           0 :                                 return pk.exportDer([&] (BytesView bytes) {
     478           0 :                                         val.setBytes(bytes);
     479           0 :                                 });
     480           0 :                         }
     481             : 
     482        2475 :                         if (bytes.size() < minLength || bytes.size() > maxLength) {
     483          25 :                                 return false;
     484             :                         }
     485             :                 }
     486        2450 :                 break;
     487           0 :         default:
     488           0 :                 return false;
     489             :                 break;
     490             :         }
     491       10225 :         return true;
     492             : }
     493             : 
     494           0 : void FieldText::hash(StringStream &stream, ValidationLevel l) const {
     495           0 :         Slot::hash(stream, l);
     496           0 :         if (l == ValidationLevel::Full) {
     497           0 :                 stream << minLength << maxLength;
     498             :         }
     499           0 : }
     500             : 
     501             : 
     502         100 : bool FieldPassword::transformValue(const Scheme &scheme, const Value &, Value &val, bool isCreate) const {
     503         100 :         if (!val.isString() && !val.isBytes()) {
     504           0 :                 return false;
     505             :         }
     506             : 
     507         100 :         if (val.isString()) {
     508         100 :                 auto &str = val.getString();
     509         100 :                 if (str.size() < minLength || str.size() > maxLength) {
     510           0 :                         return false;
     511             :                 }
     512         100 :                 val.setBytes(stappler::valid::makePassword<Interface>(str, salt));
     513             :         }
     514             : 
     515         100 :         return true;
     516             : }
     517             : 
     518           0 : void FieldPassword::hash(StringStream &stream, ValidationLevel l) const {
     519           0 :         Slot::hash(stream, l);
     520           0 :         if (l == ValidationLevel::Full) {
     521           0 :                 stream << minLength << maxLength << salt;
     522             :         }
     523           0 : }
     524             : 
     525             : 
     526        3325 : bool FieldExtra::hasDefault() const {
     527       12625 :         for (auto & it : fields) {
     528        9300 :                 if (it.second.hasDefault()) {
     529           0 :                         return true;
     530             :                 }
     531             :         }
     532        3325 :         return false;
     533             : }
     534             : 
     535           0 : Value FieldExtra::getDefault(const Value &patch) const {
     536           0 :         if (def) {
     537           0 :                 return def;
     538           0 :         } else if (defaultFn) {
     539           0 :                 return defaultFn(patch);
     540             :         }
     541             : 
     542           0 :         Value ret;
     543           0 :         for (auto & it : fields) {
     544           0 :                 if (it.second.hasDefault()) {
     545           0 :                         ret.setValue(it.second.getDefault(patch), it.first);
     546             :                 }
     547             :         }
     548           0 :         return ret;
     549           0 : }
     550             : 
     551        2500 : bool FieldExtra::transformValue(const Scheme &scheme, const Value &obj, Value &v, bool isCreate) const {
     552       16000 :         auto processValue = [&, this] (Value &val) -> bool {
     553        2500 :                 if (!val.isDictionary()) {
     554           0 :                         return false;
     555             :                 }
     556        2500 :                 auto &dict = val.asDict();
     557        2500 :                 auto it = dict.begin();
     558        9250 :                 while (it != dict.end()) {
     559        6750 :                         auto f_it = fields.find(it->first);
     560        6750 :                         if (f_it != fields.end()) {
     561        6750 :                                 if (it->second.isNull()) {
     562           0 :                                         it ++;
     563        6750 :                                 } else if (!f_it->second.transform(scheme, obj, it->second, isCreate)) {
     564          50 :                                         it = val.getDict().erase(it);
     565             :                                 } else {
     566        6700 :                                         it ++;
     567             :                                 }
     568             :                         } else {
     569           0 :                                 it = val.getDict().erase(it);
     570             :                         }
     571             :                 }
     572             : 
     573        2500 :                 if (!val.empty()) {
     574        2500 :                         return true;
     575             :                 }
     576             : 
     577           0 :                 return false;
     578        2500 :         };
     579             : 
     580        2500 :         if (transform == Transform::Array) {
     581           0 :                 if (!v.isArray()) {
     582           0 :                         return false;
     583             :                 }
     584             : 
     585           0 :                 auto &arr = v.asArray();
     586             : 
     587           0 :                 auto it = arr.begin();
     588           0 :                 while (it != arr.end()) {
     589           0 :                         if (processValue(*it)) {
     590           0 :                                 ++ it;
     591             :                         } else {
     592           0 :                                 it = arr.erase(it);
     593             :                         }
     594             :                 }
     595             : 
     596           0 :                 if (!v.empty()) {
     597           0 :                         return true;
     598             :                 }
     599             : 
     600           0 :                 return false;
     601             :         } else {
     602        2500 :                 return processValue(v);
     603             :         }
     604             : }
     605             : 
     606           0 : void FieldExtra::hash(StringStream &stream, ValidationLevel l) const {
     607           0 :         Slot::hash(stream, l);
     608           0 :         if (l == ValidationLevel::Full) {
     609           0 :                 for (auto &it : fields) {
     610           0 :                         it.second.hash(stream, l);
     611             :                 }
     612             :         }
     613           0 : }
     614             : 
     615           0 : void FieldFile::hash(StringStream &stream, ValidationLevel l) const {
     616           0 :         Slot::hash(stream, l);
     617           0 :         if (l == ValidationLevel::Full) {
     618           0 :                 stream << maxSize;
     619           0 :                 for (auto &it : allowedTypes) {
     620           0 :                         stream << it;
     621             :                 }
     622             :         }
     623           0 : }
     624             : 
     625           0 : void FieldImage::hash(StringStream &stream, ValidationLevel l) const {
     626           0 :         Slot::hash(stream, l);
     627           0 :         if (l == ValidationLevel::Full) {
     628           0 :                 stream << maxSize << primary
     629           0 :                                 << maxImageSize.width << maxImageSize.height << stappler::toInt(maxImageSize.policy)
     630           0 :                                 << minImageSize.width << minImageSize.height << stappler::toInt(minImageSize.policy);
     631           0 :                 for (auto &it : allowedTypes) {
     632           0 :                         stream << it;
     633             :                 }
     634             :         }
     635           0 : }
     636             : 
     637         450 : bool FieldObject::transformValue(const Scheme &scheme, const Value &obj, Value &val, bool isCreate) const {
     638         450 :         switch (type) {
     639         325 :         case Type::Object:
     640         325 :                 if (val.isBasicType()) {
     641         325 :                         val.setInteger(val.asInteger());
     642         325 :                         return true;
     643           0 :                 } else if (val.isDictionary()) {
     644           0 :                         return true; // pass to object's scheme
     645             :                 }
     646           0 :                 break;
     647         125 :         case Type::Set:
     648         125 :                 if (val.isArray()) {
     649         125 :                         auto &arr = val.asArray();
     650         125 :                         auto it = arr.begin();
     651         350 :                         while (it != arr.end()) {
     652         225 :                                 if (it->isBasicType()) {
     653         225 :                                         auto tmp = it->asInteger();
     654         225 :                                         if (tmp) {
     655         225 :                                                 it->setInteger(tmp);
     656             :                                         }
     657           0 :                                 } else if (it->isArray()) {
     658           0 :                                         it = arr.erase(it);
     659           0 :                                         continue;
     660             :                                 }
     661         225 :                                 ++ it;
     662             :                         }
     663         125 :                         return true;
     664           0 :                 } else if (val.isInteger()) {
     665           0 :                         return true;
     666             :                 }
     667           0 :                 break;
     668           0 :         default:
     669           0 :                 return false;
     670             :                 break;
     671             :         }
     672           0 :         return false;
     673             : }
     674             : 
     675           0 : void FieldObject::hash(StringStream &stream, ValidationLevel l) const {
     676           0 :         Slot::hash(stream, l);
     677           0 :         if (l == ValidationLevel::Full) {
     678           0 :                 if (scheme) {
     679           0 :                         stream << scheme->getName();
     680             :                 }
     681           0 :                 stream << stappler::toInt(onRemove) << stappler::toInt(linkage) << link;
     682             :         }
     683           0 : }
     684             : 
     685         400 : bool FieldArray::transformValue(const Scheme &scheme, const Value &obj, Value &val, bool isCreate) const {
     686         400 :         if (val.isArray()) {
     687         400 :                 if (tfield) {
     688         400 :                         auto &arr = val.asArray();
     689         400 :                         auto it = arr.begin();
     690        1000 :                         while (it != arr.end()) {
     691         600 :                                 if (!tfield.transform(scheme, obj, *it, isCreate)) {
     692           0 :                                         it = arr.erase(it);
     693             :                                 } else {
     694         600 :                                         ++ it;
     695             :                                 }
     696             :                         }
     697             :                 }
     698         400 :                 return true;
     699             :         }
     700           0 :         return false;
     701             : }
     702             : 
     703           0 : void FieldArray::hash(StringStream &stream, ValidationLevel l) const {
     704           0 :         Slot::hash(stream, l);
     705           0 :         if (l == ValidationLevel::Full) {
     706           0 :                 tfield.hash(stream, l);
     707             :         }
     708           0 : }
     709             : 
     710         250 : FullTextQuery FieldFullTextView::parseQuery(const Value &data) const {
     711         250 :         if (queryFn) {
     712           0 :                 return queryFn(data);
     713         250 :         } else if (data.isString() && searchConfiguration) {
     714         250 :                 return searchConfiguration->parseQuery(data.getString());
     715             :         }
     716           0 :         return FullTextQuery();
     717             : }
     718             : 
     719          25 : bool FieldVirtual::transformValue(const Scheme &scheme, const Value &obj, Value &value, bool isCreate) const {
     720          25 :         if (!writeFn) {
     721           0 :                 log::error("FieldVirtual", "Fail to write into virtual fields", data::EncodeFormat::Pretty, Value({
     722           0 :                         stappler::pair("object", Value(obj)),
     723           0 :                         stappler::pair("value", Value(value)),
     724           0 :                 }));
     725           0 :                 return false;
     726             :         }
     727             : 
     728          25 :         return true;
     729             : }
     730             : 
     731             : }

Generated by: LCOV version 1.14