77from flask import Response , abort
88from gramps .gen .db .base import DbReadBase
99from gramps .gen .filters import GenericFilter
10- from marshmallow import Schema , ValidationError , fields
11- from webargs import validate
10+ from marshmallow import Schema
11+ from webargs import ValidationError , fields , validate
1212from webargs .flaskparser import use_args
1313
1414from ...const import GRAMPS_NAMESPACES
@@ -34,8 +34,9 @@ def get_filter_rules(args: Dict[str, str], namespace: str) -> List[Dict]:
3434 rule_list = []
3535 for rule_class in _RULES_LOOKUP [namespace ]:
3636 add_rule = True
37- if args .get ("rule" ) and args ["rule" ] != rule_class .__name__ :
38- add_rule = False
37+ if "rules" in args and args ["rules" ]:
38+ if rule_class .__name__ not in args ["rules" ]:
39+ add_rule = False
3940 if add_rule :
4041 rule_list .append (
4142 {
@@ -46,6 +47,8 @@ def get_filter_rules(args: Dict[str, str], namespace: str) -> List[Dict]:
4647 "rule" : rule_class .__name__ ,
4748 }
4849 )
50+ if "rules" in args and len (args ["rules" ]) != len (rule_list ):
51+ abort (404 )
4952 return rule_list
5053
5154
@@ -55,8 +58,9 @@ def get_custom_filters(args: Dict[str, str], namespace: str) -> List[Dict]:
5558 filters .reload_custom_filters ()
5659 for filter_class in filters .CustomFilters .get_filters (namespace ):
5760 add_filter = True
58- if args .get ("filter" ) and args ["filter" ] != filter_class .get_name ():
59- add_filter = False
61+ if "filters" in args and args ["filters" ]:
62+ if filter_class .get_name () not in args ["filters" ]:
63+ add_filter = False
6064 if add_filter :
6165 filter_list .append (
6266 {
@@ -74,6 +78,8 @@ def get_custom_filters(args: Dict[str, str], namespace: str) -> List[Dict]:
7478 ],
7579 }
7680 )
81+ if "filters" in args and len (args ["filters" ]) != len (filter_list ):
82+ abort (404 )
7783 return filter_list
7884
7985
@@ -113,7 +119,7 @@ def apply_filter(db_handle: DbReadBase, args: Dict, namespace: str) -> List[Hand
113119 for filter_class in filters .CustomFilters .get_filters (namespace ):
114120 if args ["filter" ] == filter_class .get_name ():
115121 return filter_class .apply (db_handle )
116- abort (400 )
122+ abort (404 )
117123
118124 try :
119125 filter_parms = FilterSchema ().load (json .loads (args ["rules" ]))
@@ -143,21 +149,31 @@ class FilterSchema(Schema):
143149 validate = validate .OneOf (["and" , "or" , "xor" , "one" ]),
144150 )
145151 invert = fields .Boolean (required = False , missing = False )
146- rules = fields .List (fields .Nested (RuleSchema ))
152+ rules = fields .List (
153+ fields .Nested (RuleSchema ), required = True , validate = validate .Length (min = 1 )
154+ )
147155
148156
149157class CustomFilterSchema (FilterSchema ):
150158 """Structure for a custom filter."""
151159
152160 name = fields .Str (required = True , validate = validate .Length (min = 1 ))
153161 comment = fields .Str (required = False )
162+ rules = fields .List (
163+ fields .Nested (RuleSchema ), required = True , validate = validate .Length (min = 1 )
164+ )
154165
155166
156167class FilterResource (ProtectedResource , GrampsJSONEncoder ):
157168 """Filter resource."""
158169
159170 @use_args (
160- {"filter" : fields .Str (), "rule" : fields .Str ()},
171+ {
172+ "filters" : fields .DelimitedList (
173+ fields .Str (validate = validate .Length (min = 1 ))
174+ ),
175+ "rules" : fields .DelimitedList (fields .Str (validate = validate .Length (min = 1 ))),
176+ },
161177 location = "query" ,
162178 )
163179 def get (self , args : Dict [str , str ], namespace : str ) -> Response :
@@ -168,10 +184,10 @@ def get(self, args: Dict[str, str], namespace: str) -> Response:
168184 abort (404 )
169185
170186 rule_list = get_filter_rules (args , namespace )
171- if args . get ( "rule" ) and not args . get ( "filter" ) :
187+ if "rules" in args and "filters" not in args :
172188 return self .response (200 , {"rules" : rule_list })
173189 filter_list = get_custom_filters (args , namespace )
174- if args . get ( "filter" ) and not args . get ( "rule" ) :
190+ if "filters" in args and "rules" not in args :
175191 return self .response (200 , {"filters" : filter_list })
176192 return self .response (200 , {"filters" : filter_list , "rules" : rule_list })
177193
@@ -214,12 +230,11 @@ def put(self, args: Dict, namespace: str) -> Response:
214230
215231 @use_args (
216232 {
217- "name" : fields .Str (required = True ),
218- "force" : fields .Boolean (required = False , missing = False ),
233+ "force" : fields .Str (validate = validate .Length (equal = 0 )),
219234 },
220- location = "json " ,
235+ location = "query " ,
221236 )
222- def delete (self , args : Dict , namespace : str ) -> Response :
237+ def delete (self , args : Dict , namespace : str , name : str ) -> Response :
223238 """Delete a custom filter."""
224239 try :
225240 namespace = GRAMPS_NAMESPACES [namespace ]
@@ -229,17 +244,15 @@ def delete(self, args: Dict, namespace: str) -> Response:
229244 filters .reload_custom_filters ()
230245 custom_filters = filters .CustomFilters .get_filters (namespace )
231246 for custom_filter in custom_filters :
232- if args [ " name" ] == custom_filter .get_name ():
247+ if name == custom_filter .get_name ():
233248 filter_set = set ()
234249 self ._find_dependent_filters (namespace , custom_filter , filter_set )
235250 if len (filter_set ) > 1 :
236251 if "force" not in args or not args ["force" ]:
237252 abort (405 )
238253 list (map (custom_filters .remove , filter_set ))
239254 filters .CustomFilters .save ()
240- return self .response (
241- 200 , {"message" : "Deleted filter: " + args ["name" ]}
242- )
255+ return self .response (200 , {"message" : "Deleted filter: " + name })
243256 return abort (404 )
244257
245258 def _find_dependent_filters (
0 commit comments