Пример #1
0
def get_topic_list(cid, numq=True):
    """ Return a list of dicts with topic information for the given course.
        [{ tid: int       Topic ID
          name: string   Name of Topic
          num:  int      Number of questions (if numq is false, then None)
          visibility:  int    Who can see the topic. 0 = Noone, 1 = Staff,
                                                     2 = Course, 3 = Student,
                                                     4 = Guest

        },]
    """     # TODO: magic numbers!
    tlist = []
    topics = Courses.get_topics(int(cid))
    for topic in topics:
        if numq:
            num = Topics.get_num_qs(topic)
        else:
            num = None
        tlist.append({
            'tid': topic,
            'name': Topics.get_name(topic),
            'num': num,
            'visibility': Topics.get_vis(topic)
        })
    return tlist
Пример #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
Пример #3
0
def get_topics_all(course, archived=2, numq=True):
    """ Return a summary of all topics in the course.
        if archived=0, only return non archived courses
        if archived=1, only return archived courses
        if archived=2, return all courses
        if numq is true then include the number of questions in the topic
    """
    ret = None
    if archived == 0:
        ret = run_sql("""SELECT topic, title, position, visibility, archived
                         FROM topics
                         WHERE course=%s
                           AND (archived='0' OR archived IS NULL)
                         ORDER BY position, topic;""", (course,))
    elif archived == 1:
        ret = run_sql("""SELECT topic, title, position, visibility, archived
                         FROM topics
                         WHERE course=%s
                           AND archived='1'
                         ORDER BY position, topic;""", (course,))
    elif archived == 2:
        ret = run_sql("""SELECT topic, title, position, visibility, 0
                         FROM topics
                         WHERE course=%s
                         ORDER BY position, topic;""", (course,))
    info = {}
    if ret:
        count = 0
        for row in ret:
            info[count] = {'id': int(row[0]),
                           'title': row[1],
                           'position': row[2],
                           'visibility': row[3],
                           'archived': row[4]}
            if info[count]['position'] is None or info[count]['position'] is "None":
                info[count]['position'] = 0
            if numq:
                info[count]['numquestions'] = Topics.get_num_qs(int(row[0]))
            count += 1
    else:  # we probably don't have the archived flag in the Db yet
        ret = run_sql(
            """SELECT topic, title, position, visibility
               FROM topics
               WHERE course=%s
               ORDER BY position, topic;""", (course,))
        if ret:
            count = 0
            for row in ret:
                info[count] = {'id': int(row[0]),
                               'title': row[1],
                               'position': row[2],
                               'visibility': row[3]}
                if info[count]['position'] is None or info[count]['position'] is "None":
                    info[count]['position'] = 0
                if numq:
                    info[count]['numquestions'] = Topics.get_num_qs(int(row[0]))
                count += 1
    return info
Пример #4
0
def practice_do_question(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 = Courses2.get_course(course_id)
    except KeyError:
        course = None
        abort(404)
    topictitle = "UNKNOWN"
    try:
        topictitle = Topics.get_name(topic_id)
    except KeyError:
        abort(404)
    try:
        qtemplate = DB.get_qtemplate(qt_id)
    except KeyError:
        qtemplate = None
        abort(404)
    questions = Practice.get_sorted_questions(course_id, topic_id, user_id)
    q_title = qtemplate['title']
    q_pos = DB.get_qtemplate_topic_pos(qt_id, topic_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), err:
        log(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="?",
        )
Пример #5
0
def topic_to_zip(topic_id):
    """
    :param topic_id: ID of the topic to export
    :return: binary string containing ZIPped data
    """

    topic = Topics.get_topic(topic_id)
    qts = Topics.get_qts(topic_id)

    return qts_to_zip(qts, extra_info={'topic': topic})
Пример #6
0
def topic_to_zip(topic_id):
    """
    :param topic_id: ID of the topic to export
    :return: binary string containing ZIPped data
    """

    topic = Topics.get_topic(topic_id)
    qts = Topics.get_qts(topic_id)

    return qts_to_zip(qts, extra_info={'topic': topic})
Пример #7
0
def practice_mark_question(topic_id, question_id):
    """ Mark the submitted question answersjust wa """
    user_id = session['user_id']

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

    course = Courses2.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_topic_pos(qt_id, topic_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_id, next_id = Practice.get_next_prev(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_id=next_id,
        prev_id=prev_id
    )
Пример #8
0
def practice_mark_question(topic_id, question_id):
    """ Mark the submitted question answersjust wa """
    user_id = session['user_id']

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

    course = Courses2.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_topic_pos(qt_id, topic_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_id, next_id = Practice.get_next_prev(qt_id, topic_id)  # TODO: need next_pos and prev_pos

    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_id=next_id,
        prev_id=prev_id
    )
Пример #9
0
def topic_to_zip(topic_id, fname='oa_export', suffix='oaq'):
    """
    :param topic_id: ID of the topic to export
    :param fname: filename to create
    :param suffix: suffix
    :return: binary string containing ZIPped data
    """

    topic = Topics.get_topic(topic_id)
    qts = Topics.get_qts(topic_id)

    return qts_to_zip(qts, fname=fname, extra_info={'topic': topic})
Пример #10
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
Пример #11
0
def cadmin_view_qtemplate_history(course_id, topic_id, qt_id):
    """ Show the practice history of the question template. """
    if not course_id:
        abort(404)

    course = Courses2.get_course(course_id)
    topic = {"id": topic_id, "position": Topics.get_pos(topic_id), "name": Topics.get_name(topic_id)}
    qtemplate = DB.get_qtemplate(qt_id)
    year = datetime.now().year
    years = range(year, year - 6, -1)

    return render_template(
        "courseadmin_viewqtemplate.html", course=course, topic=topic, qtemplate=qtemplate, years=years
    )
Пример #12
0
def cadmin_edit_topic(course_id, topic_id):
    """ Present a page to view and edit a topic, including adding/editing
        questions and setting some parameters.
    """
    user_id = session['user_id']

    if not course_id:
        abort(404)

    course = Courses2.get_course(course_id)
    topic = {
        'id': topic_id,
        'position': Topics.get_pos(topic_id),
        'name': Topics.get_name(topic_id)
    }
    questions = [question
                 for question in Topics.get_qts(topic_id).values()]
    for question in questions:
        question['embed_id'] = DB.get_qt_embedid(question['id'])
        if question['embed_id']:
            question['embed_url'] = "%s/embed/question/%s/question.html" % \
                                    (OaConfig.parentURL, question['embed_id'])
        else:
            question['embed_url'] = None
        question['editor'] = DB.get_qt_editor(question['id'])

    all_courses = Courses2.get_course_list()
    all_courses = [crse
                   for crse in all_courses
                   if satisfy_perms(user_id, int(crse['id']),
                                    ("questionedit", "courseadmin",
                                    "sysadmin"))]
    all_courses.sort(lambda f, s: cmp(f['name'], s['name']))

    all_course_topics = []
    for crse in all_courses:
        topics = Courses.get_topics_all(crse['id'], numq=False)
        if topics:
            all_course_topics.append({'course': crse['name'], 'topics': topics})

    questions.sort(key=lambda k: k['position'])
    return render_template(
        "courseadmin_edittopic.html",
        course=course,
        topic=topic,
        questions=questions,
        all_course_topics=all_course_topics
    )
Пример #13
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)
Пример #14
0
def api_qedit2_get_qtemplate_json(qt_id):
    """ Present a list of qtemplates that are available for use in the exam."""
    if 'user_id' not in session:
        abort(401)
    user_id = session['user_id']
    topic_id = DB.get_topic_for_qtemplate(qt_id)
    course_id = Topics.get_course_id(topic_id)
    if not satisfy_perms(user_id, course_id, ("questionedit",)):
        abort(401)

    # test data while we're building the frontend
    return jsonify(result={
        'type': "qtemplate data",
        'title': "Test QE2 Question",
        'embed_id': "aaaaaaaaa3",
        'maxscore': 3,
        'pre_vars': [
            {'id': 1, 'name': "a", 'type': 'List', 'value': "2,3,4,5,6,7"},
            {'id': 2, 'name': "b", 'type': 'Range', 'value': "1-10"},
            {'id': 3, 'name': "a1", 'type': 'Calculation', 'value': "$a+$b"},
            {'id': 4, 'name': "a2", 'type': 'Calculation', 'value': "$a*$b"},
        ],
        'qtext': "What is $a + $b ? <answer1>\nWhat is $a * $b?  <answer2> ",
        'answers': [
            {'id': 1, 'source': 'Variable', 'value': '$a1', 'tolerance': 0, 'score': 1},
            {'id': 2, 'source': 'Variable', 'value': '$a2', 'tolerance': 0, 'score': 1}
        ]
    })
Пример #15
0
    def test_assess_create(self):
        """ Create an empty assessment"""

        course_id = Courses.create("TESTCOURSE5", "unit tests for assessment", 1, 1)
        Courses.create_config(course_id, "casual", 1)
        Courses.set_active(course_id, True)
        Courses.set_prac_vis(course_id, "none")
        Courses.set_assess_vis(course_id, "none")

        title = "Test Assessment 1"
        atype = 2  # assignment
        duration = 60
        code = "123456"
        instant = 1
        instructions = "These are the instructions"
        astart = datetime.datetime.utcnow()
        aend = astart + datetime.timedelta(hours=2)

        exam_id = Exams.create(course_id, 1, title, atype, duration, astart,
                               aend, instructions, code=code, instant=instant)
        self.assertGreater(exam_id, 0)

        topic1_id = Topics.create(course_id, "TESTASSESS1", 1, 1)
        self.assertGreater(topic1_id, 0)

        data = open(self.test_question_fname).read()
        numread = External.import_qts_from_zip(data, topic1_id)
        self.assertEqual(numread, 3)
Пример #16
0
def get_q_list(tid, uid=None, numdone=True):
    """ Return a list of dicts with question template information for the topic.
        [{ qtid: int      QTemplate ID
          name: string   Name of Question
          position: int  Position of Question in topic
          done:  Number of times the given user has submitted a question
                 for practice
        },]
    """
    qlist = []
    qtemplates = Topics.get_qts(int(tid))
    for qtid in qtemplates:
        if uid and numdone:
            num = DB.get_student_q_practice_num(uid, qtid)
        else:
            num = 0
        qlist.append({
            'qtid': qtid,
            'name': qtemplates[qtid]['name'],
            'position': qtemplates[qtid]['position'],
            'done': num
        })
        # Sort them by position
    qlist.sort(lambda f, s: cmp(f["position"], s["position"]))
    return qlist
Пример #17
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))
Пример #18
0
    def test_create_qtemplate(self):
        """ Test qtemplates creation
        """

        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)

        self.assertIsInstance(qt1_id, int)
        self.assertIsInstance(qt2_id, int)

        qt1 = DB.get_qtemplate(qt1_id)
        qt2 = DB.get_qtemplate(qt2_id)

        self.assertEqual(qt1['title'], "TESTQ1")
        self.assertEqual(qt2['title'], "TESTQ2")
        self.assertEqual(qt1['description'], "Test question 1")
        self.assertEqual(qt2['description'], "Test question 2")

        course_id = Courses.create("TEST107", "Test create qtemplate", 1, 1)
        topic1_id = Topics.create(course_id, "TESTTOPIC9", 1, 2)

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

        self.assertIsInstance(qt3_id, int)

        qt3 = DB.get_qtemplate(qt3_id)
        self.assertEqual(qt3['title'], "TESTQ3")
        self.assertEqual(qt3['description'], "Test question 3")
        self.assertEqual(DB.get_topic_for_qtemplate(qt3_id), topic1_id)
Пример #19
0
def cadmin_view_topic(course_id, topic_id):
    """ Present a page to view a topic, including basic stats """
    user_id = session['user_id']

    if not course_id:
        abort(404)

    course = Courses2.get_course(course_id)
    topic = {
        'id': topic_id,
        'position': Topics.get_pos(topic_id),
        'name': Topics.get_name(topic_id)
    }
    questions = [question for question in Topics.get_qts(topic_id).values()]
    for question in questions:
        question['embed_id'] = DB.get_qt_embedid(question['id'])
        if question['embed_id']:
            question['embed_url'] = "%s/embed/question/%s/question.html" % \
                                    (OaConfig.parentURL, question['embed_id'])
        else:
            question['embed_url'] = None
        question['editor'] = DB.get_qt_editor(question['id'])

    all_courses = [
        crse for crse in Courses2.get_course_list()
        if satisfy_perms(user_id, int(crse['id']), ("questionedit",
                                                    "courseadmin", "sysadmin"))
    ]
    all_courses.sort(lambda f, s: cmp(f['name'], s['name']))

    all_course_topics = []
    for crse in all_courses:
        topics = Courses.get_topics_all(crse['id'], numq=False)
        if topics:
            all_course_topics.append({
                'course': crse['name'],
                'topics': topics
            })

    questions.sort(key=lambda k: k['position'])
    return render_template(
        "courseadmin_viewtopic.html",
        course=course,
        topic=topic,
        questions=questions,
        all_course_topics=all_course_topics,
    )
Пример #20
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))
Пример #21
0
def practice_choose_question(topic_id):
    """ Present a list of questions for them to choose from the given topic """
    user_id = session['user_id']
    try:
        course_id = Topics.get_course_id(topic_id)
    except KeyError:
        course_id = None
        abort(404)
    topics = []
    try:
        topics = Courses2.get_topics_list(course_id)
    except KeyError:
        abort(404)
    try:
        course = Courses2.get_course(course_id)
    except KeyError:
        course = None
        abort(404)
    topictitle = Topics.get_name(topic_id)
    questions = Practice.get_sorted_questions(course_id, topic_id, user_id)

    thistopic = Topics.get_topic(topic_id)
    members = []
    if thistopic['visibility'] == 2:  # course only
        if not members:
            members = Courses.get_users(course_id)
            if not user_id in members:
                abort(404)

    for topic in topics:
        if topic['visibility'] == 2:  # course only
            if not members:
                members = Courses.get_users(course_id)
            if not user_id in members:
                topics.remove(topic)

    return render_template(
        "practicetopic.html",
        canpreview=check_perm(user_id, course_id, "questionpreview"),
        topics=topics,
        topic_id=topic_id,
        course=course,
        topictitle=topictitle,
        questions=questions
    )
Пример #22
0
def practice_choose_question(topic_id):
    """ Present a list of questions for them to choose from the given topic """
    user_id = session['user_id']
    try:
        course_id = Topics.get_course_id(topic_id)
    except KeyError:
        course_id = None
        abort(404)
    topics = []
    try:
        topics = Courses2.get_topics_list(course_id)
    except KeyError:
        abort(404)
    try:
        course = Courses2.get_course(course_id)
    except KeyError:
        course = None
        abort(404)
    topictitle = Topics.get_name(topic_id)
    questions = Practice.get_sorted_questions(course_id, topic_id, user_id)

    thistopic = Topics.get_topic(topic_id)
    members = []
    if thistopic['visibility'] == 2:  # course only
        if not members:
            members = Courses.get_users(course_id)
            if user_id not in members:
                abort(404)

    for topic in topics:
        if topic['visibility'] == 2:  # course only
            if not members:
                members = Courses.get_users(course_id)
            if user_id not in members:
                topics.remove(topic)

    return render_template(
        "practicetopic.html",
        canpreview=check_perm(user_id, course_id, "questionpreview"),
        topics=topics,
        topic_id=topic_id,
        course=course,
        topictitle=topictitle,
        questions=questions
    )
Пример #23
0
    def test_import_questions(self):
        """ Import the questions made in export_questions"""
        course_id = Courses.create("TEST103", "Test import questions", 1, 1)
        self.assertGreater(course_id, 0)
        topic1_id = Topics.create(course_id, "TESTQUESTIONS1", 1, 2)
        self.assertGreater(topic1_id, 0)

        data = open(self.test_question_fname).read()
        numread = External.import_qts_from_zip(data, topic1_id)
        self.assertEqual(numread, 3)
Пример #24
0
def cadmin_view_qtemplate_history(course_id, topic_id, qt_id):
    """ Show the practice history of the question template. """
    if not course_id:
        abort(404)

    course = Courses2.get_course(course_id)
    topic = {
        'id': topic_id,
        'position': Topics.get_pos(topic_id),
        'name': Topics.get_name(topic_id)
    }
    qtemplate = DB.get_qtemplate(qt_id)
    year = datetime.now().year
    years = range(year, year - 6, -1)

    return render_template("courseadmin_viewqtemplate.html",
                           course=course,
                           topic=topic,
                           qtemplate=qtemplate,
                           years=years)
Пример #25
0
def cadmin_view_topic(course_id, topic_id):
    """ Present a page to view a topic, including basic stats """
    user_id = session["user_id"]

    if not course_id:
        abort(404)

    course = Courses2.get_course(course_id)
    topic = {"id": topic_id, "position": Topics.get_pos(topic_id), "name": Topics.get_name(topic_id)}
    questions = [question for question in Topics.get_qts(topic_id).values()]
    for question in questions:
        question["embed_id"] = DB.get_qt_embedid(question["id"])
        if question["embed_id"]:
            question["embed_url"] = "%s/embed/question/%s/question.html" % (OaConfig.parentURL, question["embed_id"])
        else:
            question["embed_url"] = None
        question["editor"] = DB.get_qt_editor(question["id"])

    all_courses = Courses2.get_course_list()
    all_courses = [
        crse
        for crse in all_courses
        if satisfy_perms(user_id, int(crse["id"]), ("questionedit", "courseadmin", "sysadmin"))
    ]
    all_courses.sort(lambda f, s: cmp(f["name"], s["name"]))

    all_course_topics = []
    for crse in all_courses:
        topics = Courses.get_topics_all(crse["id"], numq=False)
        if topics:
            all_course_topics.append({"course": crse["name"], "topics": topics})

    questions.sort(key=lambda k: k["position"])
    return render_template(
        "courseadmin_viewtopic.html",
        course=course,
        topic=topic,
        questions=questions,
        all_course_topics=all_course_topics,
    )
Пример #26
0
def get_topic_list(cid, numq=True):
    """ Return a list of dicts with topic information for the given course.
        [{ tid: int       Topic ID
          name: string   Name of Topic
          num:  int      Number of questions (if numq is false, then None)
          visibility:  int    Who can see the topic. 0 = Noone, 1 = Staff,
                                                     2 = Course, 3 = Student,
                                                     4 = Guest

        },]
    """     # TODO: magic numbers!
    tlist = []
    topics = Courses.get_topics(int(cid))
    for topic in topics:
        if numq:
            num = Topics.get_num_qs(topic)
        else:
            num = None
        tlist.append({'tid': topic,
                      'name': Topics.get_name(topic),
                      'num': num,
                      'visibility': Topics.get_vis(topic)})
    return tlist
Пример #27
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()
Пример #28
0
def practice_choose_question_stats(topic_id):
    """ Present a list of questions for them to choose from the given topic,
        and show some statistics on how they're doing.
    """
    user_id = session['user_id']

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

    topics = Courses2.get_topics_list(course_id)
    course = Courses2.get_course(course_id)
    topictitle = Topics.get_name(topic_id)
    questions = Practice.get_sorted_qlist_wstats(course_id, topic_id, user_id)

    return render_template(
        "practicetopicstats.html",
        canpreview=check_perm(user_id, course_id, "questionpreview"),
        topics=topics,
        topic_id=topic_id,
        course=course,
        topictitle=topictitle,
        questions=questions
    )
Пример #29
0
def practice_choose_question_stats(topic_id):
    """ Present a list of questions for them to choose from the given topic,
        and show some statistics on how they're doing.
    """
    user_id = session['user_id']

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

    topics = Courses2.get_topics_list(course_id)
    course = Courses2.get_course(course_id)
    topictitle = Topics.get_name(topic_id)
    questions = Practice.get_sorted_qlist_wstats(course_id, topic_id, user_id)

    return render_template(
        "practicetopicstats.html",
        canpreview=check_perm(user_id, course_id, "questionpreview"),
        topics=topics,
        topic_id=topic_id,
        course=course,
        topictitle=topictitle,
        questions=questions
    )
Пример #30
0
def do_topic_update(course, request):
    """Read the submitted form and make relevant changes to Topic information
    """
    categories = []
    topics = []

    form = request.form
    if form:
        for i in form.keys():
            parts = i.split('_')
            if len(parts) > 1:
                catid = parts[0]
                if catid not in categories:
                    categories = categories + [catid]

        for c in categories:
            topics = topics + [{'id': int(c),
                                'position': form['%s_position' % c],
                                'name': form['%s_name' % c],
                                'visibility': form['%s_visibility' % c]
                                }]
        for i in topics:
            if not i['id'] == 0:
                Topics.set_pos(i['id'], i['position'])
                Topics.set_name(int(i['id']), i['name'])
                Topics.set_vis(i['id'], i['visibility'])
                Courses.incr_version()
            else:
                if not i['name'] == "[Name of new topic]":
                    Topics.create(course['id'],
                                  i['name'],
                                  int(i['visibility']),
                                  i['position'])
                    Courses.incr_version()

        return True

    return False
Пример #31
0
def do_topic_update(course, request):
    """Read the submitted form and make relevant changes to Topic information
    """
    categories = []
    topics = []

    form = request.form
    if form:
        for i in form.keys():
            parts = i.split('_')
            if len(parts) > 1:
                catid = parts[0]
                if catid not in categories:
                    categories = categories + [catid]

        for c in categories:
            topics = topics + [{
                'id': int(c),
                'position': form['%s_position' % c],
                'name': form['%s_name' % c],
                'visibility': form['%s_visibility' % c]
            }]
        for i in topics:
            if not i['id'] == 0:
                Topics.set_pos(i['id'], i['position'])
                Topics.set_name(int(i['id']), i['name'])
                Topics.set_vis(i['id'], i['visibility'])
                Courses.incr_version()
            else:
                if not i['name'] == "[Name of new topic]":
                    Topics.create(course['id'], i['name'],
                                  int(i['visibility']), i['position'])
                    Courses.incr_version()

        return True

    return False
Пример #32
0
def get_q_list(tid, uid=None, numdone=True):
    """ Return a list of dicts with question template information for the topic.
        [{ qtid: int      QTemplate ID
          name: string   Name of Question
          position: int  Position of Question in topic
          done:  Number of times the given user has submitted a question
                 for practice
        },]
    """
    qlist = []
    qtemplates = Topics.get_qts(int(tid))
    for qtid in qtemplates:
        if uid and numdone:
            num = DB.get_student_q_practice_num(uid, qtid)
        else:
            num = 0
        qlist.append({'qtid': qtid,
                      'name': qtemplates[qtid]['name'],
                      'position': qtemplates[qtid]['position'],
                      'done': num})
        # Sort them by position
    qlist.sort(lambda f, s: cmp(f["position"], s["position"]))
    return qlist
Пример #33
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()
Пример #34
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}
Пример #35
0
    def test_create_topic(self):
        """ Fetch a topic back and check it
        """

        course_id = Courses.create("TEST101", "Test topic position logic", 1, 1)

        self.assertDictContainsSubset(
            {course_id:
                 {'active': 1,
                  'assess_visibility': 'enrol',
                  'id': course_id,
                  'name': 'TEST101',
                  'owner': 1,
                  'practice_visibility': 'all',
                  'title': 'Test topic position logic',
                  'type': 1
                  }
             },
            Courses.get_courses_dict(),
        )

        topic1_id = Topics.create(course_id, "TESTTOPIC1", 1, 2)
        topic2_id = Topics.create(course_id, "TESTTOPIC2", 3, 3)

        self.assertGreater(topic1_id, 0)
        self.assertIsInstance(topic1_id, int)

        self.assertGreater(topic2_id, 0)
        self.assertIsInstance(topic2_id, int)

        self.assertNotEqual(topic1_id, topic2_id)

        topic1 = Topics.get_topic(topic1_id)
        topic2 = Topics.get_topic(topic2_id)

        self.assertEqual(topic1['id'], topic1_id)
        self.assertEqual(topic2['id'], topic2_id)
        self.assertEqual(topic1['title'], "TESTTOPIC1")
        self.assertEqual(topic2['title'], "TESTTOPIC2")
        self.assertEqual(topic1['visibility'], 1)
        self.assertEqual(topic2['visibility'], 3)

        self.assertEqual(Topics.get_name(topic1_id), topic1['title'])

        Topics.set_name(topic1_id, "NEWNAME1")
        self.assertEqual(Topics.get_name(topic1_id), "NEWNAME1")

        self.assertEqual(Topics.get_num_qs(topic1_id), 0)

        self.assertEqual(Topics.get_pos(topic1_id), 2)

        Topics.set_pos(topic1_id, 8)
        self.assertEqual(Topics.get_pos(topic1_id), 8)
Пример #36
0
def get_topics_all(course, archived=2, numq=True):
    """ Return a summary of all topics in the course.
        if archived=0, only return non archived courses
        if archived=1, only return archived courses
        if archived=2, return all courses
        if numq is true then include the number of questions in the topic
    """
    ret = None
    if archived == 0:
        ret = run_sql(
            """SELECT topic, title, position, visibility, archived
                         FROM topics
                         WHERE course=%s
                           AND (archived='0' OR archived IS NULL)
                         ORDER BY position, topic;""", (course, ))
    elif archived == 1:
        ret = run_sql(
            """SELECT topic, title, position, visibility, archived
                         FROM topics
                         WHERE course=%s
                           AND archived='1'
                         ORDER BY position, topic;""", (course, ))
    elif archived == 2:
        ret = run_sql(
            """SELECT topic, title, position, visibility, 0
                         FROM topics
                         WHERE course=%s
                         ORDER BY position, topic;""", (course, ))
    info = {}
    if ret:
        count = 0
        for row in ret:
            info[count] = {
                'id': int(row[0]),
                'title': row[1],
                'position': row[2],
                'visibility': row[3],
                'archived': row[4]
            }
            if info[count]['position'] is None or info[count][
                    'position'] is "None":
                info[count]['position'] = 0
            if numq:
                info[count]['numquestions'] = Topics.get_num_qs(int(row[0]))
            count += 1
    else:  # we probably don't have the archived flag in the Db yet
        ret = run_sql(
            """SELECT topic, title, position, visibility
               FROM topics
               WHERE course=%s
               ORDER BY position, topic;""", (course, ))
        if ret:
            count = 0
            for row in ret:
                info[count] = {
                    'id': int(row[0]),
                    'title': row[1],
                    'position': row[2],
                    'visibility': row[3]
                }
                if info[count]['position'] is None or info[count][
                        'position'] is "None":
                    info[count]['position'] = 0
                if numq:
                    info[count]['numquestions'] = Topics.get_num_qs(int(
                        row[0]))
                count += 1
    return info
Пример #37
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}
Пример #38
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 = Courses2.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_topic_pos(qt_id, topic_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,
    )
Пример #39
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 = Courses2.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_topic_pos(qt_id, topic_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,
    )
Пример #40
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}