diff --git a/specifyweb/backend/context/views.py b/specifyweb/backend/context/views.py
index ed50095bf07..53e3a98c03f 100644
--- a/specifyweb/backend/context/views.py
+++ b/specifyweb/backend/context/views.py
@@ -5,6 +5,7 @@
import json
import os
import re
+import logging
from typing import List
from xml.etree import ElementTree
@@ -14,7 +15,7 @@
from django.db import connection, transaction
from django.db.models import Q
from django.http import Http404, HttpResponse, HttpResponseBadRequest, \
- HttpResponseForbidden, JsonResponse
+ HttpResponseForbidden, HttpResponseServerError, JsonResponse
from django.urls import URLPattern
from django.utils.translation import get_language_info
from django.utils.translation import gettext as _
@@ -46,6 +47,8 @@
is_collection_available,
is_guided_setup_complete,
)
+
+logger = logging.getLogger(__name__)
def set_collection_cookie(response, collection_id): # pragma: no cover
response.set_cookie('collection', str(collection_id), max_age=365*24*60*60)
@@ -655,13 +658,13 @@ def schema_localization_import(request):
if not isinstance(language, str) or not re.fullmatch(
r'[A-Za-z]{2}(?:-[A-Za-z]{2})?', language
):
- raise ValueError
+ raise ValueError(f"Invalid language string: {language}")
if isinstance(schema, dict) and {'language', 'schema'} <= schema.keys():
source_language = schema['language']
if not isinstance(source_language, str) or (
source_language.lower() != language.lower()
):
- raise ValueError
+ raise ValueError(f"Invalid Localization (expected {source_language}, got {language}")
schema = schema['schema']
references = {
'format': _schema_import_resource_names(
@@ -704,8 +707,16 @@ def schema_localization_import(request):
request.specify_collection, request.specify_user_agent,
model.__name__, data
)
- except (AttributeError, KeyError, TypeError, ValueError, json.JSONDecodeError):
- return HttpResponseBadRequest()
+ except (AttributeError, ValueError, json.JSONDecodeError) as err:
+ logger.warning("Schema import validation failed", exc_info=True)
+ return JsonResponse(
+ {"error": "Invalid schema localization import payload."},
+ status=400
+ )
+ except (KeyError, TypeError) as err:
+ logger.warning(f"Schema Import failed: {err}")
+ return HttpResponseServerError("An internal error has occurred.", content_type="text/plain")
+
return JsonResponse({'updated': len(operations)})
view_parameters_schema = [
diff --git a/specifyweb/frontend/js_src/lib/components/SchemaConfig/Layout.tsx b/specifyweb/frontend/js_src/lib/components/SchemaConfig/Layout.tsx
index 161dfc818d4..ac53a147a8d 100644
--- a/specifyweb/frontend/js_src/lib/components/SchemaConfig/Layout.tsx
+++ b/specifyweb/frontend/js_src/lib/components/SchemaConfig/Layout.tsx
@@ -24,6 +24,7 @@ import {
useSchemaConfig,
} from './Store';
import { dialogIcons } from '../Atoms/Icons';
+import { raise } from '../Errors/Crash';
export function SchemaConfigLayout(): JSX.Element {
const schemaData = useOutletContext();
@@ -55,8 +56,7 @@ function SchemaConfigLayoutContent(): JSX.Element {
const setSingleResource = React.useContext(SetSingleResourceContext);
const loading = React.useContext(LoadingContext);
const [importFile, setImportFile] = React.useState();
- const [importError, setImportError] = React.useState(false);
- const [importSuccessful, setImportSuccessful] = React.useState(false);
+ const [importStatus, setImportStatus] = React.useState(0);
const [importRefreshError, setImportRefreshError] = React.useState(false);
React.useEffect(() => {
@@ -80,7 +80,6 @@ function SchemaConfigLayoutContent(): JSX.Element {
);
};
const handleImport = (file: File): void => {
- setImportError(false);
setImportFile(file);
};
const confirmImport = (): void => {
@@ -95,17 +94,25 @@ function SchemaConfigLayoutContent(): JSX.Element {
method: 'POST',
headers: { Accept: 'application/json' },
body: { schema, language: rawLanguage },
- errorMode: 'silent',
+ expectedErrors: [400, 500, 504]
})
)
.then(
- () => setImportSuccessful(true),
- () => setImportError(true)
+ (response) => {
+ setImportStatus(response.status);
+ if (response.status !== 200)
+ raise({name: schemaText.importSchemaError({schemaConfig: schemaText.schemaConfig()}), message:
+ response.status === 504 ? schemaText.importSchemaErrorTimeout({schemaConfig: schemaText.schemaConfig()}) :
+ response.status === 400 ? schemaText.importSchemaErrorBadRequest({schemaConfig: schemaText.schemaConfig()}) :
+ schemaText.importSchemaErrorInternalError()
+ })
+ },
+ (err) => raise(err)
)
);
};
const closeImportSuccess = (): void => {
- setImportSuccessful(false);
+ setImportStatus(0);
loading(
handleSchemaSaved(rawLanguage, tableName).catch(() =>
setImportRefreshError(true)
@@ -170,25 +177,7 @@ function SchemaConfigLayoutContent(): JSX.Element {
)}
- {importError && (
-
- )}
- {importSuccessful && (
+ {importStatus == 200 && (