Пример #1
0
    def set_from_file(self):
        self.init_code = ""
        self.iter_code = ""
        self.text = "\n\n<h3>ERROR: no code exists for question '{}' for language '{}'!</h3>".format(
            self.q_id, PageLanguage.toStr(self.language))

        self.page.add_lines(
            "\n<!-- Rendering question '{}' for language '{}' -->\n\n".format(
                self.q_id, PageLanguage.toStr(self.language)))

        q = self.repository.get_question(self.q_id)
        if q is None:
            return

        if "init.lua" in q.keys():
            #logging.debug("%s, %s", str(q.keys()), str(q))
            self.init_code = q["init.lua"]

        if "iter.lua" in q.keys():
            self.iter_code = q["iter.lua"]

        text_key = "text." + PageLanguage.toStr(self.language)
        if text_key in q.keys():
            self.text = q[text_key]
        else:
            logging.error("Question '{}' not found ({}).".format(
                self.q_id, text_key))
Пример #2
0
    def get_prev_next_questions_browse_url(self):

        prev_question, next_question = self.choose_next_question_browse()

        if prev_question:
            url_prev = self.page.page_params.create_url(
                op=PageOperation.BROWSE,
                language=PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                q_id=prev_question["name"],
                q_num="0",
                beta=True if self.page.page_params.get_param("beta") else None)
        else:
            url_prev = None

        if next_question:
            url_next = self.page.page_params.create_url(
                op=PageOperation.BROWSE,
                language=PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                q_id=next_question["name"],
                q_num="0",
                beta=True if self.page.page_params.get_param("beta") else None)
        else:
            url_next = None

        return url_prev, url_next
Пример #3
0
def prepare_user_stats_chart(pg, u_ID):

    if (u_ID == "UNKNOWN" or u_ID == "local:UNKNOWN"):
        user_stats = context.c.session.get("anon_stats")
    else:
        user_stats = render_stats_data(pg, u_ID)

    pg.template_params["template_name"] = pg.page_params.get_param("language").value + "/" + "stats.html.j2"

    pg.template_params["class_gen_str"] = pg.get_messages()["year"]
    #pg.template_params["class_gen_str"] = 'Razred'

    pg.template_params["stats"] = {}

    if user_stats:
        sorted_levels = list(user_stats['level'].keys())
        sorted_levels.sort()
    else:
        sorted_levels = []

    #for level_key, level_val in user_stats['level'].items():
    for level_key in sorted_levels:
        level_val = user_stats['level'][level_key]
        level_short=level_val['level_short']
        pg.template_params["stats"][level_key] = {}
        pg.template_params["stats"][level_key]['level_short'] = level_short
        for theme_key, theme_val in level_val['theme'].items():
            pg.template_params["stats"][level_key][theme_key] = draw_chart(theme_val['subtheme'], pg)

    pg.template_params["url_year"] = pg.page_params.create_url(
                                    op=PageOperation.MENU_YEAR, \
                                    language = PageLanguage.toStr(pg.page_params.get_param("language")), 
                                    year = "", \
                                    theme = "", \
                                    subtheme = "", \
                                    topic = "", \
                                    difficulty = "", \
                                    period = "", \
                                    beta = True if pg.page_params.get_param("beta") else None)

    pg.template_params["url_theme"] = pg.page_params.create_url(
                                    op=PageOperation.MENU_THEME, \
                                    language = PageLanguage.toStr(pg.page_params.get_param("language")), 
                                    year=pg.page_params.get_param("year"), \
                                    theme = "", \
                                    subtheme = "", \
                                    topic = "", \
                                    difficulty = "", \
                                    period = "", \
                                    beta = True if pg.page_params.get_param("beta") else None)


    #print(json.dumps(pg.template_params["stats"], indent=2))

    return
Пример #4
0
 def get_language_details(self, language=None):
     if language is None:
         language = PageLanguage.toStr(
             self.page_params.get_param("language"))
     if language in self.app_data.messages.keys():
         return self.app_data.messages[language]
     return self.app_data.messages["rs"]
Пример #5
0
    def get_prev_question_test_url(self):
        if len(context.c.session.get("history")) <= 1:
            url_prev = self.page.page_params.create_url(\
                        op = PageOperation.MENU_THEME,
                        language = PageLanguage.toStr(self.page.page_params.get_param("language")),
                        beta=True if self.page.page_params.get_param("beta") else None)
        else:
            q_id = context.c.session.get("history")[-2]["q_id"]
            q_number = self.get_q_number()
            url_prev = self.page.page_params.create_url(\
                        op = PageOperation.TEST_PREV,
                        language = PageLanguage.toStr(self.page.page_params.get_param("language")),
                        q_id = q_id,
                        q_num = str(q_number-1),
                        beta=True if self.page.page_params.get_param("beta") else None)

        return url_prev
Пример #6
0
    def logout(self):
        logging.info("logout: closing session")
        context.c.user = None
        context.c.session.close()

        # url = self.page_params.get_param("root") + "?op={}".format(PageOperation.MENU_USER.value)

        url = self.page_params.create_url( \
            op = PageOperation.MENU_USER,
            language = PageLanguage.toStr(self.page_params.get_param("language")),
            beta = True if self.page_params.get_param("beta") else None
        )

        return url
Пример #7
0
    def get_next_question_test_url(self, total_questions):
        # We may choose to offer fewer questions if there aren't enough available
        more_questions = False

        if not context.c.session.get("history") or len(
                context.c.session.get("history")) == 0:
            # Starting a new test, record the start time in epoch seconds
            context.c.session.set("test_id", int(time.time() * 1000))

        next_question, more_questions = self.choose_next_question_test()

        q_number = self.get_q_number()
        if q_number >= total_questions or not more_questions:
            url_next = self.page.page_params.create_url(
                op=PageOperation.SUMMARY,
                language=PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                beta=True if self.page.page_params.get_param("beta") else None)
            url_skip = url_next
        else:
            url_next = self.page.page_params.create_url(
                op=PageOperation.TEST,
                language=PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                q_id=next_question["name"],
                q_num=str(q_number + 1),
                beta=True if self.page.page_params.get_param("beta") else None)
            url_skip = self.page.page_params.create_url(
                op=PageOperation.TEST,
                language=PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                q_id=next_question["name"],
                q_num=str(q_number + 1),
                skipped="true",
                beta=True if self.page.page_params.get_param("beta") else None)

        return url_next, url_skip
Пример #8
0
    def choose_next_question_browse(self, last_question_id=None):
        log_str = "Next question for browse in {}/{}/{}/{}/{}/{} - ".format(
            self.page.page_params.get_param("year"),
            self.page.page_params.get_param("theme"),
            self.page.page_params.get_param("subtheme"),
            self.page.page_params.get_param("topic"),
            context.c.session.get("period"),
            context.c.session.get("difficulty"))

        if not last_question_id:
            last_question_id = context.c.session.get("browse_last_q")

        subtheme, topic, period, difficulty = self._get_page_params()

        questions = list(
            self.page.repository.get_content_questions(
                PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                self.page.page_params.get_param("year"),
                self.page.page_params.get_param("theme"),
                subtheme=subtheme,
                topic=topic,
                period=period,
                difficulty=difficulty).values())

        questions.sort(key=lambda x: [
            x["rank_subtheme"], x["rank_topic"], x["period"], x["difficulty"]
        ])

        next_q = None
        prev_q = None

        if not last_question_id:
            next_q = questions[0]
            prev_q = None
        else:
            for idx, q in enumerate(questions):
                if last_question_id == q["name"].strip():
                    if idx + 1 < len(questions):
                        next_q = questions[idx + 1]
                    if idx - 1 >= 0:
                        prev_q = questions[idx - 1]
                    break

        log_str += "next_q: {}, prev_q: {}".format(next_q, prev_q)
        #print("\n\n\n", log_str, "\n\n\n")

        return prev_q, next_q
Пример #9
0
    def render_edit(page):

        page.template_params["template_name"] = Design_dev._add_language(
            page, "dev/edit.html.j2")

        Design_dev.render_menu(page)

        page.template_params["action"] = page.page_params.get_param("root")
        page.template_params["q_id"] = page.page_params.get_param("q_id")
        page.template_params["language"] = PageLanguage.toStr(
            page.page_params.get_param("language"))

        page.template_params["init_code"] = page.page_params.get_param(
            "init_code")
        page.template_params["iter_code"] = page.page_params.get_param(
            "iter_code")
        page.template_params["text"] = page.page_params.get_param("text")

        if page.question is not None:
            page.question.eval_with_exception(True)
Пример #10
0
    def login_anon(self) -> str:
        if not context.c.user:
            user_id = 'UNKNOWN'
            name = 'UNKNOWN'
            email = None
            user_language = "rs"

            logging.debug("Login anonymous user UNKNOWN")
            self.userdb.login_test(user_id, name, email, user_language)
        else:
            logging.info("login(): User already logged in")

        # url = self.page_params.get_param("root") + \
        #     "?op={}".format(PageOperation.toStr(PageOperation.CONFIRM_ANON))

        url = self.page_params.create_url( \
            op = PageOperation.CONFIRM_ANON,
            language = PageLanguage.toStr(self.page_params.get_param("language")),
            beta = True if self.page_params.get_param("beta") else None
        )

        return url
Пример #11
0
    def eval(self, page):

        # Parse text
        indices = [{"start": -1, "type": "text"}]
        cend = -1

        self.page.add_lines("\n\n<!-- QUESTIONS START -->\n\n")
        #self.page.add_lines("<div id='question' style='display:table; margin:0 auto;'>\n")
        self.page.add_lines(
            "<div id='question' style='display:inline-block; margin:0 auto; width: inherit'>\n"
        )

        self.page.add_lines(
            "<script>var test_id = {}; var test_order = {};</script>\n".format(
                self.test_id, self.test_order))

        btext = self.make_pretty(self.text)

        # Identify commands and strings
        while True:
            cstart = btext.find("@", cend + 1)
            if cstart == -1:
                indices.append({"start": len(btext), "type": "end"})
                break
            cend = btext.find("@", cstart + 1)
            if cend == -1:
                raise Exception(
                    "Code block started in text at position {} not finished".
                    format(cstart))
            indices.append({"start": cstart, "type": "code"})
            indices.append({"start": cend, "type": "text"})

        # Find repeates
        items = []
        strings = []
        start_index = None
        for ind in range(0, len(indices) - 1):
            if (indices[ind]["type"] == "code"):
                if (indices[ind + 1]["start"] - indices[ind]["start"] - 1 >
                        len("repeat()") and
                        btext[indices[ind]["start"] + 1:indices[ind]["start"] +
                              1 + len("repeat")] == "repeat" and
                        btext[indices[ind]["start"] + 1 + len("repeat")] == "("
                        and btext[indices[ind + 1]["start"] - 1] == ")"):
                    if not start_index is None:
                        raise Exception("Nested repeat in text: {}".format(
                            btext[indices[ind]["start"] +
                                  1:indices[ind]["start"] + 1 +
                                  len("repeat")]))
                    no_iter = int(
                        btext[indices[ind]["start"] + 1 +
                              len("repeat("):indices[ind + 1]["start"] - 1])
                    items.append({"type": "repeat", "no_iter": no_iter})
                    strings.append("")
                    start_index = ind

                elif (indices[ind + 1]["start"] - indices[ind]["start"] - 1
                      == len("/repeat") and
                      btext[indices[ind]["start"] + 1:indices[ind]["start"] +
                            1 + len("/repeat")] == "/repeat"):
                    if start_index is None:
                        raise Exception("Repeat ended without starting")
                    items.append({"type": "end", "start": start_index})
                    strings.append("")
                    start_index = None

                else:
                    items.append({
                        "type":
                        "code",
                        "string":
                        btext[indices[ind]["start"] + 1:indices[ind +
                                                                1]["start"]]
                    })
                    strings.append(btext[indices[ind]["start"] +
                                         1:indices[ind + 1]["start"]])
            elif (indices[ind]["type"] == "text"):
                items.append({
                    "type":
                    "text",
                    "string":
                    btext[indices[ind]["start"] + 1:indices[ind + 1]["start"]]
                })
                strings.append(btext[indices[ind]["start"] +
                                     1:indices[ind + 1]["start"]])

        # Eval code
        code = self.main_script_begin

        # Define Lua include function with proper paths
        # TBD TODO: This is still reading from a file. Rewrite to use repository

        # Special provisioning for Serbian cyrillic
        if self.language == PageLanguage.RS and self.cyrillic:
            lua_lang_t = PageLanguage.RSC.value
            code = code + """
            function require_if_exists(name)
                local f=io.open(name,"r")
                if f~=nil then io.close(f); dofile(name) end
            end
            function require_if_exists_t(name, name_t)
                local f_t=io.open(name_t,"r")
                if f_t~=nil then io.close(f_t); dofile(name_t) 
                else
                    local f=io.open(name,"r")
                    if f~=nil then io.close(f); dofile(name) end
                end
            end
            function include(name)
                local root_path = '""" + self.questions_root_path + """';
                local question_path = '""" + self.q_id + """';
                local language = '""" + PageLanguage.toStr(
                self.language) + """';
                local language_t = '""" + lua_lang_t + """';

                require_if_exists_t(root_path.."/"..question_path.."/"..name.."."..language..".lua", root_path.."/"..question_path.."/"..name.."."..language_t..".lua");
                require_if_exists_t(root_path.."/global/"..name.."."..language..".lua", root_path.."/global/"..name.."."..language_t..".lua");
                require_if_exists(root_path.."/global/"..name..".lua");
            end
            """
        else:
            code = code + """
            function require_if_exists(name)
                local f=io.open(name,"r")
                if f~=nil then io.close(f); dofile(name) end
            end
            function include(name)
                local root_path = '""" + self.questions_root_path + """';
                local question_path = '""" + self.q_id + """';
                local language = '""" + PageLanguage.toStr(
                self.language) + """';

                require_if_exists(root_path.."/"..question_path.."/"..name.."."..language..".lua");
                require_if_exists(root_path.."/global/"..name.."."..language..".lua");
                require_if_exists(root_path.."/global/"..name..".lua");
            end
            """

        # It seems that Lupa doesn't know about integer type that was new in Lua 5.3
        # Everything Lupa returns is treated as a float, causing bad printout format
        # We use these Lua wrapper functions to convert to int within Lua
        # Note that this is a dangerous trick as search and replace calls!
        code = code + """
            function sh_random(m, n)
              rnd = lib.math.random
              r = rnd(m,n)
              if m~=nil or n~=nil then
                return math.tointeger(r)
              end
              return r
            end

            function sh_round(n)
              return math.tointeger(lib.math._round(n))
            end
        """

        code = code + self.init_code + "\n"

        ind = 0
        start_repeat = None
        no_iter = None
        loop = 1
        while ind < len(items):
            item = items[ind]
            if item["type"] == "text":
                code = code + "page.add_lines(strings[{}])\n".format(ind)
            elif item["type"] == "code":
                # Look for include() directives
                if (len(strings[ind]) > len("include()")
                        and strings[ind][0:len("include(")] == "include("
                        and strings[ind][len(strings[ind]) - 1] == ")"):
                    inc_file = strings[ind][len("include("):len(strings[ind]) -
                                            1]

                    q = self.repository.get_question(self.q_id)
                    inc_name = inc_file + "." + PageLanguage.toStr(
                        self.language) + ".lua"
                    include_code = ""
                    if q is not None and inc_name in q.keys():
                        include_code = q[inc_name]
                    else:
                        g = self.repository.get_globals()
                        if g is not None and inc_name in g.keys():
                            include_code = g[inc_name]

                    code = code + include_code

                # Ignore alignment tags
                elif (strings[ind] != "left" and strings[ind] != "right" and strings[ind] != "center" and \
                    strings[ind] != "H1" and strings[ind] != "H2" and strings[ind] != "H3" and \
                    strings[ind] != "/H1" and strings[ind] != "/H2" and strings[ind] != "/H3"):
                    code = code + "output = {}\n".format(strings[ind])
                    code = code + "if (output ~= nil) then page.add_lines(output) end\n"
            elif item["type"] == "repeat":
                no_iter = item["no_iter"]
                start_repeat = ind
                loop = 1
                code = code + "ITEM = {}\n".format(loop)
                code = code + self.iter_code + "\n"

            elif item["type"] == "end":
                loop = loop + 1
                if loop == no_iter + 1:
                    loop = 1
                    start_repeat = None
                else:
                    code = code + "ITEM = {}\n".format(loop)
                    code = code + self.iter_code + "\n"
                    ind = start_repeat
            ind = ind + 1

        code = code + self.main_script_end

        code = code.replace("\\", "\\\\")

        # Replace math.random with lib.math.random so we can log all random values
        code = code.replace("math.random(", "sh_random(")
        # Replace round with a local wrapper to force it to become int (Lupa doesn't know about int types)
        code = code.replace("lib.math.round(", "sh_round(")

        # DEBUG
        if False:
            logging.debug("\n\n********************\nSTRINGS: \n")
            for i in range(0, len(strings)):
                logging.debug("string[{}]: {}".format(i, strings[i]))

            logging.debug("\n\n********************\nCODE: {}".format(code))

        lua_fun = self.lua.eval(code)
        lua_fun(self.page, self.lib, strings)

        if self.lib is not None:
            self.lib.add_check_button_code()
            self.lib.add_clear_button_code()
            self.lib.add_solution_button_code()
            self.lib.add_error_report_button_code()

        self.page.add_lines("</div>\n")
        self.page.add_lines("\n\n<!-- QUESTIONS END -->\n\n")
Пример #12
0
    def register(self, args):

        # TBD: we record UNKNOWN for testing only.
        # In deployment we should ignore registering requests from UNKNOWN
        # (and not even send them from the page)
        try:
            user_id = context.c.user.user_id if context.c.user else "UNKNOWN"
        except:
            user_id = "UNKNOWN"
            pass


        if args["response_type"] == ResponseOperation.toStr(ResponseOperation.SUBMIT) or \
           args["response_type"] == ResponseOperation.toStr(ResponseOperation.SKIP):

            # Record answer to the database

            correct = 0
            incorrect = 0
            questions = ""

            if "q_id" in args.keys() and "now" in args.keys():
                if "l_id" not in args.keys(
                ) or not args["l_id"] or args["l_id"] is None:
                    l_id = ""
                else:
                    l_id = args["l_id"]

                if "language" not in args.keys(
                ) or not args["language"] or args["language"] is None:
                    language = ""
                else:
                    language = args["language"]

                # for key, v in args.items():
                #     value = v
                #     if key[0:5] == "q_res":
                #         questions = questions + key + "=" + value + ","
                #         if value == "true":
                #             correct = correct + 1
                #         else:
                #             incorrect = incorrect + 1

                questions = ""
                if 'detailed' in args.keys():
                    for k, v in args['detailed'].items():
                        if v == "true":
                            correct = correct + 1
                        else:
                            incorrect = incorrect + 1
                    questions = str(args['detailed'])

                values = ""
                if 'values' in args.keys():
                    values = str(args['values'])

                shown_solution = False
                if "shown_solutions" in args.keys() and type(
                        args["shown_solutions"]) == bool:
                    shown_solution = args["shown_solutions"]

                hist = context.c.session.get("history")
                if (len(hist) > 0 and
                    (hist[-1]["correct"] == 0
                     or correct > hist[-1]["correct"])) and not shown_solution:
                    hist[-1]["correct"] = correct
                    hist[-1]["incorrect"] = incorrect
                    context.c.session.set("history", hist)

                # We register temporary stats for anonymous users that are stored with the cookie
                if (user_id == "UNKNOWN" or user_id == "local:UNKNOWN") and \
                    context.c.session.get("last_q_year") and context.c.session.get("last_q_theme") and \
                    context.c.session.get("last_q_subtheme") and context.c.session.get("difficulty"):

                    year = context.c.session.get("last_q_year")
                    theme = context.c.session.get("last_q_theme")
                    subtheme = context.c.session.get("last_q_subtheme")
                    difficulty = context.c.session.get("difficulty")

                    anon_stats = context.c.session.get("anon_stats")
                    if not anon_stats:
                        anon_stats = {}
                        context.c.session.set("anon_stats", anon_stats)

                    add_anon_stats(self, anon_stats, args["q_id"], \
                            PageLanguage.fromStr(language), \
                            year, theme, subtheme, difficulty, correct, incorrect)

                response = {
                    "user_id":
                    user_id,
                    "question_id":
                    args["q_id"],
                    "list_id":
                    l_id,
                    "year":
                    context.c.session.get("last_q_year")
                    if context.c.session.get("last_q_year") else "",
                    "theme":
                    context.c.session.get("last_q_theme")
                    if context.c.session.get("last_q_theme") else "",
                    "subtheme":
                    context.c.session.get("last_q_subtheme")
                    if context.c.session.get("last_q_subtheme") else "",
                    "topic":
                    context.c.session.get("last_q_topic")
                    if context.c.session.get("last_q_topic") else "",
                    "period":
                    context.c.session.get("period")
                    if context.c.session.get("period") else "",
                    "difficulty":
                    context.c.session.get("difficulty")
                    if context.c.session.get("difficulty") else "",
                    "language":
                    language,
                    "test_id":
                    args["test_id"],
                    "test_order":
                    args["test_order"],
                    "response_type":
                    args["response_type"],
                    "attempt":
                    args["attempt"],
                    "shown_solutions":
                    args["shown_solutions"],
                    "time":
                    args["start"],
                    "duration":
                    int(args["now"]) - int(args["start"]),
                    "correct":
                    correct,
                    "incorrect":
                    incorrect,
                    "questions":
                    questions,
                    "values":
                    values
                }

                # logging.debug("Register results: user_id={}, q_id={}, l_id={}, lang={}, response_type={}, " +
                #             "attempt={}, start={}, duration={}, correct={}, incorrect={}, questions=\"{}\"".format(
                #             str(user_id), str(args["q_id"]), str(l_id),
                #             str(language), str(args["response_type"]), str(args["attempt"]),
                #             str(args["start"]), str(int(args["now"]) - int(args["start"])),
                #             str(correct), str(incorrect), str(questions)))

                try:
                    self.app_data.storage.record_response(response)
                except Exception as err:
                    logging.error(
                        "Error submitting record response: {}\n{}".format(
                            err, helpers.get_stack_trace()))

                # Also register responses to LogAnalytics for better visibility

                log_json = {
                    "user":
                    user_id,
                    "q_id":
                    args["q_id"],
                    "l_id":
                    l_id,
                    "year":
                    context.c.session.get("last_q_year")
                    if context.c.session.get("last_q_year") else "",
                    "theme":
                    context.c.session.get("last_q_theme")
                    if context.c.session.get("last_q_theme") else "",
                    "subtheme":
                    context.c.session.get("last_q_subtheme")
                    if context.c.session.get("last_q_subtheme") else "",
                    "topic":
                    context.c.session.get("last_q_topic")
                    if context.c.session.get("last_q_topic") else "",
                    "period":
                    context.c.session.get("period")
                    if context.c.session.get("period") else "",
                    "difficulty":
                    context.c.session.get("difficulty")
                    if context.c.session.get("difficulty") else "",
                    "language":
                    language,
                    "response_type":
                    args["response_type"],
                    "attempt":
                    args["attempt"],
                    "shown_solutions":
                    args["shown_solutions"],
                    "time":
                    args["start"],
                    "duration":
                    int(args["now"]) - int(args["start"]),
                    "correct":
                    correct,
                    "incorrect":
                    incorrect
                }

                self.app_data.log_json("Register", log_json)

            else:
                logging.error(
                    "Register operation with incomplete parameters: {}\n{}".
                    format(args, helpers.get_stack_trace()))

        else:
            # This is often hit by crawlers, so ignore
            logging.debug("Unknown register operation: {}".format(
                args["response_type"]))

        return "ABC"
Пример #13
0
    def render_feedback(page):

        language = page.page_params.get_param("language")

        page.template_params["template_name"] = Design_dev._add_language(
            page, "dev/feedback.html.j2")

        Design_dev.render_menu(page)

        storage = Storage_az_table()

        no_days = int(page.page_params.get_param("interval"))
        from_date = datetime.today() - timedelta(no_days)
        feedbacks = storage.get_all_user_feedback(from_date)

        feedbacks.sort(key=lambda i: i["Timestamp"], reverse=True)

        page.template_params["attributes"] = {}
        page.template_params["questions"] = []

        for f in feedbacks:
            #print(f["question_id"], f["type"], f["Timestamp"], f["language"], f["comment"], f["random_vals"])

            q_id = f["question_id"]
            q = {}
            q["q_id"] = q_id
            q["attributes"] = {}

            q["attributes"]["Type"] = f["type"]
            q["attributes"]["Time"] = str(f["Timestamp"])
            q["attributes"]["Lang"] = f["language"]
            q["attributes"]["User"] = f["user_id"]
            q["attributes"]["Comment"] = f["comment"]

            # This one-liner doesn't preserve value ordering in python 3.6
            # rand_vals = list(json.loads(f["random_vals"].replace("'", "\"")).values())
            json_vals = json.loads(f["random_vals"].replace("'", "\""))
            sorted_json_vals = {}
            for k, v in json_vals.items():
                if "rnd_arr_" in k:
                    num_k = k[8:]
                else:
                    num_k = k[4:]
                sorted_json_vals[int(num_k)] = v
            rand_vals = []
            for k, v in sorted(sorted_json_vals.items()):
                rand_vals.append(v)

            q["link"] = page.page_params.create_url_edit( \
                                    op = PageOperation.VIEW, \
                                    language = PageLanguage.toStr(language),
                                    q_id = q_id)

            # Generate question and paste it into the list
            page.page_params.set_param("q_id", q_id)
            gq = question.Question(page,
                                   language=language,
                                   rand_vals=rand_vals)
            gq.set_from_file_with_exception()

            try:
                gq.eval_with_exception()
            except:
                page.add_lines("Problem with the question!\n")
                logging.error(
                    "\n\nERROR: problem with question {}!\n\n".format(q_id))
                pass

            q["lib_id"] = gq.lib.lib_id

            q["text"] = ""
            for l in page.script_lines:
                q["text"] = q["text"] + l + "\n"
            for l in page.lines:
                q["text"] = q["text"] + str(l)

            previous_params = page.template_params
            page.clear()
            page.template_params = previous_params
            page.template_params["questions"].append(q)
Пример #14
0
 def get_default_list(self):
     return self.get_all_lists(
         PageLanguage.toStr(self.page_params.get_param("language")))[0]
Пример #15
0
    def main(self, req, headers, timers, args):
        logging.debug("\n\nMAIN ARGS: {}\n\n".format(args))

        if headers is None or req is None:
            # Cherrypy - ignore cookies

            # Special ops to register a user reported error
            # DEBUG: This is only for testing and may not implement the full feedback functionality
            if "op" in args.keys() and args["op"] == PageOperation.toStr(
                    PageOperation.FEEDBACK):
                return self.feedback(args)

            self.page_params.parse(args, legacy=True)
            return Design.main(self)

        # No caching
        headers.set_no_store()

        if args["root"] == "edit":
            # Old style EDIT page with parameter passing in GET URL

            # DEBUG: these two special ops are for testing and are not fully functional in edit mode
            # Special ops to register results
            if "op" in args.keys() and args["op"] == PageOperation.toStr(
                    PageOperation.REGISTER):
                return self.register(args)

            # Special ops to register a user reported error
            elif "op" in args.keys() and args["op"] == PageOperation.toStr(
                    PageOperation.FEEDBACK):
                return self.feedback(args)

            self.page_params.parse_edit(in_args=args)
            # self.page_params.print_params()
            return Design.main(self)

        with context.new_context(req, headers):
            context.c.timers = timers

            with self.sessiondb.init_session(req, headers) as session:
                context.c.session = session
                context.c.user = self.userdb.get_user(session.user_id())

                # Debug
                if False:
                    session.print()

                # Special ops to register results
                if "op" in args.keys() and args["op"] == PageOperation.toStr(
                        PageOperation.REGISTER):
                    return self.register(args)

                # Special ops to register a user reported error
                elif "op" in args.keys() and args["op"] == PageOperation.toStr(
                        PageOperation.FEEDBACK):
                    return self.feedback(args)

                else:
                    self.page_params.set_url(req.get_url())

                    # DEBUG (log.debug level required for the below to work)
                    # print("\n\nPRE PARSING:\n")
                    # #print("\n\nARGS: \n{}\n".format(json.dumps(args, indent=2)))
                    # print("\n\nARGS: \n{}\n".format(args))
                    # session.print()

                    # # Parameters stored in a session,
                    # # only updates passed in URL
                    self.page_params.parse(in_args=args, session=session)

                    if self.page_params.get_param("language"):
                        #print("\n\n**** DIRECT: ", self.page_params.get_param("language"))
                        self.userdb.update_selected_language(
                            self.page_params.get_param("language").value)
                    elif context.c.user and context.c.user.selected_language:
                        self.page_params.set_param(
                            "language",
                            PageLanguage.fromStr(
                                context.c.user.selected_language))
                        #print("\n\n**** FROM DB: ", self.page_params.get_param("language"))
                    else:
                        self.page_params.set_param(
                            "language",
                            PageLanguage.get_default(req.get_preferred_lang()))
                        #print("\n\n**** DEFAULT: ", self.page_params.get_param("language"))

                    # DEBUG (log.debug level required for the below to work)
                    # print("\n\nPOST PARSING:\n")
                    # self.page_params.print_params()
                    # session.print()

                    logging.debug("=== New /main request, op = {}".format(
                        self.page_params.get_param('op')))
                    if False:
                        self.page_params.print_params()
                        logging.info(
                            "\n\n === New request: op={} - "
                            "q_id={}, l_id={}, language={}, "
                            "init_code={}, iter_code={}, text={}.\n\n".format(
                                PageOperation.toStr(
                                    self.page_params.get_param("op")),
                                self.page_params.get_param("q_id"),
                                self.page_params.get_param("l_id"),
                                PageLanguage.toStr(
                                    self.page_params.get_param("language")),
                                self.page_params.get_param("init_code"),
                                self.page_params.get_param("iter_code"),
                                self.page_params.get_param("text"),
                            ))

                    log_json = {"url": req.get_url()}

                    if context.c.user and context.c.user.user_id:
                        log_json["user"] = context.c.user.user_id

                    if self.page_params.get_param("op"):
                        log_json["op"] = PageOperation.toStr(
                            self.page_params.get_param("op"))

                    if self.page_params.get_param("q_id"):
                        log_json["q_id"] = self.page_params.get_param("q_id")

                    if self.page_params.get_param("l_id"):
                        log_json["l_id"] = self.page_params.get_param("l_id")

                    if self.page_params.get_param("language"):
                        log_json["language"] = PageLanguage.toStr(
                            self.page_params.get_param("language"))
                    if self.page_params.get_param("year"):
                        log_json["year"] = self.page_params.get_param("year")
                    if self.page_params.get_param("theme"):
                        log_json["theme"] = self.page_params.get_param("theme")
                    if self.page_params.get_param("subtheme"):
                        log_json["subtheme"] = self.page_params.get_param(
                            "subtheme")
                    if self.page_params.get_param("topic"):
                        log_json["topic"] = self.page_params.get_param("topic")
                    if context.c.session.get("period"):
                        log_json["period"] = context.c.session.get("period")
                    if context.c.session.get("difficulty"):
                        log_json["difficulty"] = context.c.session.get(
                            "difficulty")
                    if self.page_params.get_param("skipped"):
                        log_json["skipped"] = self.page_params.get_param(
                            "skipped")

                    # HTTP header
                    log_json["accepted_lang"] = req.get_header(
                        'Accept-Language')
                    log_json["preferred_lang"] = req.get_preferred_lang()
                    log_json["remote_addr"] = req.get_header('Remote-Addr')
                    log_json["user_agent"] = req.get_header('User-Agent')

                    self.app_data.log_json("Access", log_json)

                    with context.c.timers.new_section("design.main"):
                        return Design.main(self)
Пример #16
0
 def get_default_question(self):
     return self.get_all_questions(
         PageLanguage.toStr(self.page_params.get_param("language")))[0]
Пример #17
0
    def render_menu(page):

        page.template_params["menu"] = {}

        ### Questions/lists
        # Edit or view question
        if page.page_params.get_param(
                "op") == PageOperation.EDIT or page.page_params.get_param(
                    "op") == PageOperation.VIEW or page.page_params.get_param(
                        "op") == PageOperation.GENERATE:
            if page.page_params.get_param("op") == PageOperation.GENERATE:
                page_name = PageOperation.toStr(PageOperation.EDIT)
            else:
                page_name = PageOperation.toStr(
                    page.page_params.get_param("op"))

            page.template_params["menu"][
                "current_choice"] = page.page_params.get_param("q_id")
            page.template_params["menu"]["choices"] = page.get_all_questions(
                PageLanguage.toStr(page.page_params.get_param("language")))
            page.template_params["menu"]["choice_action"] = page.page_params.create_url_edit( \
                                    op = encap_str(page_name), \
                                    q_id = "this.value", \
                                    language = "sel_lang.value", \
                                    js = True)

        # View list
        elif page.page_params.get_param(
                "op") == PageOperation.LIST or page.page_params.get_param(
                    "op") == PageOperation.TEST:
            page.template_params["menu"][
                "current_choice"] = page.page_params.get_param("l_id")
            page.template_params["menu"]["choices"] = page.get_all_lists()
            page.template_params["menu"]["choice_action"] = page.page_params.create_url_edit(\
                                    l_id = "this.value", \
                                    language = "sel_lang.value", \
                                    js = True)

        # View feedbacks
        elif page.page_params.get_param("op") == PageOperation.VIEW_FEEDBACK:
            page.template_params["menu"]["current_choice"] = "7"
            page.template_params["menu"]["choices"] = ["7", "14", "30"]
            page.template_params["menu"]["choice_action"] = page.page_params.create_url_edit(\
                                    interval = "this.value", \
                                    language = "sel_lang.value", \
                                    js = True)

        ### Languages
        page.template_params["menu"]["languages"] = page.get_language_list()
        page.template_params["menu"]["current_language"] = PageLanguage.toStr(
            page.page_params.get_param("language"))
        if page.page_params.get_param(
                "op") == PageOperation.EDIT or page.page_params.get_param(
                    "op") == PageOperation.VIEW:
            page.template_params["menu"]["language_action"] = page.page_params.create_url_edit( \
                                                        q_id = "choice_id.value", \
                                                        language = "this.value", \
                                                        js = True)
        # View list
        elif page.page_params.get_param(
                "op") == PageOperation.LIST or page.page_params.get_param(
                    "op") == PageOperation.TEST:
            page.template_params["menu"]["language_action"] = page.page_params.create_url_edit( \
                                                        l_id = "choice_id.value", \
                                                        language = "this.value", \
                                                        js = True)
        # Generate?
        else:
            page.template_params["menu"]["language_action"] = page.page_params.create_url_edit( \
                                                        q_id = "choice_id.value", \
                                                        language = "this.value", \
                                                        js = True)

        ### Operations
        options = [
            PageOperation.toStr(PageOperation.EDIT),
            PageOperation.toStr(PageOperation.VIEW),
            PageOperation.toStr(PageOperation.LIST),
            PageOperation.toStr(PageOperation.VIEW_FEEDBACK),
            PageOperation.toStr(PageOperation.STATS)
        ]
        page.template_params["menu"]["operations"] = options
        page.template_params["menu"][
            "current_operation"] = PageOperation.toStr(
                page.page_params.get_param("op"))
        page.template_params["menu"]["operation_action"] = page.page_params.create_url_edit( \
                                                            op = "sel_op.value", \
                                                            js = True)
Пример #18
0
    def choose_next_question_test(self):
        log_str = "Next question for test in {}/{}/{}/{}/{}/{} - ".format(
            self.page.page_params.get_param("year"),
            self.page.page_params.get_param("theme"),
            self.page.page_params.get_param("subtheme"),
            self.page.page_params.get_param("topic"),
            context.c.session.get("period"),
            context.c.session.get("difficulty"))

        # Total number of unique questions (including previously asked ones)
        remaining_question = 0

        potential_questions = {"all": [], "topics": {}, "difficulty": {}}
        potential_questions_w_repeat = []

        past_questions = {}

        last_question = None
        if context.c.session.get("history"):
            for hist in context.c.session.get("history"):
                last_question = hist["q_id"]
                if not hist["q_id"] in past_questions.keys():
                    past_questions[hist["q_id"]] = {
                        "number": 1,
                        "correct": 1 if hist["incorrect"] == 0 else 0,
                        "skipped": ("skipped" in hist.keys()
                                    and hist["skipped"])
                    }
                else:
                    past_questions[hist["q_id"]]["number"] = past_questions[
                        hist["q_id"]]["number"] + 1
                    if hist["incorrect"] == 0:
                        past_questions[
                            hist["q_id"]]["correct"] = past_questions[
                                hist["q_id"]]["correct"] + 1
                    if "skipped" in hist.keys() and hist["skipped"]:
                        past_questions[hist["q_id"]]["skipped"] = True

        prev_question = None

        # Find the list of all question in the subtopic (potential_questions_w_repeat),
        # and also those among them that haven't been already asked in this session (potential_questions)

        subtheme, topic, period, difficulty = self._get_page_params()

        for _, next_q in self.page.repository.get_content_questions(
                PageLanguage.toStr(
                    self.page.page_params.get_param("language")),
                self.page.page_params.get_param("year"),
                self.page.page_params.get_param("theme"),
                subtheme=subtheme,
                topic=topic,
                period=period,
                difficulty=difficulty).items():

            add_in_random = True
            diff = 0

            if not next_q["name"] in past_questions.keys():
                potential_questions["all"].append(next_q)
                topic = self._make_topic(next_q)
                if topic not in potential_questions["topics"].keys():
                    potential_questions["topics"][topic] = {}
                if next_q["difficulty"] not in potential_questions["topics"][
                        topic].keys():
                    potential_questions["topics"][topic][
                        next_q["difficulty"]] = []
                potential_questions["topics"][topic][
                    next_q["difficulty"]].append(next_q)
                if next_q["difficulty"] not in potential_questions[
                        "difficulty"].keys():
                    potential_questions["difficulty"][
                        next_q["difficulty"]] = []
                potential_questions["difficulty"][next_q["difficulty"]].append(
                    next_q)
                if next_q["random"] >= 10 or remaining_question >= 100:
                    diff = 100
                    remaining_question = 100
                else:
                    diff = next_q["random"] if next_q["random"] > 0 else 1
                    remaining_question = remaining_question + diff

            else:
                if next_q["name"] == last_question:
                    prev_question = next_q

                ask_again = not past_questions[next_q["name"]]["skipped"]
                ask_again = ask_again and not (\
                    (past_questions[next_q["name"]]["correct"] >= 1 and next_q["random"] < 5) or \
                    (past_questions[next_q["name"]]["correct"] >= 2 and next_q["random"] >= 5 and next_q["random"] < 10) or \
                    (past_questions[next_q["name"]]["correct"] >= 3 and next_q["random"] >= 10) \
                )
                ask_again = ask_again and not \
                    (next_q["random"] < 10 and next_q["random"] <= past_questions[next_q["name"]]["number"])

                if not ask_again:
                    add_in_random = False
                else:
                    if next_q["random"] >= 10 or remaining_question >= 100:
                        diff = 100
                        remaining_question = 100
                    else:
                        diff = next_q["random"] - past_questions[next_q["name"]]["number"] \
                            if next_q["random"] - past_questions[next_q["name"]]["number"] >= 0 else 0
                        remaining_question = remaining_question + diff

            #print("Q: {} ({}) - {} {}".format(next_q["name"], add_in_random, diff, remaining_question))

            if add_in_random:
                potential_questions_w_repeat.append(next_q)

        # print("remaining_question={}\npotential_questions={}\npotential_questions_w_repeat={}".format(
        #     remaining_question, json.dumps(potential_questions, indent=2), json.dumps(potential_questions_w_repeat, indent=2)
        #     ))

        # if not potential_questions_w_repeat:
        #     total = len(all_potential_questions_w_repeat)
        #     index = random.randrange(total)
        #     potential_questions_w_repeat.append(all_potential_questions_w_repeat[index])

        next_question = {
            "name": "",
            "subtheme": "",
            "topic": "",
            "period": "",
            "difficulty": "",
            "random": False
        }

        # Do we insiste on a specific topic in a subtheme or we can
        is_topic_specified = not self.page.page_params.get_param("subtheme") == '*' and \
                             not self.page.page_params.get_param("topic") == '*'

        if prev_question or is_topic_specified:
            if prev_question:
                topic = self._make_topic(prev_question)
            else:
                topic = self.page.page_params.get_param("subtheme") + "|" + \
                    self.page.page_params.get_param("topic")

            if topic in potential_questions["topics"].keys():
                # There are more potential questions in the same topic that have not been asked before, choose one
                candidates = []

                if prev_question:
                    candidate_difficulty = prev_question["difficulty"]
                elif context.c.session.get("difficulty") == "*":
                    candidate_difficulty = "1"
                else:
                    candidate_difficulty = context.c.session.get("difficulty")

                log_str = log_str + "found topic {} ".format(topic)
                if candidate_difficulty in potential_questions["topics"][
                        topic].keys():
                    # There are more questions in the same topic with the same difficulty, choose one
                    candidates = potential_questions["topics"][topic][
                        candidate_difficulty]
                    log_str = log_str + "difficulty {} ".format(
                        candidate_difficulty)
                elif str(int(candidate_difficulty) +
                         1) in potential_questions["topics"][topic].keys():
                    # There are more questions in the same topic with the next difficulty, choose one
                    candidates = potential_questions["topics"][topic][str(
                        int(candidate_difficulty) + 1)]
                    log_str = log_str + "difficulty {} ".format(
                        str(int(candidate_difficulty) + 1))
                elif str(int(candidate_difficulty) +
                         2) in potential_questions["topics"][topic].keys():
                    candidates = potential_questions["topics"][topic][str(
                        int(candidate_difficulty) + 2)]
                    log_str = log_str + "difficulty {} ".format(
                        str(int(candidate_difficulty) + 2))
                else:
                    log_str = log_str + "no difficulty found (!) - "

                if candidates:
                    total = len(candidates)
                    index = random.randrange(total)
                    next_question = candidates[index]
                    log_str = log_str + "selected new question: {}".format(
                        next_question["name"])

        if not next_question["name"]:

            # A suitable question from the same topic not found, find an easy one from a new topic
            # (if new topic allowed, otherwise potential_questions will be empty)
            candidates = []
            if "1" in potential_questions["difficulty"].keys():
                # There are more questions in the same topic with the same difficulty, choose one
                candidates = potential_questions["difficulty"]["1"]
                log_str = log_str + "new topic, difficulty: 1 - "
            elif "2" in potential_questions["difficulty"].keys():
                # There are more questions in the same topic with the next difficulty, choose one
                candidates = potential_questions["difficulty"]["2"]
                log_str = log_str + "new topic, difficulty: 2 - "
            elif "3" in potential_questions["difficulty"].keys():
                candidates = potential_questions["difficulty"]["3"]
                log_str = log_str + "new topic, difficulty: 3 - "
            else:
                log_str = log_str + "no new topics - "

            if candidates:
                total = len(candidates)
                index = random.randrange(total)
                next_question = candidates[index]
                log_str = log_str + "selected: {}- {}".format(
                    self._make_topic(next_question), next_question["name"])

        if not next_question["name"] and potential_questions_w_repeat:
            # Otherwise give randomly any previously asked randomizable question
            total = len(potential_questions_w_repeat)
            index = random.randrange(total)
            next_question = potential_questions_w_repeat[index]
            log_str = log_str + "no new topics - selected previous q: {}".format(
                next_question["name"])
        elif not next_question["name"]:
            log_str = log_str + "no new topics - no question selected!"

        logging.info("\n\n ************ " + log_str + "\n\n")

        # logging.info("\n\nNEXT Q: {}\n\n {}\n\n {}\n\n {}\n\n".format(
        #      potential_questions_w_repeat, potential_questions, next_question, remaining_question))

        # Serve at most remaining_question
        #remaining_question = (remaining_question - 1) if remaining_question > 0 else remaining_question
        logging.info("Remaining questions: {}".format(remaining_question))

        if remaining_question == 0:
            more_questions = False
        else:
            more_questions = True

        return next_question, more_questions
Пример #19
0
    def __init__(self,
                 page,
                 q_id=None,
                 language=None,
                 test_id=None,
                 test_order=None,
                 init_code=None,
                 iter_code=None,
                 text=None,
                 rand_vals=None):

        self.lua = LuaRuntime(unpack_returned_tuples=True)
        self.page = page
        self.repository = page.repository
        self.rel_path = page.app_data.rel_path

        # If we have more questions on the same page make sure all use pseudo-random thus unique IDs
        self.q_unique_id = str(int(random.random() * 1000000000))

        if q_id:
            self.q_id = q_id
        else:
            self.q_id = page.page_params.get_param("q_id")
        self.page.add_script_lines(
            "<script> global_q_id = \"{}\";</script>".format(self.q_id))

        if language:
            self.language = language
        else:
            self.language = page.page_params.get_param("language")

        # Special provisioing for Serbian cyrillic
        if self.language == PageLanguage.RSC:
            self.language = PageLanguage.RS
            self.cyrillic = True

        self.page.add_script_lines(
            "<script> global_language = \"{}\";</script>".format(
                PageLanguage.toStr(self.language)))

        # Parameters useful for error reporting
        if self.page.page_params.get_param("l_id"):
            self.page.add_script_lines(
                "<script> global_l_id = \"{}\";</script>".format(
                    self.page.page_params.get_param("l_id")))
        if self.page.page_params.get_param("root"):
            self.page.add_script_lines(
                "<script> global_root = \"{}\";</script>".format(
                    self.page.page_params.get_param("root")))

        self.test_id = test_id if test_id else 0
        self.test_order = test_order if test_order else 0

        if not init_code is None:
            self.init_code = init_code
        else:
            self.init_code = page.page_params.get_param("init_code")

        if not iter_code is None:
            self.iter_code = iter_code
        else:
            self.iter_code = page.page_params.get_param("iter_code")

        if not text is None:
            self.text = text
        else:
            self.text = page.page_params.get_param("text")

        self.lib = Library(self, rand_vals=rand_vals)
        logging.debug("Rendering question %s, language=%s",
                      self.question_url(), PageLanguage.toStr(self.language))
        self.questions_root_path = self.rel_path + "/" + self.questions_rel_path
Пример #20
0
    def render_list(page):

        language = page.page_params.get_param("language")
        qlist = page.repository.get_list(page.page_params.get_param("l_id"))

        page.template_params["template_name"] = Design_dev._add_language(
            page, "dev/list.html.j2")

        Design_dev.render_menu(page)

        if "name" in qlist.keys():
            page.template_params["name"] = qlist["name"]
        else:
            page.template_params["name"] = "UNKNOWN"

        page.template_params["attributes"] = {}
        for key, value in qlist.items():
            if key != "name" and key != "questions":
                page.template_params["attributes"][key] = value

        page.template_params["questions"] = []
        page.template_params["summary"] = {}

        for i in qlist["questions"]:

            if "subtheme" in i.keys():
                if isinstance(i["subtheme"], list):
                    asubtheme = i["subtheme"]
                else:
                    asubtheme = [i["subtheme"]]
            else:
                asubtheme = ["UNKNOWN"]

            for subtheme in asubtheme:
                topic = i["topic"] if "topic" in i.keys() else "UNKNOWN"
                difficulty = i["difficulty"] if "difficulty" in i.keys(
                ) else "UNKNOWN"
                period = i["period"] if "period" in i.keys() else "UNKNOWN"

                if subtheme not in page.template_params["summary"].keys():
                    page.template_params["summary"][subtheme] = {}
                if topic not in page.template_params["summary"][subtheme].keys(
                ):
                    page.template_params["summary"][subtheme][topic] = {
                        "difficulty": {},
                        "period": {}
                    }
                if difficulty not in page.template_params["summary"][subtheme][
                        topic]["difficulty"].keys():
                    page.template_params["summary"][subtheme][topic][
                        "difficulty"][difficulty] = 0
                if period not in page.template_params["summary"][subtheme][
                        topic]["period"].keys():
                    page.template_params["summary"][subtheme][topic]["period"][
                        period] = 0

                page.template_params["summary"][subtheme][topic]["difficulty"][difficulty] = \
                    page.template_params["summary"][subtheme][topic]["difficulty"][difficulty] + 1
                page.template_params["summary"][subtheme][topic]["period"][period] = \
                    page.template_params["summary"][subtheme][topic]["period"][period] + 1

            q_id = i["name"]
            q = {}
            q["q_id"] = q_id
            q["attributes"] = {}
            for key, value in i.items():
                if key != "name":
                    q["attributes"][key] = [value]
            q["link"] = page.page_params.create_url_edit( \
                                    op = PageOperation.VIEW, \
                                    language = PageLanguage.toStr(language),
                                    q_id = q_id)

            # Generate question and paste it into the list
            page.page_params.set_param("q_id", q_id)
            gq = question.Question(page, language=language)
            gq.set_from_file_with_exception()
            try:
                gq.eval_with_exception()
            except:
                page.add_lines("Problem with the question!\n")
                logging.error(
                    "\n\nERROR: problem with question {}!\n\n".format(q_id))
                pass

            q["lib_id"] = gq.lib.lib_id

            q["text"] = ""
            for l in page.script_lines:
                q["text"] = q["text"] + l + "\n"
            for l in page.lines:
                q["text"] = q["text"] + str(l)

            previous_params = page.template_params
            page.clear()
            page.template_params = previous_params
            page.template_params["questions"].append(q)