Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v2/serializers/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Serializers for the contentstore v2 utils views module.

This module contains DRF serializers for different utils like validations.
"""

from rest_framework import serializers


class NumericalInputValidationRequestSerializer(serializers.Serializer):
formula = serializers.CharField()


class NumericalInputValidationReponseSerializer(serializers.Serializer):
preview = serializers.CharField()
is_valid = serializers.BooleanField()
error = serializers.CharField(allow_null=True)
6 changes: 5 additions & 1 deletion cms/djangoapps/contentstore/rest_api/v2/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.conf import settings
from django.urls import path, re_path

from cms.djangoapps.contentstore.rest_api.v2.views import downstreams, home
from cms.djangoapps.contentstore.rest_api.v2.views import downstreams, home, utils

app_name = "v2"

Expand Down Expand Up @@ -33,4 +33,8 @@
downstreams.SyncFromUpstreamView.as_view(),
name="sync_from_upstream"
),
re_path(
'^validate/numerical-input/$',
utils.NumericalInputValidationView.as_view(),
name='numerical_input_validation'),
]
22 changes: 22 additions & 0 deletions cms/djangoapps/contentstore/rest_api/v2/views/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
Common utilities for V2 APIs.
"""
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework import permissions
from cms.djangoapps.contentstore.rest_api.v2.serializers.utils import NumericalInputValidationRequestSerializer
from xmodule.capa.inputtypes import preview_numeric_input


class NumericalInputValidationView(GenericAPIView):
"""Class in charge of NumericalInputValidations"""
permission_classes = (permissions.IsAuthenticated,)
serializer_class = NumericalInputValidationRequestSerializer

def post(self, request):
"""function to validate a math expression (formula) and return of the numeric input is valid or not"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
formula = serializer.validated_data['formula']
result = preview_numeric_input(formula)
return Response(result, status=200)
41 changes: 33 additions & 8 deletions xmodule/capa/inputtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@

import html5lib
import nh3
import pyparsing
import six
from calc.preview import latex_preview
import pyparsing
from chem import chemcalc
from lxml import etree

Expand Down Expand Up @@ -1300,22 +1300,47 @@ def preview_formcalc(self, get):

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

# TODO add references to valid variables and functions
# At some point, we might want to mark invalid variables as red
# or something, and this is where we would need to pass those in.
try:
# TODO add references to valid variables and functions
# At some point, we might want to mark invalid variables as red
# or something, and this is where we would need to pass those in.
result["preview"] = latex_preview(formula)
numeric_result = preview_numeric_input(formula)
# Map results into the correct format
result["preview"] = numeric_result["preview"]
if numeric_result["error"]:
result["error"] = numeric_result["error"]
# if formula is invalid return formula
if not numeric_result["is_valid"]:
result["formula"] = formula
except pyparsing.ParseException:
result["error"] = _("Sorry, couldn't parse formula")
result["formula"] = formula
result['error'] = _("Sorry, couldn't parse formula")
result['formula'] = formula
except Exception: # lint-amnesty, pylint: disable=broad-except
# this is unexpected, so log
log.warning("Error while previewing formula", exc_info=True)
result["error"] = _("Error while rendering preview")
return result

return result


def preview_numeric_input(formula):
"""
Handles numeric validations, validates that the formula provided is a valid formula.
"""
result = {'preview': '', 'is_valid': True, 'error': ''}
try:
result['preview'] = latex_preview(formula)
except pyparsing.ParseException:
result["error"] = "Sorry, couldn't parse formula"
result['is_valid'] = False
return result
except Exception: # pylint: disable=broad-exception-caught
log.warning("Error while previewing formula", exc_info=True)
result['error'] = "Error while rendering preview"
result['is_valid'] = False
return result


# -----------------------------------------------------------------------------


Expand Down
4 changes: 2 additions & 2 deletions xmodule/capa/tests/test_inputtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,7 @@ def test_ajax_parse_err(self):
With parse errors, FormulaEquationInput should give an error message
"""
# Simulate answering a problem that raises the exception
with patch("xmodule.capa.inputtypes.latex_preview") as mock_preview:
with patch('xmodule.capa.inputtypes.preview_numeric_input') as mock_preview:
mock_preview.side_effect = ParseException("Oopsie")
response = self.the_input.handle_ajax(
"preview_formcalc",
Expand All @@ -1379,7 +1379,7 @@ def test_ajax_other_err(self, mock_log):
"""
With other errors, test that FormulaEquationInput also logs it
"""
with patch("xmodule.capa.inputtypes.latex_preview") as mock_preview:
with patch('xmodule.capa.inputtypes.preview_numeric_input') as mock_preview:
mock_preview.side_effect = Exception()
response = self.the_input.handle_ajax(
"preview_formcalc",
Expand Down
Loading