from contextlib import contextmanager import os import typing from tortoise.validators import Validator from tortoise.exceptions import ValidationError import importlib.util import types from services.timeout import timeout from .customField import is_binary_file def checkExoSupportCompatibility(obj): isPdf = False if (obj['pdf'] == None or ( obj['calcul'] == False and obj['pdf'] == False)) else True isCsv = False if (obj['csv'] == None or ( obj['calcul'] == False and obj['csv'] == False)) else True isWeb = False if (obj['web'] == None or ( obj['calcul'] == False and obj['web'] == False)) else True return { 'isPdf': isPdf, 'isCsv': isCsv, 'isWeb': isWeb} def get_module_from_string(value: str) -> types.ModuleType: spec = types.ModuleType('exo') try: exec(value, spec.__dict__) except Exception as err: raise ValidationError(f'[Error] : {err}') return spec def execute_main_if_present(spec): try: return spec.main() except AttributeError as atrerror: raise ValidationError(f"[Error] : function 'main' is missing") except Exception as e: raise ValidationError(f'[Error] : {e}') def get_spec_with_timeout(data, time): with timeout(time, ValidationError('[Error] : Script took too long')): return get_module_from_string(data) def fill_empty_values(object): default_object = {"calcul": False, 'pdf': False, 'csv': False, 'web': False, 'correction': False} return {**default_object, **object} def get_support_compatibility_for_exo_source_from_data(data: str): spec = get_spec_with_timeout(data, 5) result = execute_main_if_present(spec) result = fill_empty_values(result) exo_supports_compatibility = checkExoSupportCompatibility(result) return exo_supports_compatibility def get_support_compatibility_for_exo_source_from_path(path): if not os.path.exists(path): raise ValidationError('[Error] : No such file or directory') is_binary = is_binary_file(path) if is_binary: mode = 'rb' else: mode = 'r' with open(path, mode) as f: data = f.read() if mode == "r" else f.read().decode('utf8') return get_support_compatibility_for_exo_source_from_data(data) class ExoSourceValidator(Validator): """ A validator to validate ... """ def __call__(self, value: typing.IO): exo_supports_compatibility = get_support_compatibility_for_exo_source_from_data( value.read()) if not exo_supports_compatibility['isPdf'] and not exo_supports_compatibility['isCsv'] and not exo_supports_compatibility['isWeb']: raise ValidationError('[Error] : Exercice non valide (compatible avec aucun support)')