@@ -2,11 +2,12 @@ use crate::user::FPUser;
22use crate :: FPError ;
33use byteorder:: { BigEndian , ReadBytesExt } ;
44use regex:: Regex ;
5+ use semver:: Version ;
56use serde:: { Deserialize , Serialize } ;
67use serde_json:: Value ;
78use sha1:: Digest ;
8- use std:: collections:: HashMap ;
99use std:: string:: String ;
10+ use std:: { collections:: HashMap , str:: FromStr } ;
1011use tracing:: { info, warn} ;
1112
1213#[ derive( Serialize , Deserialize , Debug , PartialEq ) ]
@@ -286,7 +287,11 @@ impl Rule {
286287enum ConditionType {
287288 String ,
288289 Segment ,
289- Date , // no implement
290+ Date ,
291+ Number ,
292+ SemVer ,
293+ #[ serde( other) ]
294+ Unknown ,
290295}
291296
292297#[ derive( Serialize , Deserialize , Debug , PartialEq , Clone ) ]
@@ -301,15 +306,16 @@ struct Condition {
301306impl Condition {
302307 pub fn meet ( & self , user : & FPUser , segment_repo : Option < & HashMap < String , Segment > > ) -> bool {
303308 match & self . r#type {
304- ConditionType :: String => self . match_string_condition ( user, & self . predicate ) ,
305- ConditionType :: Segment => {
306- self . match_segment_condition ( user, & self . predicate , segment_repo)
307- }
309+ ConditionType :: String => self . match_string ( user, & self . predicate ) ,
310+ ConditionType :: Segment => self . match_segment ( user, & self . predicate , segment_repo) ,
311+ ConditionType :: Number => self . match_ordering :: < f64 > ( user, & self . predicate ) ,
312+ ConditionType :: SemVer => self . match_ordering :: < Version > ( user, & self . predicate ) ,
313+ ConditionType :: Date => self . match_timestamp ( user, & self . predicate ) ,
308314 _ => false ,
309315 }
310316 }
311317
312- fn match_segment_condition (
318+ fn match_segment (
313319 & self ,
314320 user : & FPUser ,
315321 predicate : & str ,
@@ -325,22 +331,66 @@ impl Condition {
325331 }
326332 }
327333
328- fn match_string_condition ( & self , user : & FPUser , predicate : & str ) -> bool {
329- if let Some ( custom_value) = user. get ( & self . subject ) {
334+ fn match_string ( & self , user : & FPUser , predicate : & str ) -> bool {
335+ if let Some ( c) = user. get ( & self . subject ) {
336+ return match predicate {
337+ "is one of" => self . do_match :: < String > ( c, |c, o| c. eq ( o) ) ,
338+ "ends with" => self . do_match :: < String > ( c, |c, o| c. ends_with ( o) ) ,
339+ "starts with" => self . do_match :: < String > ( c, |c, o| c. starts_with ( o) ) ,
340+ "contains" => self . do_match :: < String > ( c, |c, o| c. contains ( o) ) ,
341+ "matches regex" => {
342+ self . do_match :: < String > ( c, |c, o| match Regex :: new ( o) {
343+ Ok ( re) => re. is_match ( c) ,
344+ Err ( _) => false , // invalid regex should be checked when load config
345+ } )
346+ }
347+ "is not any of" => !self . match_string ( user, "is one of" ) ,
348+ "does not end with" => !self . match_string ( user, "ends with" ) ,
349+ "does not start with" => !self . match_string ( user, "starts with" ) ,
350+ "does not contain" => !self . match_string ( user, "contains" ) ,
351+ "does not match regex" => !self . match_string ( user, "matches regex" ) ,
352+ _ => {
353+ info ! ( "unknown predicate {}" , predicate) ;
354+ false
355+ }
356+ } ;
357+ }
358+ info ! ( "user attr missing: {}" , self . subject) ;
359+ false
360+ }
361+
362+ fn match_ordering < T : FromStr + PartialOrd > ( & self , user : & FPUser , predicate : & str ) -> bool {
363+ if let Some ( c) = user. get ( & self . subject ) {
364+ let c: T = match c. parse ( ) {
365+ Ok ( v) => v,
366+ Err ( _) => return false ,
367+ } ;
368+ return match predicate {
369+ "=" => self . do_match :: < T > ( & c, |c, o| c. eq ( o) ) ,
370+ "!=" => !self . match_ordering :: < T > ( user, "=" ) ,
371+ ">" => self . do_match :: < T > ( & c, |c, o| c. gt ( o) ) ,
372+ ">=" => self . do_match :: < T > ( & c, |c, o| c. ge ( o) ) ,
373+ "<" => self . do_match :: < T > ( & c, |c, o| c. lt ( o) ) ,
374+ "<=" => self . do_match :: < T > ( & c, |c, o| c. le ( o) ) ,
375+ _ => {
376+ info ! ( "unknown predicate {}" , predicate) ;
377+ false
378+ }
379+ } ;
380+ }
381+ info ! ( "user attr missing: {}" , self . subject) ;
382+ false
383+ }
384+
385+ fn match_timestamp ( & self , user : & FPUser , predicate : & str ) -> bool {
386+ if let Some ( c) = user. get ( & self . subject ) {
387+ let c: u64 = match c. parse ( ) {
388+ Ok ( v) => v,
389+ Err ( _) => return false ,
390+ } ;
330391 return match predicate {
331- "is one of" => self . match_objects ( |object| custom_value. eq ( object) ) ,
332- "ends with" => self . match_objects ( |object| custom_value. ends_with ( object) ) ,
333- "starts with" => self . match_objects ( |object| custom_value. starts_with ( object) ) ,
334- "contains" => self . match_objects ( |object| custom_value. contains ( object) ) ,
335- "matches regex" => self . match_objects ( |object| match Regex :: new ( object) {
336- Ok ( re) => re. is_match ( custom_value) ,
337- Err ( _) => false , // invalid regex should be checked when load config
338- } ) ,
339- "is not any of" => !self . match_string_condition ( user, "is one of" ) ,
340- "does not end with" => !self . match_string_condition ( user, "ends with" ) ,
341- "does not start with" => !self . match_string_condition ( user, "starts with" ) ,
342- "does not contain" => !self . match_string_condition ( user, "contains" ) ,
343- "does not match regex" => !self . match_string_condition ( user, "matches regex" ) ,
392+ ">=" => self . do_match :: < u64 > ( & c, |c, o| c. ge ( o) ) ,
393+ "<" => self . do_match :: < u64 > ( & c, |c, o| c. lt ( o) ) ,
344394 _ => {
345395 info ! ( "unknown predicate {}" , predicate) ;
346396 false
@@ -351,8 +401,14 @@ impl Condition {
351401 false
352402 }
353403
354- fn match_objects ( & self , f : impl Fn ( & String ) -> bool ) -> bool {
355- self . objects . iter ( ) . map ( f) . any ( |x| x)
404+ fn do_match < T : FromStr > ( & self , t : & T , f : fn ( & T , & T ) -> bool ) -> bool {
405+ self . objects
406+ . iter ( )
407+ . map ( |o| match o. parse :: < T > ( ) {
408+ Ok ( o) => f ( t, & o) ,
409+ Err ( _) => false ,
410+ } )
411+ . any ( |x| x)
356412 }
357413
358414 fn user_in_segments ( & self , user : & FPUser , repo : & HashMap < String , Segment > ) -> bool {
@@ -674,6 +730,23 @@ mod string_condition_tests {
674730 use std:: fs;
675731 use std:: path:: PathBuf ;
676732
733+ #[ test]
734+ fn test_unkown_condition ( ) {
735+ let json_str = r#"
736+ {
737+ "type": "new_type",
738+ "subject": "new_subject",
739+ "predicate": ">",
740+ "objects": []
741+ }
742+ "# ;
743+
744+ let condition = serde_json:: from_str :: < Condition > ( & json_str) ;
745+ assert ! ( condition. is_ok( ) ) ;
746+ let condition = condition. unwrap ( ) ;
747+ assert_eq ! ( condition. r#type, ConditionType :: Unknown ) ;
748+ }
749+
677750 #[ test]
678751 fn test_match_is_one_of ( ) {
679752 let condition = Condition {
@@ -684,7 +757,7 @@ mod string_condition_tests {
684757 } ;
685758
686759 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "world" ) ;
687- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
760+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
688761 }
689762
690763 #[ test]
@@ -698,7 +771,7 @@ mod string_condition_tests {
698771
699772 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "not_in" ) ;
700773
701- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
774+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
702775 }
703776
704777 #[ test]
@@ -712,7 +785,7 @@ mod string_condition_tests {
712785
713786 let user = FPUser :: new ( String :: from ( "not care" ) ) ;
714787
715- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
788+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
716789 }
717790
718791 #[ test]
@@ -725,7 +798,7 @@ mod string_condition_tests {
725798 } ;
726799
727800 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "welcome" ) ;
728- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
801+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
729802 }
730803
731804 #[ test]
@@ -739,7 +812,7 @@ mod string_condition_tests {
739812
740813 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "not_in" ) ;
741814
742- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
815+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
743816 }
744817
745818 #[ test]
@@ -753,7 +826,7 @@ mod string_condition_tests {
753826
754827 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "bob world" ) ;
755828
756- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
829+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
757830 }
758831
759832 #[ test]
@@ -767,7 +840,7 @@ mod string_condition_tests {
767840
768841 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "bob" ) ;
769842
770- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
843+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
771844 }
772845
773846 #[ test]
@@ -781,7 +854,7 @@ mod string_condition_tests {
781854
782855 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "bob" ) ;
783856
784- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
857+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
785858 }
786859
787860 #[ test]
@@ -795,7 +868,7 @@ mod string_condition_tests {
795868
796869 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "bob world" ) ;
797870
798- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
871+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
799872 }
800873
801874 #[ test]
@@ -809,7 +882,7 @@ mod string_condition_tests {
809882
810883 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "world bob" ) ;
811884
812- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
885+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
813886 }
814887
815888 #[ test]
@@ -823,7 +896,7 @@ mod string_condition_tests {
823896
824897 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "bob" ) ;
825898
826- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
899+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
827900 }
828901
829902 #[ test]
@@ -837,7 +910,7 @@ mod string_condition_tests {
837910
838911 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "bob" ) ;
839912
840- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
913+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
841914 }
842915
843916 #[ test]
@@ -851,7 +924,7 @@ mod string_condition_tests {
851924
852925 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "world bob" ) ;
853926
854- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
927+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
855928 }
856929
857930 #[ test]
@@ -865,7 +938,7 @@ mod string_condition_tests {
865938
866939 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice world bob" ) ;
867940
868- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
941+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
869942 }
870943
871944 #[ test]
@@ -879,7 +952,7 @@ mod string_condition_tests {
879952
880953 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice bob" ) ;
881954
882- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
955+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
883956 }
884957
885958 #[ test]
@@ -893,7 +966,7 @@ mod string_condition_tests {
893966
894967 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice bob" ) ;
895968
896- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
969+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
897970 }
898971
899972 #[ test]
@@ -907,7 +980,7 @@ mod string_condition_tests {
907980
908981 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice world bob" ) ;
909982
910- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
983+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
911984 }
912985
913986 #[ test]
@@ -921,7 +994,7 @@ mod string_condition_tests {
921994
922995 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice world bob" ) ;
923996
924- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
997+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
925998 }
926999
9271000 #[ test]
@@ -935,7 +1008,7 @@ mod string_condition_tests {
9351008
9361009 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice orld bob hello3" ) ;
9371010
938- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
1011+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
9391012 }
9401013
9411014 #[ test]
@@ -949,7 +1022,7 @@ mod string_condition_tests {
9491022
9501023 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice orld bob hello" ) ;
9511024
952- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
1025+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
9531026 }
9541027
9551028 #[ test]
@@ -963,7 +1036,7 @@ mod string_condition_tests {
9631036
9641037 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "alice orld bob hello" ) ;
9651038
966- assert ! ( condition. match_string_condition ( & user, & condition. predicate) ) ;
1039+ assert ! ( condition. match_string ( & user, & condition. predicate) ) ;
9671040 }
9681041
9691042 #[ test]
@@ -977,7 +1050,7 @@ mod string_condition_tests {
9771050
9781051 let user = FPUser :: new ( String :: from ( "not care" ) ) . with ( "name" , "\\ \\ \\ " ) ;
9791052
980- assert ! ( !condition. match_string_condition ( & user, & condition. predicate) ) ;
1053+ assert ! ( !condition. match_string ( & user, & condition. predicate) ) ;
9811054 }
9821055
9831056 #[ test]
0 commit comments