Skip to content

Commit 2637cc6

Browse files
feat(numericalInput): endpoint added to validate a numerical input (#37677)
To be used in the visual Problem editor to validate numeric input. Part of: openedx/frontend-app-authoring#1680
1 parent a032955 commit 2637cc6

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""
2+
Serializers for the contentstore v2 utils views module.
3+
4+
This module contains DRF serializers for different utils like validations.
5+
"""
6+
7+
from rest_framework import serializers
8+
9+
10+
class NumericalInputValidationRequestSerializer(serializers.Serializer):
11+
formula = serializers.CharField()
12+
13+
14+
class NumericalInputValidationReponseSerializer(serializers.Serializer):
15+
preview = serializers.CharField()
16+
is_valid = serializers.BooleanField()
17+
error = serializers.CharField(allow_null=True)

cms/djangoapps/contentstore/rest_api/v2/urls.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.conf import settings
44
from django.urls import path, re_path
55

6-
from cms.djangoapps.contentstore.rest_api.v2.views import downstreams, home
6+
from cms.djangoapps.contentstore.rest_api.v2.views import downstreams, home, utils
77

88
app_name = "v2"
99

@@ -33,4 +33,8 @@
3333
downstreams.SyncFromUpstreamView.as_view(),
3434
name="sync_from_upstream"
3535
),
36+
re_path(
37+
'^validate/numerical-input/$',
38+
utils.NumericalInputValidationView.as_view(),
39+
name='numerical_input_validation'),
3640
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
Common utilities for V2 APIs.
3+
"""
4+
from rest_framework.response import Response
5+
from rest_framework.generics import GenericAPIView
6+
from rest_framework import permissions
7+
from cms.djangoapps.contentstore.rest_api.v2.serializers.utils import NumericalInputValidationRequestSerializer
8+
from xmodule.capa.inputtypes import preview_numeric_input
9+
10+
11+
class NumericalInputValidationView(GenericAPIView):
12+
"""Class in charge of NumericalInputValidations"""
13+
permission_classes = (permissions.IsAuthenticated,)
14+
serializer_class = NumericalInputValidationRequestSerializer
15+
16+
def post(self, request):
17+
"""function to validate a math expression (formula) and return of the numeric input is valid or not"""
18+
serializer = self.get_serializer(data=request.data)
19+
serializer.is_valid(raise_exception=True)
20+
formula = serializer.validated_data['formula']
21+
result = preview_numeric_input(formula)
22+
return Response(result, status=200)

xmodule/capa/inputtypes.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949

5050
import html5lib
5151
import nh3
52-
import pyparsing
5352
import six
5453
from calc.preview import latex_preview
54+
import pyparsing
5555
from chem import chemcalc
5656
from lxml import etree
5757

@@ -1300,22 +1300,47 @@ def preview_formcalc(self, get):
13001300

13011301
result["request_start"] = int(get.get("request_start", 0))
13021302

1303+
# TODO add references to valid variables and functions
1304+
# At some point, we might want to mark invalid variables as red
1305+
# or something, and this is where we would need to pass those in.
13031306
try:
1304-
# TODO add references to valid variables and functions
1305-
# At some point, we might want to mark invalid variables as red
1306-
# or something, and this is where we would need to pass those in.
1307-
result["preview"] = latex_preview(formula)
1307+
numeric_result = preview_numeric_input(formula)
1308+
# Map results into the correct format
1309+
result["preview"] = numeric_result["preview"]
1310+
if numeric_result["error"]:
1311+
result["error"] = numeric_result["error"]
1312+
# if formula is invalid return formula
1313+
if not numeric_result["is_valid"]:
1314+
result["formula"] = formula
13081315
except pyparsing.ParseException:
1309-
result["error"] = _("Sorry, couldn't parse formula")
1310-
result["formula"] = formula
1316+
result['error'] = _("Sorry, couldn't parse formula")
1317+
result['formula'] = formula
13111318
except Exception: # lint-amnesty, pylint: disable=broad-except
1312-
# this is unexpected, so log
13131319
log.warning("Error while previewing formula", exc_info=True)
13141320
result["error"] = _("Error while rendering preview")
1321+
return result
13151322

13161323
return result
13171324

13181325

1326+
def preview_numeric_input(formula):
1327+
"""
1328+
Handles numeric validations, validates that the formula provided is a valid formula.
1329+
"""
1330+
result = {'preview': '', 'is_valid': True, 'error': ''}
1331+
try:
1332+
result['preview'] = latex_preview(formula)
1333+
except pyparsing.ParseException:
1334+
result["error"] = "Sorry, couldn't parse formula"
1335+
result['is_valid'] = False
1336+
return result
1337+
except Exception: # pylint: disable=broad-exception-caught
1338+
log.warning("Error while previewing formula", exc_info=True)
1339+
result['error'] = "Error while rendering preview"
1340+
result['is_valid'] = False
1341+
return result
1342+
1343+
13191344
# -----------------------------------------------------------------------------
13201345

13211346

xmodule/capa/tests/test_inputtypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ def test_ajax_parse_err(self):
13611361
With parse errors, FormulaEquationInput should give an error message
13621362
"""
13631363
# Simulate answering a problem that raises the exception
1364-
with patch("xmodule.capa.inputtypes.latex_preview") as mock_preview:
1364+
with patch('xmodule.capa.inputtypes.preview_numeric_input') as mock_preview:
13651365
mock_preview.side_effect = ParseException("Oopsie")
13661366
response = self.the_input.handle_ajax(
13671367
"preview_formcalc",
@@ -1379,7 +1379,7 @@ def test_ajax_other_err(self, mock_log):
13791379
"""
13801380
With other errors, test that FormulaEquationInput also logs it
13811381
"""
1382-
with patch("xmodule.capa.inputtypes.latex_preview") as mock_preview:
1382+
with patch('xmodule.capa.inputtypes.preview_numeric_input') as mock_preview:
13831383
mock_preview.side_effect = Exception()
13841384
response = self.the_input.handle_ajax(
13851385
"preview_formcalc",

0 commit comments

Comments
 (0)