Ejemplo n.º 1
0
    def test_topic_position(self):
        """ Test putting qtemplates into topics and moving them around
        """

        course_id = Courses.create("TEST101", "Test topic position logic", 1, 1)
        topic1_id = Topics.create(course_id, "TESTTOPIC1", 1, 2)
        topic2_id = Topics.create(course_id, "TESTTOPIC2", 3, 3)
        qt1_id = DB.create_qt(1, "TESTQ1", "Test question 1", 0, 5.0, 1)
        qt2_id = DB.create_qt(1, "TESTQ2", "Test question 2", 0, 4.1, 2, topic1_id)

        DB.move_qt_to_topic(qt1_id, topic1_id)

        self.assertEqual(DB.get_qtemplate_practice_pos(qt1_id), 0)
        self.assertEqual(DB.get_qtemplate_practice_pos(qt2_id), 0)

        self.assertEqual(DB.get_topic_for_qtemplate(qt1_id), topic1_id)
        self.assertEqual(DB.get_topic_for_qtemplate(qt2_id), topic1_id)

        DB.update_qt_practice_pos(qt1_id, 3)
        DB.update_qt_practice_pos(qt2_id, 2)

        self.assertEqual(DB.get_qtemplate_practice_pos(qt1_id), 3)
        self.assertEqual(DB.get_qtemplate_practice_pos(qt2_id), 2)

        self.assertEqual(DB.get_qtemplate_practice_pos(qt1_id), 3, "Broken cache?")
        self.assertEqual(DB.get_qtemplate_practice_pos(qt2_id), 2, "Broken cache?")

        DB.update_qt_practice_pos(qt1_id, 0)
        DB.update_qt_practice_pos(qt2_id, -1)

        self.assertEqual(DB.get_qtemplate_practice_pos(qt1_id), 0)
        self.assertEqual(DB.get_qtemplate_practice_pos(qt2_id), -1)

        self.assertEqual(DB.get_qtemplate_practice_pos(qt1_id), 0, "Broken cache?")
        self.assertEqual(DB.get_qtemplate_practice_pos(qt2_id), -1, "Broken cache?")

        qts = Topics.get_qts(topic1_id)

        self.assertIn(qt1_id, qts)
        self.assertIn(qt2_id, qts)
        self.assertEqual(len(qts), 2)

        DB.move_qt_to_topic(qt1_id, topic2_id)
        qts = Topics.get_qts(topic1_id)

        self.assertNotIn(qt1_id, qts)
        self.assertIn(qt2_id, qts)
        self.assertEqual(len(qts), 1)
Ejemplo n.º 2
0
    def test_topic_nextprev(self):
        """ Do the "next/previous" options in practice work?
        """

        course_id = Courses.create("TEST101", "Test topic next/prev logic", 1, 1)
        topic1_id = Topics.create(course_id, "TESTTOPIC1", 1, 2)

        qt1_id = DB.create_qt(1, "TESTQ1", "Test question 1", 0, 5.0, 1)
        qt2_id = DB.create_qt(1, "TESTQ2", "Test question 2", 0, 4.1, 2)
        qt3_id = DB.create_qt(1, "TESTQ3", "Test question 3", 0, 0.0, 2)
        qt4_id = DB.create_qt(1, "TESTQ4", "Test question 4", 0, 2.0, 2)

        DB.move_qt_to_topic(qt1_id, topic1_id)
        DB.move_qt_to_topic(qt2_id, topic1_id)
        DB.move_qt_to_topic(qt3_id, topic1_id)
        DB.move_qt_to_topic(qt4_id, topic1_id)

        DB.update_qt_practice_pos(qt1_id, 1)
        DB.update_qt_practice_pos(qt2_id, 2)
        DB.update_qt_practice_pos(qt3_id, 3)
        DB.update_qt_practice_pos(qt4_id, 4)

        qts = Topics.get_qts(topic1_id)
        self.assertIn(qt1_id, qts)
        self.assertIn(qt2_id, qts)
        self.assertIn(qt3_id, qts)
        self.assertIn(qt4_id, qts)
        self.assertEqual(len(qts), 4)

        self.assertTupleEqual(Practice.get_next_prev_pos(qt1_id, topic1_id), (None, 2))
        self.assertTupleEqual(Practice.get_next_prev_pos(qt2_id, topic1_id), (1, 3))
        self.assertTupleEqual(Practice.get_next_prev_pos(qt3_id, topic1_id), (2, 4))
        self.assertTupleEqual(Practice.get_next_prev_pos(qt4_id, topic1_id), (3, None))

        DB.update_qt_practice_pos(qt2_id, 3)

        self.assertEqual(DB.get_qtemplate_practice_pos(qt1_id), 1)
        self.assertEqual(DB.get_qtemplate_practice_pos(qt2_id), 3)
        self.assertEqual(DB.get_qtemplate_practice_pos(qt3_id), 3)
        self.assertEqual(DB.get_qtemplate_practice_pos(qt4_id), 4)

        self.assertTupleEqual(Practice.get_next_prev_pos(qt1_id, topic1_id), (None, 3))
        self.assertTupleEqual(Practice.get_next_prev_pos(qt2_id, topic1_id), (1, 4))
        self.assertTupleEqual(Practice.get_next_prev_pos(qt3_id, topic1_id), (1, 4))
        self.assertTupleEqual(Practice.get_next_prev_pos(qt4_id, topic1_id), (3, None))

        self.assertTupleEqual(Practice.get_next_prev_pos(qt4_id, None), (None, None))
Ejemplo n.º 3
0
def practice_mark_question(topic_id, question_id):
    """ Mark the submitted question answers """
    user_id = session['user_id']

    course_id = Topics.get_course_id(topic_id)
    if not course_id:
        abort(404)

    course = Courses.get_course(course_id)
    if not course:
        abort(404)

    topictitle = "UNKNOWN"
    try:
        topictitle = Topics.get_name(topic_id)
    except KeyError:
        abort(404)

    qt_id = DB.get_q_parent(question_id)

    q_title = DB.get_qt_name(qt_id)
    questions = Practice.get_sorted_questions(course_id, topic_id, user_id)
    q_pos = DB.get_qtemplate_practice_pos(qt_id)

    blocked = Practice.is_q_blocked(user_id, course_id, topic_id, qt_id)
    if blocked:
        return render_template(
            "practicequestionblocked.html",
            mesg=blocked,
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    marking = Practice.mark_q(user_id, topic_id, question_id, request)
    prev_pos, next_pos = Practice.get_next_prev_pos(qt_id, topic_id)

    return render_template(
        "practicemarkquestion.html",
        topictitle=topictitle,
        topic_id=topic_id,
        qt_id=qt_id,
        course=course,
        q_title=q_title,
        questions=questions,
        q_pos=q_pos,
        q_id=question_id,
        marking=marking,
        next_pos=next_pos,
        prev_pos=prev_pos
    )
Ejemplo n.º 4
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
    files = request.files

    mesg = []

    # Make a list of all the commands to run
    cmdlist = []
    for command in request.form.keys():
        if '_' in command:
            (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_practice_pos(qtid, 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(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))
                    position = DB.get_qtemplate_practice_pos(qtid)
                    newid = DB.copy_qt_all(qtid)
                    DB.move_qt_to_topic(newid, target_topic, position)
                    Topics.flush_num_qs(target_topic)

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

        if target_cmd == 'show':
            for qtid in qtids:
                position = DB.get_qtemplate_practice_pos(qtid)
                if position == 0:  # If hidden, make it visible
                    newpos = DB.get_qt_max_pos_in_topic(topic_id)
                    DB.update_qt_practice_pos(qtid, newpos + 1)
                    title = DB.get_qt_name(qtid)
                    flash("Made '%s' Visible" % title)
                if position < 0:  # If hidden, make it visible
                    DB.update_qt_practice_pos(qtid, -position)
                    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
            new_id = DB.create_qt(owner=user_id,
                                  title=new_title,
                                  desc="No Description",
                                  marker=1,
                                  score_max=new_max_score,
                                  status=0,
                                  topic_id=topic_id)
            if new_id:
                mesg.append("Created new question, id %s" % new_id)
                if new_position and new_position >= 1:
                    DB.update_qt_practice_pos(new_id, new_position)

                if new_qtype == "qe2":
                    mesg.append("Creating new question, id %s as QE2" % new_id)
                    QEditor2.create_new(new_id, new_title)

                if new_qtype == "raw":
                    mesg.append("Creating new question, id %s as RAW (%s)" %
                                (new_id, new_qtype))
                    QEditor.create_new(new_id, new_title)

            else:
                mesg.append("Error creating new question, id %s" % new_id)
                L.error("Unable to create new question (%s) (%s)" %
                        (new_title, new_position))

    L.info("request.files = %s" % (repr(request.files.keys())))
    # Did they upload a file to import?
    if 'import_file' in request.files:
        L.info("File upload to topic %s by user %s" % (topic_id, user_id))
        data = files['import_file'].read()
        if len(data) > 1:
            for msg in _import_questions_from_file(data, topic_id):
                mesg.append(msg)

    Topics.flush_num_qs(topic_id)

    return 1, {'mesg': mesg}
Ejemplo n.º 5
0
def qts_to_zip(qt_ids, extra_info=None):
    """ Take a list of QTemplate IDs and return a binary string containing
        them as an .oaq file.
        (a zip file in special format)
    """

    qdir = tempfile.mkdtemp(prefix="oa")
    info = {
        'oasis': {
            'oa_version': "3.9.4",
            'qt_version': '0.9',
            'url': OaConfig.parentURL
        },
        'qtemplates': {},
        'extra': extra_info
    }

    arc = zipfile.ZipFile(os.path.join(qdir, "oasisqe.zip"),
                          'w',
                          zipfile.ZIP_DEFLATED)
    for qt_id in qt_ids:
        qtemplate = DB.get_qtemplate(qt_id)
        qtdir = os.path.join(qdir, str(qt_id))
        attachments = DB.get_qt_atts(qt_id)
        if 'qtemplate.html' not in attachments:
            attachments.append('qtemplate.html')
        if 'datfile.txt' not in attachments:
            attachments.append('datfile.txt')
        if 'image.gif' not in attachments:
            attachments.append('image.gif')
        os.mkdir(qtdir)
        os.mkdir(os.path.join(qtdir, "attach"))
        info["qtemplates"][qt_id] = {'qtemplate': qtemplate}
        info["qtemplates"][qt_id]["attachments"] = []
        info["qtemplates"][qt_id]["position"] = DB.get_qtemplate_practice_pos(qt_id)

        for name in attachments:
            if not name:
                name = 'UNKNOWN'
            mtype = DB.get_qt_att_mimetype(qt_id, name)
            if not mtype:
                mtype = ""
            data = DB.get_qt_att(qt_id, name)
            if not data:
                data = ""
            info["qtemplates"][qt_id]["attachments"].append([name, mtype, len(data)])
            subdir = os.path.join(qtdir, "attach", name)
            outf = open(subdir, "wb")
            outf.write(data)
            outf.close()
            arc.write(subdir,
                      os.path.join("%s" % qt_id, "attach", name),
                      zipfile.ZIP_DEFLATED)

    infof = open(os.path.join(qdir, "info.json"), "wb")
    infof.write(json.dumps(info))
    infof.close()
    arc.write(os.path.join(qdir, "info.json"),
              os.path.join("info.json"),
              zipfile.ZIP_DEFLATED)
    arc.close()

    readback = open(os.path.join(qdir, "oasisqe.zip"), "rb")
    data = readback.read()
    readback.close()
    shutil.rmtree(qdir)
    return data
Ejemplo n.º 6
0
def practice_do_question_id(topic_id, qt_id):
    """ Show them a question and allow them to fill in some answers """
    user_id = session['user_id']
    try:
        course_id = Topics.get_course_id(topic_id)
    except KeyError:
        course_id = None
        abort(404)
    try:
        course = Courses.get_course(course_id)
    except KeyError:
        course = None
        abort(404)
    topictitle = "UNKNOWN"
    try:
        topictitle = Topics.get_name(topic_id)
    except KeyError:
        abort(404)

    qtemplate = DB.get_qtemplate(qt_id)

    questions = Practice.get_sorted_questions(course_id, topic_id, user_id)
    q_title = qtemplate['title']
    q_pos = DB.get_qtemplate_practice_pos(qt_id)

    blocked = Practice.is_q_blocked(user_id, course_id, topic_id, qt_id)
    if blocked:
        return render_template(
            "practicequestionblocked.html",
            mesg=blocked,
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    try:
        q_id = Practice.get_practice_q(qt_id, user_id)
    except (ValueError, TypeError) as err:
        L.error("ERROR 1001  (%s,%s) %s" % (qt_id, user_id, err))
        return render_template(
            "practicequestionerror.html",
            mesg="Error generating question.",
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    if not q_id > 0:
        L.error("ERROR 1002  (%s,%s) Question not generated" % (qt_id, user_id))
        return render_template(
            "practicequestionerror.html",
            mesg="Error generating question.",
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    q_body = General.render_q_html(q_id)
    q_body = q_body.replace(r"\240", u" ")  # TODO: why is this here?

    return render_template(
        "practicedoquestion.html",
        q_body=q_body,
        topictitle=topictitle,
        topic_id=topic_id,
        qt_id=qt_id,
        course=course,
        q_title=q_title,
        questions=questions,
        q_pos=q_pos,
        q_id=q_id,
    )
Ejemplo n.º 7
0
def practice_do_question(topic_id, position):
    """ Show them a question and allow them to fill in some answers """
    user_id = session['user_id']
    try:
        course_id = Topics.get_course_id(topic_id)
    except KeyError:
        course_id = None
        abort(404)
    try:
        course = Courses.get_course(course_id)
    except KeyError:
        course = None
        abort(404)
    topictitle = "UNKNOWN"
    try:
        topictitle = Topics.get_name(topic_id)
    except KeyError:
        abort(404)
    try:
        choices = DB.get_qtemplates_in_topic_position(topic_id, position)
    except KeyError:
        choices = None
        abort(404)

    if len(choices) == 1:
        qt_id = choices[0]
    elif len(choices) > 1:
        L.debug("Practice choosing random from: %s" % repr(choices))
        qt_id = random.choice(choices)
    else:
        L.warn("Access to non existent practice topic %s question %s" % (topic_id, position))
        return render_template(
            "practicequestionerror.html",
            mesg="Error accessing question.",
            topic_id=topic_id,
            course=course,
            q_pos=position
        )

    qtemplate = DB.get_qtemplate(qt_id)

    questions = Practice.get_sorted_questions(course_id, topic_id, user_id)
    q_title = qtemplate['title']
    q_pos = DB.get_qtemplate_practice_pos(qt_id)

    blocked = Practice.is_q_blocked(user_id, course_id, topic_id, qt_id)
    if blocked:
        return render_template(
            "practicequestionblocked.html",
            mesg=blocked,
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    try:
        q_id = Practice.get_practice_q(qt_id, user_id)
    except (ValueError, TypeError) as err:
        L.error("ERROR 1001  (%s,%s) %s" % (qt_id, user_id, err))
        return render_template(
            "practicequestionerror.html",
            mesg="Error generating question.",
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    if not q_id > 0:
        L.error("ERROR 1002  (%s,%s) Question not generated" % (qt_id, user_id))
        return render_template(
            "practicequestionerror.html",
            mesg="Error generating question.",
            topictitle=topictitle,
            topic_id=topic_id,
            qt_id=qt_id,
            course=course,
            q_title=q_title,
            questions=questions,
            q_pos=q_pos,
        )

    q_body = General.render_q_html(q_id)
    q_body = q_body.replace(r"\240", u" ")  # TODO: why is this here?

    return render_template(
        "practicedoquestion.html",
        q_body=q_body,
        topictitle=topictitle,
        topic_id=topic_id,
        qt_id=qt_id,
        course=course,
        q_title=q_title,
        questions=questions,
        q_pos=q_pos,
        q_id=q_id,
    )