Skip to content

Commit 70a198b

Browse files
feat(numericalInput): endpoint to validate numerical input refactored
1 parent ac46d44 commit 70a198b

7 files changed

Lines changed: 79 additions & 36 deletions

File tree

cms/djangoapps/contentstore/api/urls.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from django.conf import settings
55
from django.urls import re_path
66

7-
from cms.djangoapps.contentstore.api.views import course_import, course_quality, course_validation, utils
7+
from cms.djangoapps.contentstore.api.views import course_import, course_quality, course_validation
88

99

1010
app_name = 'contentstore'
@@ -16,7 +16,5 @@
1616
course_validation.CourseValidationView.as_view(), name='course_validation'),
1717
re_path(fr'^v1/quality/{settings.COURSE_ID_PATTERN}/$',
1818
course_quality.CourseQualityView.as_view(), name='course_quality'),
19-
re_path(r'^v1/validate/numerical-input/$',
20-
utils.NumericalInputValidationView.as_view(), name='numerical_input_validation'),
2119

2220
]

cms/djangoapps/contentstore/api/views/utils.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@
77

88
from opaque_keys.edx.keys import CourseKey
99
from rest_framework import status
10-
from rest_framework.response import Response
1110
from rest_framework.generics import GenericAPIView
12-
1311
from common.djangoapps.student.auth import has_course_author_access
1412
from openedx.core.djangoapps.util.forms import to_bool
1513
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes
1614
from openedx.core.lib.cache_utils import request_cached
1715
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
18-
from calc.preview import latex_preview
19-
import pyparsing
2016

2117

2218
@view_auth_classes()
@@ -138,19 +134,3 @@ def _wrapper_view(self, request, course_id, *args, **kwargs):
138134
)
139135
return view(self, request, course_key, *args, **kwargs)
140136
return _wrapper_view
141-
142-
143-
class NumericalInputValidationView(GenericAPIView):
144-
"""Class in charge of NumericalInputValidations"""
145-
def post(self, request):
146-
"""function to validate a math expression (formula) and return of the numeric input is valid or not"""
147-
result = {'preview': '',
148-
'is_valid': True,
149-
'error': ''}
150-
try:
151-
result['preview'] = latex_preview(request.data.get('formula'))
152-
except pyparsing.ParseException:
153-
result["error"] = "Sorry, couldn't parse formula"
154-
result['is_valid'] = False
155-
return Response(result, status=400)
156-
return Response(result)
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_block import ProblemBlock
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 = ProblemBlock.preview_numeric_input(formula)
22+
return Response(result, status=200)

xmodule/capa/inputtypes.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
import nh3
5252
import pyparsing
5353
import six
54-
from calc.preview import latex_preview
5554
from chem import chemcalc
5655
from lxml import etree
5756

@@ -1300,18 +1299,18 @@ def preview_formcalc(self, get):
13001299

13011300
result["request_start"] = int(get.get("request_start", 0))
13021301

1303-
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)
1308-
except pyparsing.ParseException:
1309-
result["error"] = _("Sorry, couldn't parse formula")
1302+
# TODO add references to valid variables and functions
1303+
# At some point, we might want to mark invalid variables as red
1304+
# or something, and this is where we would need to pass those in.
1305+
from xmodule.capa_block import ProblemBlock
1306+
numeric_result = ProblemBlock.preview_numeric_input(formula)
1307+
# Map results into the correct format
1308+
result["preview"] = numeric_result["preview"]
1309+
if numeric_result["error"]:
1310+
result["error"] = numeric_result["error"]
1311+
# if formula is invalid retrn formula
1312+
if not numeric_result["is_valid"]:
13101313
result["formula"] = formula
1311-
except Exception: # lint-amnesty, pylint: disable=broad-except
1312-
# this is unexpected, so log
1313-
log.warning("Error while previewing formula", exc_info=True)
1314-
result["error"] = _("Error while rendering preview")
13151314

13161315
return result
13171316

xmodule/capa_block.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
from .capa.xqueue_interface import XQueueService
5454
from .fields import Date, ListScoreField, ScoreField, Timedelta
5555
from .progress import Progress
56+
from calc.preview import latex_preview
57+
import pyparsing
5658

5759
log = logging.getLogger("edx.courseware")
5860

@@ -2390,6 +2392,27 @@ def score_from_lcp(self, lcp):
23902392
lcp_score = lcp.calculate_score()
23912393
return Score(raw_earned=lcp_score["score"], raw_possible=lcp_score["total"])
23922394

2395+
@classmethod
2396+
def preview_numeric_input(cls, formula):
2397+
"""
2398+
A class method for handling numeric validations, in this case
2399+
validates that the formula provided is a valid formula.
2400+
"""
2401+
result = {'preview': '',
2402+
'is_valid': True,
2403+
'error': ''}
2404+
try:
2405+
result['preview'] = latex_preview(formula)
2406+
except pyparsing.ParseException:
2407+
result["error"] = "Sorry, couldn't parse formula"
2408+
result['is_valid'] = False
2409+
return result
2410+
except Exception:
2411+
log.warning("Error while previewing formula", exc_info=True)
2412+
result['error'] = "Error while rendering preview"
2413+
result['is_valid'] = False
2414+
return result
2415+
23932416

23942417
class GradingMethodHandler:
23952418
"""

0 commit comments

Comments
 (0)