Skip to content

Commit b140273

Browse files
authored
Add error messages (#389)
* Start adding error messages * Fix circular import * More messages * Make abort_with_message work well outside request * Add more error msgs * More descriptive error on user creation * Fix missing import * Revert "More descriptive error on user creation" This reverts commit 6f45690. * Fix users * Change error message
1 parent 0038287 commit b140273

File tree

24 files changed

+186
-148
lines changed

24 files changed

+186
-148
lines changed

gramps_webapi/api/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from functools import wraps
2323
from typing import Iterable
2424

25-
from flask import abort, current_app
25+
from flask import abort
2626
from flask_jwt_extended import get_jwt, verify_jwt_in_request
2727
from flask_jwt_extended.exceptions import NoAuthorizationError
2828

gramps_webapi/api/export.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from gramps.gen.utils.resourcepath import ResourcePath
4444

4545
from ..const import DISABLED_EXPORTERS
46-
from .util import get_locale_for_language
46+
from .util import abort_with_message, get_locale_for_language
4747

4848
_ = glocale.translation.gettext
4949

@@ -229,35 +229,35 @@ def prepare_options(db_handle: DbReadBase, args: Dict):
229229
if args["gramps_id"] is not None:
230230
gramps_id = args["gramps_id"]
231231
if db_handle.get_person_from_gramps_id(gramps_id) is None:
232-
abort(422)
232+
abort_with_message(422, "Person with this Gramps ID not found")
233233
else:
234234
try:
235235
person = db_handle.get_person_from_handle(args["handle"])
236236
except HandleError:
237-
abort(422)
237+
abort_with_message(422, "Person with this handle not found")
238238
gramps_id = person.gramps_id
239239
try:
240240
options.set_person_filter(args["person"], gramps_id)
241-
except ValueError:
242-
abort(422)
241+
except ValueError as exc:
242+
abort_with_message(422, str(exc))
243243
if args["event"] is not None:
244244
try:
245245
options.set_event_filter(args["event"])
246-
except ValueError:
247-
abort(422)
246+
except ValueError as exc:
247+
abort_with_message(422, str(exc))
248248
if args["note"] is not None:
249249
try:
250250
options.set_note_filter(args["note"])
251-
except ValueError:
252-
abort(422)
251+
except ValueError as exc:
252+
abort_with_message(422, str(exc))
253253
try:
254254
options.set_proxy_order(args["sequence"])
255-
except ValueError:
256-
abort(422)
255+
except ValueError as exc:
256+
abort_with_message(422, str(exc))
257257
if args["locale"] is not None:
258258
options.locale = get_locale_for_language(args["locale"])
259259
if options.locale is None:
260-
abort(422)
260+
abort_with_message(422, "Locale not found")
261261
return options
262262

263263

@@ -276,6 +276,6 @@ def run_export(db_handle: DbReadBase, extension: str, options):
276276
export_function = plugin.get_export_function()
277277
result = export_function(db_handle, file_path, User(), options)
278278
if not result:
279-
abort(500)
279+
abort_with_message(500, "Export function failed")
280280
return file_name, "." + extension
281-
abort(404) # exporter not found
281+
abort_with_message(404, "Exporter not found") # exporter not found

gramps_webapi/api/file.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
from ..types import FilenameOrPath
3737
from .image import LocalFileThumbnailHandler, detect_faces
38+
from .util import abort_with_message
3839

3940

4041
class FileHandler:
@@ -94,7 +95,7 @@ def get_face_regions(self, etag: Optional[str] = None):
9495
regions = detect_faces(fobj)
9596
except ImportError:
9697
# numpy or opencv missing
97-
abort(501)
98+
abort_with_message(501, "OpenCV is not installed")
9899
else:
99100
regions = []
100101
res = make_response(jsonify(regions))
@@ -139,7 +140,7 @@ def get_file_object(self) -> BinaryIO:
139140
try:
140141
self._check_path()
141142
except ValueError:
142-
abort(403)
143+
abort_with_message(403, "File access not allowed")
143144
with open(self.path_abs, "rb") as f:
144145
stream = BytesIO(f.read())
145146
return stream
@@ -152,7 +153,7 @@ def get_file_size(self) -> int:
152153
try:
153154
self._check_path()
154155
except ValueError:
155-
abort(403)
156+
abort_with_message(403, "File access not allowed")
156157
return os.path.getsize(self.path_abs)
157158

158159
def send_file(
@@ -177,7 +178,7 @@ def send_cropped(self, x1: int, y1: int, x2: int, y2: int, square: bool = False)
177178
try:
178179
self._check_path()
179180
except ValueError:
180-
abort(403)
181+
abort_with_message(403, "File access not allowed")
181182
thumb = LocalFileThumbnailHandler(self.path_abs, self.mime)
182183
buffer = thumb.get_cropped(x1=x1, y1=y1, x2=x2, y2=y2, square=square)
183184
return send_file(buffer, mimetype=MIME_JPEG)
@@ -187,7 +188,7 @@ def send_thumbnail(self, size: int, square: bool = False):
187188
try:
188189
self._check_path()
189190
except ValueError:
190-
abort(403)
191+
abort_with_message(403, "File access not allowed")
191192
thumb = LocalFileThumbnailHandler(self.path_abs, self.mime)
192193
buffer = thumb.get_thumbnail(size=size, square=square)
193194
return send_file(buffer, mimetype=MIME_JPEG)
@@ -199,7 +200,7 @@ def send_thumbnail_cropped(
199200
try:
200201
self._check_path()
201202
except ValueError:
202-
abort(403)
203+
abort_with_message(403, "File access not allowed")
203204
thumb = LocalFileThumbnailHandler(self.path_abs, self.mime)
204205
buffer = thumb.get_thumbnail_cropped(
205206
size=size, x1=x1, y1=y1, x2=x2, y2=y2, square=square

gramps_webapi/api/report.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from gramps.gen.utils.resourcepath import ResourcePath
4444

4545
from ..const import MIME_TYPES, REPORT_DEFAULTS, REPORT_FILTERS
46+
from .util import abort_with_message
4647

4748
_EXTENSION_MAP = {".gvpdf": ".pdf", ".gspdf": ".pdf"}
4849

@@ -191,7 +192,7 @@ def run_report(
191192
file_type = _EXTENSION_MAP.get(file_type) or file_type
192193
if file_type not in MIME_TYPES:
193194
current_app.logger.error(f"Cannot find {file_type} in MIME_TYPES")
194-
abort(500)
195+
abort_with_message(500, f"MIME type {file_type} not found")
195196
report_path = current_app.config.get("REPORT_DIR")
196197
os.makedirs(report_path, exist_ok=True)
197198
file_name = f"{uuid.uuid4()}{file_type}"
@@ -241,14 +242,14 @@ def validate_options(report: Dict, report_options: Dict, allow_file: bool = Fals
241242
abort(422)
242243
continue
243244
if not isinstance(report_options[option], str):
244-
abort(422)
245+
abort_with_message(422, "Report options must be provided as strings")
245246
if "A number" in report["options_help"][option][2]:
246247
try:
247248
float(report_options[option])
248249
except ValueError:
249-
abort(422)
250+
abort_with_message(422, "Cannot convert option string to number")
250251
if "Size in cm" in report["options_help"][option][2]:
251252
try:
252253
float(report_options[option])
253254
except ValueError:
254-
abort(422)
255+
abort_with_message(422, "Cannot convert option string to number")

gramps_webapi/api/resources/base.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
from .match import match_dates
5454
from .sort import sort_objects
5555
from .util import (
56+
abort_with_message,
5657
add_object,
5758
fix_object_dict,
5859
get_backlinks,
@@ -83,7 +84,9 @@ def full_object(
8384
obj.backlinks = get_backlinks(self.db_handle, obj.handle)
8485
if args.get("soundex"):
8586
if self.gramps_class_name not in ["Person", "Family"]:
86-
abort(422)
87+
abort_with_message(
88+
422, f"Option soundex is not allowed for {self.gramps_class_name}"
89+
)
8790
obj.soundex = get_soundex(self.db_handle, obj, self.gramps_class_name)
8891
obj = self.object_extend(obj, args, locale=locale)
8992
if args.get("profile") and (
@@ -147,17 +150,17 @@ def _parse_object(self) -> GrampsObject:
147150
"""Parse the object."""
148151
obj_dict = request.json
149152
if obj_dict is None:
150-
abort(400)
153+
abort_with_message(400, "Empty object")
151154
if "_class" not in obj_dict:
152155
obj_dict["_class"] = self.gramps_class_name
153156
elif obj_dict["_class"] != self.gramps_class_name:
154-
abort(400)
157+
abort_with_message(400, "Wrong object type")
155158
try:
156159
obj_dict = fix_object_dict(obj_dict)
157-
except ValueError:
158-
abort(400)
160+
except ValueError as exc:
161+
abort_with_message(400, "Error while processing object")
159162
if not validate_object_dict(obj_dict):
160-
abort(400)
163+
abort_with_message(400, "Schema validation failed")
161164
return from_json(json.dumps(obj_dict))
162165

163166
def has_handle(self, handle: str) -> bool:
@@ -249,7 +252,7 @@ def delete(self, handle: str) -> Response:
249252
get_etag = hash_object(obj)
250253
for etag in request.if_match:
251254
if etag != get_etag:
252-
abort(412)
255+
abort_with_message(412, "Resource does not match provided ETag")
253256
trans_dict = delete_object(
254257
self.db_handle_writable, handle, self.gramps_class_name
255258
)
@@ -273,16 +276,16 @@ def put(self, handle: str) -> Response:
273276
get_etag = hash_object(obj_old)
274277
for etag in request.if_match:
275278
if etag != get_etag:
276-
abort(412)
279+
abort_with_message(412, "Resource does not match provided ETag")
277280
obj = self._parse_object()
278281
if not obj:
279-
abort(400)
282+
abort_with_message(400, "Empty object")
280283
db_handle = self.db_handle_writable
281284
with DbTxn("Edit object", db_handle) as trans:
282285
try:
283286
update_object(db_handle, obj, trans)
284-
except ValueError:
285-
abort(400)
287+
except ValueError as exc:
288+
abort_with_message(400, "Error while updating object")
286289
trans_dict = transaction_to_json(trans)
287290
# update search index
288291
tree = get_tree_from_jwt()
@@ -431,13 +434,13 @@ def post(self) -> Response:
431434
check_quota_people(to_add=1)
432435
obj = self._parse_object()
433436
if not obj:
434-
abort(400)
437+
abort_with_message(400, "Empty object")
435438
db_handle = self.db_handle_writable
436439
with DbTxn("Add objects", db_handle) as trans:
437440
try:
438441
add_object(db_handle, obj, trans, fail_if_exists=True)
439-
except ValueError:
440-
abort(400)
442+
except ValueError as exc:
443+
abort_with_message(400, "Error while adding object")
441444
trans_dict = transaction_to_json(trans)
442445
# update usage
443446
if self.gramps_class_name == "Person":

gramps_webapi/api/resources/events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from webargs import fields, validate
3232

3333
from ...types import Handle
34-
from ..util import get_db_handle, get_locale_for_language, use_args
34+
from ..util import abort_with_message, get_db_handle, get_locale_for_language, use_args
3535
from . import ProtectedResource
3636
from .base import (
3737
GrampsObjectProtectedResource,
@@ -62,7 +62,7 @@ def object_extend(
6262
obj.extended["place"] = get_place_by_handle(db_handle, obj.place)
6363
if "profile" in args:
6464
if "families" in args["profile"] or "events" in args["profile"]:
65-
abort(422)
65+
abort_with_message(422, "profile contains invalid keys")
6666
obj.profile = get_event_profile_for_object(
6767
db_handle, obj, args["profile"], locale=locale
6868
)

gramps_webapi/api/resources/export_media.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from ..auth import has_permissions
3030
from ..ratelimiter import limiter_per_user
3131
from ..tasks import AsyncResult, export_media, make_task_response, run_task
32-
from ..util import get_buffer_for_file, get_tree_from_jwt
32+
from ..util import abort_with_message, get_buffer_for_file, get_tree_from_jwt
3333
from . import ProtectedResource
3434

3535

@@ -67,7 +67,7 @@ def get(self, filename: str) -> Response:
6767
)
6868
match = regex.match(filename)
6969
if not match:
70-
abort(422)
70+
abort_with_message(422, "Invalid filename")
7171

7272
file_path = os.path.join(export_path, filename)
7373
if not os.path.isfile(file_path):

gramps_webapi/api/resources/exporters.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@
3737
from ..auth import has_permissions
3838
from ..export import get_exporters, prepare_options, run_export
3939
from ..tasks import AsyncResult, export_db, make_task_response, run_task
40-
from ..util import get_buffer_for_file, get_db_handle, get_tree_from_jwt, use_args
40+
from ..util import (
41+
abort_with_message,
42+
get_buffer_for_file,
43+
get_db_handle,
44+
get_tree_from_jwt,
45+
use_args,
46+
)
4147
from . import ProtectedResource
4248
from .emit import GrampsJSONEncoder
4349

@@ -196,7 +202,7 @@ def get(self, extension: str, filename: str) -> Response:
196202
)
197203
match = regex.match(filename)
198204
if not match:
199-
abort(422)
205+
abort_with_message(422, "Invalid filename")
200206

201207
file_type = match.group(2)
202208
file_path = os.path.join(export_path, filename)

gramps_webapi/api/resources/facts.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from gramps.plugins.lib.librecords import find_records
3333
from webargs import fields, validate
3434

35-
from ..util import get_db_handle, get_locale_for_language, use_args
35+
from ..util import abort_with_message, get_db_handle, get_locale_for_language, use_args
3636
from . import ProtectedResource
3737
from .emit import GrampsJSONEncoder
3838

@@ -57,12 +57,12 @@ def get_person_filter(db_handle: DbReadBase, args: Dict) -> Union[GenericFilter,
5757
if args["gramps_id"]:
5858
gramps_id = args["gramps_id"]
5959
if db_handle.get_person_from_gramps_id(gramps_id) is None:
60-
abort(422)
60+
abort_with_message(422, "Person with this Gramps ID not found")
6161
else:
6262
try:
6363
person = db_handle.get_person_from_handle(args["handle"])
6464
except HandleError:
65-
abort(422)
65+
abort_with_message(422, "Person with this handle not found")
6666
gramps_id = person.gramps_id
6767

6868
person_filter = filters.GenericFilter()

0 commit comments

Comments
 (0)