# coding: utf-8 ''' Created on 27.07.2015 ☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦ @author: tr0glo)|(I╠╣ ☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦☦ ''' from java.util import Date from time import time import json from uuid import uuid4 from ru.curs.celesta.showcase.utils import XMLJSONConverter from qt.functions import completeTest, getImageById,\ getAttributeValue, getQuestionImg, getTimeJs, getVariantParams,\ getQuestionFields, getTestingAlgorithm, getVariantAnswerParams try: from ru.curs.showcase.core.jython import JythonDTO from ru.curs.showcase.core.jython import JythonDownloadResult except: from ru.curs.celesta.showcase import JythonDTO from qt.functions import getShowCorrectAnswerPermission from qt._qt_orm import QtiVariantQuestionCursor, QtiVariantAnswerCursor, \ QtiDestructorCursor, QtiVariantDestructorCursor, QtiVariantDestructorAnswerCursor,\ QtiResourceCursor , QtiVariantParamsCursor def cardData(context, main=None, add=None, filterinfo=None, session=None, elementId=None): u'''Карточка вопроса с одиночным выбором и для вопроса с множественным выбором. ''' begin = time() sessionContext = json.loads(session) variantQuestionId = main variant_params = getVariantParams(context, variantQuestionId) variantId = variant_params['variant_id'] print 'start', time() - begin #Проверка на то, нужно ли отображать правильный ответ correctAnswerFlag = getShowCorrectAnswerPermission(context, sessionContext, variantId) print 'countquest', time() - begin testingAlgorithm = getTestingAlgorithm(context, variantId) print 'header', time() - begin variant_answer_params = getVariantAnswerParams(context, variantId) testingStatus = variant_answer_params['testingStatus'] optionList = [] resultList = [] letter = ord('A') print 'prequest', time() - begin QtiVariantDestructor = QtiVariantDestructorCursor(context) QtiVariantDestructor.setRange('VariantQuestionID',variantQuestionId) QtiVariantDestructor.orderBy('VariantDestructorID') vd_items = {} for QtiVariantDestructor in QtiVariantDestructor.iterate(): vd_items[QtiVariantDestructor.VariantDestructorID] = QtiVariantDestructor.DestructorID QtiVariantDestructor.close() QtiDestructor = QtiDestructorCursor(context) QtiVariantDestructorAnswer = QtiVariantDestructorAnswerCursor(context) for vd_id, destructor_id in vd_items.items(): QtiDestructor.get(destructor_id) # variantDestructorId = QtiVariantDestructor.VariantDestructorID destructorHtml = QtiDestructor.DestructorHtml if QtiDestructor.DestructorHtml is not None else '' destructorHtml2 = QtiDestructor.DestructorHtml2 if QtiDestructor.DestructorHtml2 is not None else '' if QtiDestructor.DestructorImg: QtiResource = QtiResourceCursor(context) destructorImg = getImageById(QtiResource, QtiDestructor.DestructorImg) QtiResource.close() else: destructorImg = '' correctFlag = False if correctAnswerFlag and QtiDestructor.IsTrue: correctFlag = True optionList.append({"id": vd_id, "letter": chr(letter), "destructorHTML": destructorHtml + destructorImg + destructorHtml2, "isTrue": 'true' if correctFlag else 'false'}) letter += 1 checked = '1_' if testingStatus != '0' else '0_' #Проверям выбирал ли текущий вариант пользователь, когда в предыдущий раз отвечал на этот вопрос QtiVariantDestructorAnswer.setRange('VariantDestructorID', vd_id) if QtiVariantDestructorAnswer.tryFirst(): if QtiVariantDestructorAnswer.IsTrue: checked += '1' else: checked += '0' else: checked += '0' resultList.append({"id": vd_id, "checked": checked}) QtiDestructor.close() QtiVariantDestructorAnswer.close() print 'calcList', time() - begin js = getTimeJs(Date(), variant_answer_params['timeEnd']) QtiVariantParams = QtiVariantParamsCursor(context) skipQuestions = getAttributeValue(QtiVariantParams, variantId, 'SkipQuestions') changeAnswer = getAttributeValue(QtiVariantParams, variantId, 'ChangeAnswer') QtiVariantParams.close() fields = getQuestionFields(context, variant_params['question_id']) questionImg = getQuestionImg(context, fields['img_id']) xformsdata = {"schema": { "@xmlns": "", "description": { "testingAlgorithm": testingAlgorithm, "js": js, "questionHeader": u'Вопрос %s из %s'%(variant_params['question_number'], variant_params['question_count']), "questionType": '1', "testingStatus": testingStatus, "showCorrect": 'true' if correctAnswerFlag else 'false', "captchaText":'', "images": questionImg, 'variantId': variantId, "skipQuestions": skipQuestions, "changeAnswer": changeAnswer, "hasAnswer": variant_params['has_answer'], "question": { "@number": variant_params['question_number'], "@isLastQuestion":'1' if variant_params['next_variant_question_id'] == 'ID_FINISH' else '0', "@timeout": variant_answer_params['timeout'], "#text": fields['question_html']},# + questionImg + questionHtml2 + ']]>' "options": {"option": optionList}}, "result": {"option": resultList}}} #Переходы к следующему и предыдущему вопросам, завершению тестирования и списку вопросов xformssettings = {"properties": { "event": [ {"@name":"single_click", "@linkId": "1", "action": { "#sorted": [ {"navigator": {"@element": variant_params['prev_variant_question_id']}}]}}, {"@name":"single_click", "@linkId": "2", "action": { "#sorted": [ {"navigator": {"@element": variant_params['next_variant_question_id']}}]}}, {"@name":"single_click", "@linkId": "3", "action": { "#sorted": [ {"navigator": {"@element": "ID_FINISH"}}]}}, {"@name":"single_click", "@linkId": "4", "action": { "#sorted": [ {"navigator": {"@element": "ID_CONTENTS"}}]}}]}} #print XMLJSONConverter(input=xformsdata).parse(), XMLJSONConverter(input=xformssettings).parse() data = XMLJSONConverter.jsonToXml(json.dumps(xformsdata)) data = data.replace(' ',' ') settings = XMLJSONConverter.jsonToXml(json.dumps(xformssettings)) print 'finish', time() - begin return JythonDTO(data, settings) def cardDataSave(context, main=None, add=None, filterinfo=None, session=None, elementId=None, xformsdata=None): u'''Процедура сохранения ответа на вопрос. Для всех типов вопросов используется общая процедура сохранения''' ip = json.loads(session)['sessioncontext']['ip'] data_json = json.loads(xformsdata)['schema'] questionType = int(data_json['description']['questionType']) variantId = data_json['description']['variantId'] variantQuestionId = main question_id = None QtiVariantQuestion = QtiVariantQuestionCursor(context) if QtiVariantQuestion.tryGet(variantQuestionId): question_id = QtiVariantQuestion.QuestionID QtiVariantQuestion.close() now = Date() QtiVariantAnswer = QtiVariantAnswerCursor(context) QtiVariantAnswer.setRange('VariantID',variantId) QtiVariantAnswer.first() timeEnd = QtiVariantAnswer.TimeFinish if QtiVariantAnswer.TimeFinish is not None else QtiVariantAnswer.TimeEnd QtiVariantAnswer.close() timeout = True if now > timeEnd else False #Если время тестирования завершилось, то ответ на текущий вопрос не сохраняем и завешаем тестирование if timeout: completeTest(context, variantId) return #Удаляем предыдущий ответ на вопрос QtiVariantDestructor = QtiVariantDestructorCursor(context) QtiVariantDestructor.setRange('VariantQuestionID', variantQuestionId) QtiVariantDestructorAnswer = QtiVariantDestructorAnswerCursor(context) for QtiVariantDestructor in QtiVariantDestructor.iterate(): QtiVariantDestructorAnswer.setRange('VariantDestructorID', QtiVariantDestructor.VariantDestructorID) QtiVariantDestructorAnswer.deleteAll() QtiVariantDestructor.close() data = data_json['result'] optionsList = [] checkFlag = True if questionType == 1 or questionType == 2: #Для вопрсов с одиночным и множественным выбором в ответы пишутся идентификаторы выбранных вариантов optionsListTemp = data['option'] if not isinstance(optionsListTemp,list): optionsListTemp = [optionsListTemp] for option in optionsListTemp: if option['checked'] == '0_1': optionsList.append(option['id']) # QtiVariantDestructor.get(option['id']) QtiVariantDestructorAnswer.VariantDestructorAnswerID = unicode(uuid4()) QtiVariantDestructorAnswer.VariantDestructorID = option['id'] QtiVariantDestructorAnswer.IsTrue = True QtiVariantDestructorAnswer.AnswerIP = ip QtiVariantDestructorAnswer.insert() if optionsList: QtiDestructor = QtiDestructorCursor(context) QtiDestructor.setRange('QuestionID', question_id) QtiDestructor.setRange('IsTrue', True) answerList = [] # Формируе список правильных вариантов отвтов for QtiDestructor in QtiDestructor.iterate(): answerList.append(QtiDestructor.DestructorID) QtiDestructor.close() QtiVariantDestructor = QtiVariantDestructorCursor(context) QtiVariantDestructor.setRange('VariantQuestionID', variantQuestionId) for QtiVariantDestructor in QtiVariantDestructor.iterate(): if QtiVariantDestructor.VariantDestructorID in optionsList: if QtiVariantDestructor.DestructorID not in answerList: checkFlag = False else: answerList.remove(QtiVariantDestructor.DestructorID) QtiVariantDestructor.close() if answerList != []: checkFlag = False elif questionType == 3: #Для текстового вопрос записывается текст ответ в поле DestructorText if data['option']['answer']: optionsList = [data['option']['answer']] variantDestructorId = data['option']['@id'] QtiVariantDestructorAnswer.VariantDestructorAnswerID = unicode(uuid4()) QtiVariantDestructorAnswer.VariantDestructorID = variantDestructorId QtiVariantDestructorAnswer.DestructorText = data['option']['answer'] QtiVariantDestructorAnswer.IsTrue = True QtiVariantDestructorAnswer.AnswerIP = ip QtiVariantDestructorAnswer.insert() if optionsList: QtiDestructor = QtiDestructorCursor(context) QtiDestructor.setRange('QuestionID', question_id) if QtiDestructor.tryFirst(): if optionsList[0] != QtiDestructor.DestructorHtml: checkFlag = False QtiDestructor.close() elif questionType == 4 or questionType == 6: #Для соответствия и классификации в DestructorId пишутся какой вариант из правого столбца был выбран if 'option2' in data: optionsList = data['option2'] if not isinstance(optionsList,list): optionsList = [optionsList] for option in optionsList: QtiVariantDestructorAnswer.VariantDestructorAnswerID = unicode(uuid4()) QtiVariantDestructorAnswer.VariantDestructorID = option['@VariantDestructorID'] QtiVariantDestructorAnswer.DestructorID = option['@DestructorID'] QtiVariantDestructorAnswer.IsTrue = True QtiVariantDestructorAnswer.AnswerIP = ip QtiVariantDestructorAnswer.insert() if optionsList: optionDict = dict((str(p['@VariantDestructorID']), p['@DestructorID']) for p in optionsList) QtiVariantDestructor = QtiVariantDestructorCursor(context) QtiVariantDestructor.setRange('VariantQuestionID', variantQuestionId) for QtiVariantDestructor in QtiVariantDestructor.iterate(): if optionDict[QtiVariantDestructor.VariantDestructorID] != QtiVariantDestructor.DestructorID: checkFlag = False QtiVariantDestructor.close() elif questionType == 5: #Для сортировки в DestructorText пишется порядковый номер варианта if 'option2' in data: optionsList = data['option2'] if not isinstance(optionsList,list): optionsList = [optionsList] for option in optionsList: QtiVariantDestructorAnswer.VariantDestructorAnswerID = unicode(uuid4()) QtiVariantDestructorAnswer.VariantDestructorID = option['@id'] QtiVariantDestructorAnswer.DestructorText = option['@text'] QtiVariantDestructorAnswer.IsTrue = True QtiVariantDestructorAnswer.AnswerIP = ip QtiVariantDestructorAnswer.insert() if optionsList: optionDict = dict((str(p['@id']), p['@text']) for p in optionsList) QtiDestructor = QtiDestructorCursor(context) QtiVariantDestructor = QtiVariantDestructorCursor(context) QtiVariantDestructor.setRange('VariantQuestionID', variantQuestionId) for QtiVariantDestructor in QtiVariantDestructor.iterate(): QtiDestructor.get(QtiVariantDestructor.DestructorID) if optionDict.get(QtiVariantDestructor.VariantDestructorID): if int(QtiDestructor.DestructorOrder) != int(optionDict[QtiVariantDestructor.VariantDestructorID]): checkFlag = False else: checkFlag = False QtiDestructor.close() QtiVariantDestructor.close() QtiVariantDestructorAnswer.close() QtiVariantQuestion = QtiVariantQuestionCursor(context) if QtiVariantQuestion.tryGet(variantQuestionId): QtiVariantQuestion.HasAnswer = True if optionsList else False QtiVariantQuestion.CorrectAnswer = checkFlag and QtiVariantQuestion.HasAnswer QtiVariantQuestion.update() QtiVariantQuestion.close()