Ejemplo n.º 1
0
    def test_do_question(self):
        """ Do a question"""

        course_id = Courses.create("TEST102", "Test question logic", 1, 1)
        self.assertGreater(course_id, 0)
        topic1_id = Topics.create(course_id, "TESTQUESTIONS1", 1, 2)
        self.assertGreater(topic1_id, 0)

        qt1_id = DB.create_qt(1, "TESTQ9", "Test question 9", 0, 5.0, 1, topic_id=topic1_id)
        self.assertIsNotNone(qt1_id)

        ver = DB.get_qt_version(qt1_id)
        self.assertGreater(ver, 0)

        data = "2\n|1\n|2\n"
        qvars = [{'A1': "2"}, {'A1': "3"}]
        for row in range(0, len(qvars)):
            DB.add_qt_variation(qt1_id, row + 1, qvars[row], ver)
        DB.create_qt_att(qt1_id, "datfile.dat", "text/plain", data , ver)
        DB.create_qt_att(qt1_id, "qtemplate.html", "text/html", "What is <VAL A1>? <ANSWER 1>", ver)

        q_id = DB.get_q_by_qt_student(qt1_id, 1)
        self.assertFalse(q_id)  # Not generated yet

        q_id = General.gen_q(qt1_id, 1)
        self.assertGreater(q_id, 0)

        q_id = DB.get_q_by_qt_student(qt1_id, 1)
        self.assertTrue(qt1_id)  # Better be there now

        DB.update_qt_maxscore(qt1_id, 7.0)
        score = DB.get_qt_maxscore(qt1_id)
        self.assertEqual(score, 7.0)
        DB.set_q_viewtime(q_id)
        self.assertIsNotNone(DB.get_q_viewtime(q_id))
Ejemplo n.º 2
0
def import_qts_from_zip(data, topic_id):
    """ Open the given OAQ file and import any qtemplates found.
        Return False if it's not valid
        Return 0 if it's valid but has no qtemplates
        Return NUM of templates imported.
    """

    # TODO: How do we protect against malicious uploads?
    # At the moment they're allowed for trusted people only,
    # but we'll eventually want this in the UI for end users.

    # eg.    unzip to huge size
    # add digital signatures?

    sdata = StringIO(data)
    tmpd = tempfile.mkdtemp(prefix="oa")
    qdir = os.path.join(tmpd, "oasisqe")
    os.mkdir(qdir)
    num = 0
    try:
        with zipfile.ZipFile(sdata, "r") as zfile:

            zfile.extractall(qdir)
            data = open("%s/info.json" % qdir, "r").read()
            info = json.loads(data)
            qtids = info['qtemplates'].keys()
            qtids.sort()
            for qtid in qtids:
                qtemplate = info['qtemplates'][qtid]['qtemplate']
                attachments = info['qtemplates'][qtid]['attachments']
                if 'position' in info['qtemplates'][qtid]:
                    position = info['qtemplates'][qtid]['position']
                else:
                    position = 0
                newid = DB.create_qt(owner=1,   # ownerid
                                     title=qtemplate['title'],
                                     desc=qtemplate['description'],
                                     marker=qtemplate['marker'],
                                     score_max=qtemplate['scoremax'],
                                     status=qtemplate['status'],
                                     topic_id=topic_id)

                DB.update_qt_practice_pos(newid, position)
                num += 1

    #            print "%s attachments" % len(attachments)
                for att in attachments:
                    (att_name, att_type, att_size) = att
                    data = open("%s/%s/attach/%s" % (qdir, qtemplate['id'], att_name)).read()
                    DB.create_qt_att(newid, att_name, att_type, data, 1)
                    if att_name == "datfile.txt" or att_name == "datfile.dat" or att_name == "datfile" or att_name == "_datfile" or att_name == "__datfile":
                        qvars = QEditor.parse_datfile(data)
                        for row in range(0, len(qvars)):
                            DB.add_qt_variation(newid, row + 1, qvars[row], 1)
    except zipfile.BadZipfile:
        return False
    Topics.flush_num_qs(topic_id)
    return num
Ejemplo n.º 3
0
def import_qts_from_zip(data, topicid):
    """ Open the given OAQ file and import any qtemplates found.
        Return False if it's not valid
        Return 0 if it's valid but has no qtemplates
        Return NUM of templates imported.
    """

    # TODO: How do we protect against malicious uploads?
    # At the moment they're allowed for trusted people only,
    # but we'll eventually want this in the UI for end users.

    # eg.    unzip to huge size
    # add digital signatures?

    sdata = StringIO(data)
    tmpd = tempfile.mkdtemp(prefix="oa")
    qdir = os.path.join(tmpd, "oasisqe")
    os.mkdir(qdir)
    with zipfile.ZipFile(sdata, "r") as zfile:

        zfile.extractall(qdir)
        data = open("%s/info.json" % qdir, "r").read()
        info = json.loads(data)
        print "%s questions found" % (len(info['qtemplates']))
        position = 1
        for qtid in info['qtemplates'].keys():
            qtemplate = info['qtemplates'][qtid]['qtemplate']
            print "%s" % qtemplate['title']
            newid = DB.create_qt(1,
                                 qtemplate['title'],
                                 qtemplate['description'],
                                 qtemplate['marker'],
                                 qtemplate['scoremax'],
                                 qtemplate['status'])
            DB.update_qt_pos(newid, topicid, position)
            position += 1
            attachments = info['qtemplates'][qtid]['attachments']

            print "%s attachments" % len(attachments)
            for att in attachments:
                (att_name, att_type, att_size) = att
                data = open("%s/%s/attach/%s" % (qdir, qtemplate['id'], att_name)).read()
                DB.create_qt_att(newid, att_name, att_type, data, 1)
                if att_name == "datfile.txt" or att_name == "datfile.dat" or att_name == "datfile" or att_name == "_datfile" or att_name == "__datfile":
                    qvars = QEditor.parse_datfile(data)
                    print "generating variations..."
                    for row in range(0, len(qvars)):
                        DB.add_qt_variation(newid, row + 1, qvars[row], 1)

    Topics.flush_num_qs(topicid)
    return 0
Ejemplo n.º 4
0
def create_new(qt_id, name):
    """
    Set the given qtemplate up as a new (default) question. Makes sure
    the appropriate things the editor needs are configured and in place.
    Assumes the QT has not previously been set up.

    :param qt_id: The ID of the qtemplate to set up.
    :param name: Name of the question.
    :return:
    """

    # The _editor.qe2 file contains a json object with most of the structural
    # information about the question.
    default_ = {
        'name': name,
        'qe_version': 0.1
    }
    DB.create_qt_att(qt_id,
                     "__editor.qe2",
                     "application/oasis-qe2",
                     json.dumps(default_),
                     1)
    return
Ejemplo n.º 5
0
def process_save(qt_id, topic_id, request, session, version):
    """ Have received a web form POST to save the current changes.

    :param qt_id: ID of the question template being edited
    :param topic_id: Topic the question template is in
    :param request: The POST request.
    :param session: The web session object
    :param version: (int) the new version of the qt being saved
    :return: None
    """

    form = request.form

    if 'blocks' in form:
        blocks = form['blocks'].encode("utf8")
        DB.create_qt_att(qt_id,
                         "__editor.qe2",
                         "text/json",
                         blocks,
                         version)
    else:
        raise KeyError("blocks")

    return
Ejemplo n.º 6
0
def create_exported_questions(fname):
    """ Make some questions and export them."""
    # Not really related to assessment, but can use this to create some questions to import and use multiple times
    course_id = Courses.create("TEST106", "Test Question Export", 1, 1)
    topic1_id = Topics.create(course_id, "TESTEXPORT1", 1, 2)
    qt1_id = DB.create_qt(1, "TESTQ1", "Test question 1", 0, 5.0, 1, topic_id=topic1_id)
    ver = DB.get_qt_version(qt1_id)

    data = "2\n|1\n|2\n"
    qvars = [{'A1': "2"}, {'A1': "3"}]
    for row in range(0, len(qvars)):
        DB.add_qt_variation(qt1_id, row + 1, qvars[row], ver)
    DB.create_qt_att(qt1_id, "datfile.dat", "text/plain", data, ver)
    DB.create_qt_att(qt1_id, "qtemplate.html", "text/html", "What is <VAL A1>? <ANSWER 1>", ver)

    qt2_id = DB.create_qt(1, "TESTQ2", "Test question 2", 0, 5.0, 1, topic_id=topic1_id)
    ver = DB.get_qt_version(qt2_id)
    data = "2\n|6\n|7\n"
    qvars = [{'A1': "6"}, {'A1': "7"}]
    for row in range(0, len(qvars)):
        DB.add_qt_variation(qt2_id, row + 1, qvars[row], ver)
    DB.create_qt_att(qt2_id, "datfile.dat", "text/plain", data, ver)
    DB.create_qt_att(qt2_id, "qtemplate.html", "text/html", "Question 2: What is <VAL A1>? <ANSWER 1>", ver)

    qt3_id = DB.create_qt(1, "TESTQ3", "Test question 3", 0, 5.0, 1, topic_id=topic1_id)
    ver = DB.get_qt_version(qt3_id)
    data = "3\n|9\n|10\n|11\n"
    qvars = [{'A1': "9"}, {'A1': "10"}, {'A1': "11"}]
    for row in range(0, len(qvars)):
        DB.add_qt_variation(qt3_id, row + 1, qvars[row], ver)
    DB.create_qt_att(qt3_id, "datfile.dat", "text/plain", data, ver)
    DB.create_qt_att(qt3_id, "qtemplate.html", "text/html", "Question 3: What is <VAL A1>? <ANSWER 1>", ver)

    data = External.topic_to_zip(topic1_id)
    f = open("%s" % fname, mode='w')
    f.write(data)
    f.close()
Ejemplo n.º 7
0
def do_topic_page_commands(request, topic_id, user_id):
    """We've been asked to perform some operations on the Topic page.

        Expecting form fields:

            selected_QTID
            position_QTID
            name_QTID

        where QTID is a question template id. May receive many.

            new_position
            new_name
            new_type

            select_cmd = 'copy' | 'move'
            select_target = TOPICID of target topic

    """

    form = request.form
    mesg = []

    # Make a list of all the commands to run
    cmdlist = []
    for command in request.form.keys():
        (cmd, data) = command.split('_', 2)
        value = form[command]
        if not value == "none":
            cmdlist += [{'cmd': cmd, 'data': data, 'value': value}]

    # Now run them:
    # Titles first
    for command in [cmd for cmd in cmdlist if cmd['cmd'] == 'name']:
        qid = int(command['data'])
        title = command['value']
        DB.update_qt_title(qid, title)

    # Then positions
    for command in [cmd for cmd in cmdlist if cmd['cmd'] == 'position']:
        qtid = int(command['data'])
        try:
            position = int(command['value'])
        except ValueError:
            position = 0
        DB.update_qt_pos(qtid, topic_id, position)

    # Then commands on selected questions
    target_cmd = form.get('target_cmd', None)
    if target_cmd:
        qtids = [int(cmd['data']) for cmd in cmdlist if cmd['cmd'] == 'select']
        try:
            target_topic = int(form.get('target_topic', 0))
        except ValueError:
            target_topic = None

        if target_cmd == 'move':
            if target_topic:
                for qtid in qtids:
                    qt_title = DB.get_qt_name(qtid)
                    topic_title = Topics.get_name(target_topic)
                    flash("Moving %s to %s" % (qt_title, topic_title))
                    DB.move_qt_to_topic(qtid, target_topic)
                    Topics.flush_num_qs(topic_id)
                    Topics.flush_num_qs(target_topic)
        if target_cmd == 'copy':
            if target_topic:
                for qtid in qtids:
                    qt_title = DB.get_qt_name(qtid)
                    topic_title = Topics.get_name(target_topic)
                    flash("Copying %s to %s" % (qt_title, topic_title))
                    newid = DB.copy_qt_all(qtid)
                    DB.add_qt_to_topic(newid, target_topic)
                    Topics.flush_num_qs(target_topic)

        if target_cmd == 'hide':
            for qtid in qtids:
                position = DB.get_qtemplate_topic_pos(qtid, topic_id)
                if position > 0:  # If visible, make it hidden
                    DB.update_qt_pos(qtid, topic_id, -position)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Hidden" % title)
                    Topics.flush_num_qs(topic_id)

        if target_cmd == 'show':
            for qtid in qtids:
                position = DB.get_qtemplate_topic_pos(qtid, topic_id)
                if position == 0:  # If hidden, make it visible
                    newpos = DB.get_qt_max_pos_in_topic(topic_id)
                    DB.update_qt_pos(qtid, topic_id, newpos + 1)
                    Topics.flush_num_qs(topic_id)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Visible" % title)
                if position < 0:  # If hidden, make it visible
                    DB.update_qt_pos(qtid, topic_id, -position)
                    Topics.flush_num_qs(topic_id)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Visible" % title)
        if target_cmd == "export":
            if len(qtids) < 1:
                flash("No questions selected to export")
            else:
                data = External.qts_to_zip(qtids, fname="oa_export", suffix="oaq")
                if not data:
                    abort(401)

                sio = StringIO.StringIO(data)
                return 2, send_file(sio, "application/oasisqe", as_attachment=True, attachment_filename="oa_export.zip")

    # Then new questions
    new_title = form.get('new_title', None)
    if new_title:
        if not (new_title == "[New Question]" or new_title == ""):
            new_position = form.get('new_position', 0)
            try:
                new_position = int(new_position)
            except ValueError:
                new_position = 0
            new_qtype = form.get('new_qtype', 'raw')
            try:
                new_maxscore = float(form.get('new_maxscore', 0))
            except ValueError:
                new_maxscore = 0
            newid = DB.create_qt(user_id,
                                 new_title,
                                 "No Description",
                                 1,
                                 new_maxscore,
                                 0)
            if newid:
                mesg.append("Created new question, id %s" % newid)
                DB.update_qt_pos(newid,
                                 topic_id,
                                 new_position)
                DB.create_qt_att(newid,
                                 "qtemplate.html",
                                 "application/oasis-html",
                                 "empty",
                                 1)
                DB.create_qt_att(newid,
                                 "qtemplate.html",
                                 "application/oasis-html",
                                 "empty",
                                 1)
                if new_qtype == "oqe":
                    mesg.append("Creating new question, id %s as OQE" % newid)
                    DB.create_qt_att(newid,
                                     "_editor.oqe",
                                     "application/oasis-oqe",
                                     "",
                                     1)
                if new_qtype == "raw":
                    mesg.append("Creating new question, id %s as RAW (%s)" %
                                (newid, new_qtype))
                    DB.create_qt_att(newid,
                                     "datfile.txt",
                                     "application/oasis-dat",
                                     "0",
                                     1)
            else:
                mesg.append("Error creating new question, id %s" % newid)
                L.error("Unable to create new question (%s) (%s)" %
                    (new_title, new_position))
    Topics.flush_num_qs(topic_id)

    return 1, {'mesg': mesg}
Ejemplo n.º 8
0
    def test_export_questions(self):
        """ Make some questions and export them."""
        course_id = Courses.create("TEST106", "Test Question Export", 1, 1)
        self.assertGreater(course_id, 0)
        topic1_id = Topics.create(course_id, "TESTEXPORT1", 1, 2)
        self.assertGreater(topic1_id, 0)

        qt1_id = DB.create_qt(1, "TESTQ1", "Test question 1", 0, 5.0, 1, topic_id=topic1_id)
        self.assertIsNotNone(qt1_id)

        ver = DB.get_qt_version(qt1_id)
        self.assertGreater(ver, 0)

        data = "2\n|1\n|2\n"
        qvars = [{'A1': "2"}, {'A1': "3"}]
        for row in range(0, len(qvars)):
            DB.add_qt_variation(qt1_id, row + 1, qvars[row], ver)
        DB.create_qt_att(qt1_id, "datfile.dat", "text/plain", data, ver)
        DB.create_qt_att(qt1_id, "qtemplate.html", "text/html", "What is <VAL A1>? <ANSWER 1>", ver)

        qt2_id = DB.create_qt(1, "TESTQ2", "Test question 2", 0, 5.0, 1, topic_id=topic1_id)
        self.assertIsNotNone(qt2_id)

        ver = DB.get_qt_version(qt2_id)
        self.assertGreater(ver, 0)

        data = "2\n|6\n|7\n"
        qvars = [{'A1': "6"}, {'A1': "7"}]
        for row in range(0, len(qvars)):
            DB.add_qt_variation(qt2_id, row + 1, qvars[row], ver)
        DB.create_qt_att(qt2_id, "datfile.dat", "text/plain", data, ver)
        DB.create_qt_att(qt2_id, "qtemplate.html", "text/html", "Question 2: What is <VAL A1>? <ANSWER 1>", ver)

        qt3_id = DB.create_qt(1, "TESTQ3", "Test question 3", 0, 5.0, 1, topic_id=topic1_id)
        self.assertIsNotNone(qt3_id)

        ver = DB.get_qt_version(qt3_id)
        self.assertGreater(ver, 0)

        data = "3\n|9\n|10\n|11\n"
        qvars = [{'A1': "9"}, {'A1': "10"}, {'A1': "11"}]
        for row in range(0, len(qvars)):
            DB.add_qt_variation(qt3_id, row + 1, qvars[row], ver)
        DB.create_qt_att(qt3_id, "datfile.dat", "text/plain", data, ver)
        DB.create_qt_att(qt3_id, "qtemplate.html", "text/html", "Question 3: What is <VAL A1>? <ANSWER 1>", ver)

        data = External.topic_to_zip(topic1_id)
        f = open("%s" % self.test_question_fname, mode='w')
        f.write(data)
        f.close()
Ejemplo n.º 9
0
def do_topic_page_commands(request, topic_id, user_id):
    """We've been asked to perform some operations on the Topic page.

        Expecting form fields:

            selected_QTID
            position_QTID
            name_QTID

        where QTID is a question template id. May receive many.

            new_position
            new_name
            new_type

            select_cmd = 'copy' | 'move'
            select_target = TOPICID of target topic

    """

    form = request.form
    mesg = []

    # Make a list of all the commands to run
    cmdlist = []
    for command in request.form.keys():
        (cmd, data) = command.split('_', 2)
        value = form[command]
        if not value == "none":
            cmdlist += [{'cmd': cmd, 'data': data, 'value': value}]

    # Now run them:
    # Titles first
    for command in [cmd for cmd in cmdlist if cmd['cmd'] == 'name']:
        qid = int(command['data'])
        title = command['value']
        DB.update_qt_title(qid, title)

    # Then positions
    for command in [cmd for cmd in cmdlist if cmd['cmd'] == 'position']:
        qtid = int(command['data'])
        try:
            position = int(command['value'])
        except ValueError:
            position = 0
        DB.update_qt_pos(qtid, topic_id, position)

    # Then commands on selected questions
    target_cmd = form.get('target_cmd', None)
    if target_cmd:
        qtids = [int(cmd['data']) for cmd in cmdlist if cmd['cmd'] == 'select']
        try:
            target_topic = int(form.get('target_topic', 0))
        except ValueError:
            target_topic = None

        if target_cmd == 'move':
            if target_topic:
                for qtid in qtids:
                    qt_title = DB.get_qt_name(qtid)
                    topic_title = Topics.get_name(target_topic)
                    flash("Moving %s to %s" % (qt_title, topic_title))
                    DB.move_qt_to_topic(qtid, target_topic)
                    Topics.flush_num_qs(topic_id)
                    Topics.flush_num_qs(target_topic)
        if target_cmd == 'copy':
            if target_topic:
                for qtid in qtids:
                    qt_title = DB.get_qt_name(qtid)
                    topic_title = Topics.get_name(target_topic)
                    flash("Copying %s to %s" % (qt_title, topic_title))
                    newid = DB.copy_qt_all(qtid)
                    DB.add_qt_to_topic(newid, target_topic)
                    Topics.flush_num_qs(target_topic)

        if target_cmd == 'hide':
            for qtid in qtids:
                position = DB.get_qtemplate_topic_pos(qtid, topic_id)
                if position > 0:  # If visible, make it hidden
                    DB.update_qt_pos(qtid, topic_id, -position)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Hidden" % title)
                    Topics.flush_num_qs(topic_id)

        if target_cmd == 'show':
            for qtid in qtids:
                position = DB.get_qtemplate_topic_pos(qtid, topic_id)
                if position == 0:  # If hidden, make it visible
                    newpos = DB.get_qt_max_pos_in_topic(topic_id)
                    DB.update_qt_pos(qtid, topic_id, newpos + 1)
                    Topics.flush_num_qs(topic_id)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Visible" % title)
                if position < 0:  # If hidden, make it visible
                    DB.update_qt_pos(qtid, topic_id, -position)
                    Topics.flush_num_qs(topic_id)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Visible" % title)
        if target_cmd == "export":
            if len(qtids) < 1:
                flash("No questions selected to export")
            else:
                data = External.qts_to_zip(qtids)
                if not data:
                    abort(401)

                sio = StringIO.StringIO(data)
                return 2, send_file(sio,
                                    "application/oasisqe",
                                    as_attachment=True,
                                    attachment_filename="oa_export.zip")

    # Then new questions
    new_title = form.get('new_title', None)
    if new_title:
        if not (new_title == "[New Question]" or new_title == ""):
            new_position = form.get('new_position', 0)
            try:
                new_position = int(new_position)
            except ValueError:
                new_position = 0
            new_qtype = form.get('new_qtype', 'raw')
            try:
                new_max_score = float(form.get('new_maxscore', 0))
            except ValueError:
                new_max_score = 0
            newid = DB.create_qt(user_id, new_title, "No Description", 1,
                                 new_max_score, 0)
            if newid:
                mesg.append("Created new question, id %s" % newid)
                DB.update_qt_pos(newid, topic_id, new_position)
                DB.create_qt_att(newid, "qtemplate.html",
                                 "application/oasis-html", "empty", 1)
                DB.create_qt_att(newid, "qtemplate.html",
                                 "application/oasis-html", "empty", 1)
                if new_qtype == "oqe":
                    mesg.append("Creating new question, id %s as OQE" % newid)
                    DB.create_qt_att(newid, "_editor.oqe",
                                     "application/oasis-oqe", "", 1)
                if new_qtype == "raw":
                    mesg.append("Creating new question, id %s as RAW (%s)" %
                                (newid, new_qtype))
                    DB.create_qt_att(newid, "datfile.txt",
                                     "application/oasis-dat", "0", 1)
            else:
                mesg.append("Error creating new question, id %s" % newid)
                L.error("Unable to create new question (%s) (%s)" %
                        (new_title, new_position))
    Topics.flush_num_qs(topic_id)

    return 1, {'mesg': mesg}