示例#1
0
 def participate_in_hippos(self):
     # Multiple conversions test
     return ab_test("hippos",
                     conversion_name=["hippos_binary",
                                      "hippos_counting"],
                     conversion_type=[ConversionTypes.Binary,
                                      ConversionTypes.Counting])
示例#2
0
    def get_alternative_for_user(user_data, current_user=False):
        """ Returns the experiment alternative for the specified user, or
        the current logged in user. If the user is the logged in user, will
        opt in for an experiment, as well. Will not affect experiments if
        not the current user.
        
        """
        
        # We're interested in analyzing the effects of different struggling
        # models on users. A more accurate model would imply that the user
        # can get help earlier on. This varies drastically for those with
        # and without coaches, so it is useful to separate the population out.
        if user_data.coaches:
            exp_name = 'Struggling model (w/coach)'
        else:
            exp_name = 'Struggling model (no coach)'

        # If it's not the current user, then it must be an admin or coach
        # viewing a dashboard. Don't affect the actual experiment as only the
        # actions of the user affect her participation in the experiment.
        if current_user:
            return ab_test(exp_name,
                       	   StrugglingExperiment._ab_test_alternatives,
                       	   StrugglingExperiment._conversion_names,
                           StrugglingExperiment._conversion_types)

        return find_alternative_for_user(exp_name, user_data)
示例#3
0
    def participate_in_doppleganger_on_new_instance(self):
        """Simulate participating in a new experiment on a "new" instance.
        
        This test works by loading memcache with a copy of all gae/bingo
        experiments before the doppleganger test exists.

        After the doppleganger test has been created once, all future calls to
        this function simulate being run on machines that haven't yet cleared
        their instance cache and loaded the newly created doppleganger yet. We
        do this by replacing the instance cache'd state of BingoCache with the
        deep copy that we made before doppleganger was created.

        A correctly functioning test will still only create one copy of the
        experiment even though multiple clients attempted to create a new
        experiment.
        """
        # First, make a deep copy of the current state of bingo's experiments
        bingo_clone = memcache.get("bingo_clone")

        if not bingo_clone:
            # Set the clone by copying the current bingo cache state
            memcache.set("bingo_clone", copy.deepcopy(BingoCache.get()))
        else:
            # Set the current bingo cache state to the cloned state
            gae_bingo.instance_cache.set(BingoCache.CACHE_KEY, bingo_clone)

        return ab_test("doppleganger")
示例#4
0
    def get_alternative_for_user(user_data, current_user=False):
        """ Returns the experiment alternative for the specified user, or
        the current logged in user. If the user is the logged in user, will
        opt in for an experiment, as well. Will not affect experiments if
        not the current user.
        
        """

        # We're interested in analyzing the effects of different struggling
        # models on users. A more accurate model would imply that the user
        # can get help earlier on. This varies drastically for those with
        # and without coaches, so it is useful to separate the population out.
        if user_data.coaches:
            exp_name = 'Struggling model (w/coach)'
        else:
            exp_name = 'Struggling model (no coach)'

        # If it's not the current user, then it must be an admin or coach
        # viewing a dashboard. Don't affect the actual experiment as only the
        # actions of the user affect her participation in the experiment.
        if current_user:
            return ab_test(exp_name,
                           StrugglingExperiment._ab_test_alternatives,
                           StrugglingExperiment._conversion_names,
                           StrugglingExperiment._conversion_types)

        return find_alternative_for_user(exp_name, user_data)
示例#5
0
    def get(self):
        user_data = models.UserData.current() or models.UserData.pre_phantom()
        user_exercise_graph = models.UserExerciseGraph.get(user_data)

        sees_new_review = ab_test(
            'Review Mode UI',
            conversion_name=ViewExercise._review_conversion_names,
            conversion_type=ViewExercise._review_conversion_types)
        show_review_drawer = (sees_new_review and
                              not user_exercise_graph.has_completed_review())

        template_values = {
            'graph_dict_data': exercise_graph_dict_json(user_data),
            'user_data': user_data,
            'expanded_all_exercises': user_data.expanded_all_exercises,
            'map_coords':
            knowledgemap.deserializeMapCoords(user_data.map_coords),
            'selected_nav_link': 'practice',
            'show_review_drawer': show_review_drawer,
        }

        if show_review_drawer:

            template_values['review_statement'] = ab_test(
                'review_statement_of_fact', [
                    'Fortify your knowledge',
                    'Attain mastery',
                    'Review exercises',
                    'Reinforce your learning',
                    'Consolidate what you know',
                    "Master what you've learned",
                    'How much can you recall?',
                    "Let's review",
                    'Refresh your memory',
                ])

            template_values['review_call_to_action'] = ab_test(
                'review_call_to_action', [
                    'Start Reviews',
                    'Start now',
                    'Go go go!',
                    "Let's go!",
                    "I'll do it",
                    "Let's do this!",
                ])

        self.render_jinja2_template('viewexercises.html', template_values)
示例#6
0
    def get(self):
        user_data = models.UserData.current() or models.UserData.pre_phantom()
        user_exercise_graph = models.UserExerciseGraph.get(user_data)

        sees_new_review = ab_test('Review Mode UI',
            conversion_name=ViewExercise._review_conversion_names,
            conversion_type=ViewExercise._review_conversion_types)
        show_review_drawer = (sees_new_review and not
                user_exercise_graph.has_completed_review())

        template_values = {
            'graph_dict_data': exercise_graph_dict_json(user_data),
            'user_data': user_data,
            'expanded_all_exercises': user_data.expanded_all_exercises,
            'map_coords': knowledgemap.deserializeMapCoords(user_data.map_coords),
            'selected_nav_link': 'practice',
            'show_review_drawer': show_review_drawer,
        }

        if show_review_drawer:

            template_values['review_statement'] = ab_test(
                'review_statement_of_fact', [
                    'Fortify your knowledge',
                    'Attain mastery',
                    'Review exercises',
                    'Reinforce your learning',
                    'Consolidate what you know',
                    "Master what you've learned",
                    'How much can you recall?',
                    "Let's review",
                    'Refresh your memory',
                ]
            )

            template_values['review_call_to_action'] = ab_test(
                'review_call_to_action', [
                    'Start Reviews',
                    'Start now',
                    'Go go go!',
                    "Let's go!",
                    "I'll do it",
                    "Let's do this!",
                ]
            )

        self.render_jinja2_template('viewexercises.html', template_values)
示例#7
0
 def add_conversions(self):
     return ab_test("hippos",
                    conversion_name=["hippos_binary",
                                     "hippos_counting",
                                     "rhinos_counting"],
                    conversion_type=[ConversionTypes.Binary,
                                     ConversionTypes.Counting,
                                     ConversionTypes.Counting])
示例#8
0
    def get(self):

        import models

        code_url = "https://foursquare.com/oauth2/authenticate?client_id=%s&response_type=code&redirect_uri=%s" % (CLIENT_ID,REDIRECT_URI)

        self.context["fslogin"] = code_url
        self.context["page"] = "home"

        self.context["justRegistered"] = self.session.pop("justRegistered", default=None)
        logging.info("-----------------------")
        logging.info("getting justRegistered value")
        logging.info(self.context["justRegistered"])

        tasks=[]
        partnerTasks=[]
        user = None
        #----------------------------------------------
        # get user if we have one
        if self.session.has_key("userKey"):
            user_identifier = self.session["userKey"]
            user = UserProfile.get_by_key_name(user_identifier)
        #----------------------------------------------

        # redirect to settings to complete registration if we need to
        if user is not None:

            if user.status==0:
                return self.redirect('/settings')
            else:

                tasks = user.getActiveTasks()

            if user.partner:
                partnerTasks = user.partner.getActiveTasks()
#                for partnerTask in partnerTasks:
#                    tasks.append(partnerTask)
        else:
            self.context["bannerHeader"] = True
            from gae_bingo.gae_bingo import ab_test
            self.context["showshare"] = ab_test("showshare", conversion_name="registered")


        if "inviteCouple" in self.session:
            thisInvite = EmailInvite.get_by_key_name(self.session["inviteCouple"])
            if thisInvite is not None:
                logging.info("definining firstname here")
                self.context["inviteCouple"] = thisInvite
                self.context["inviter"] = thisInvite.inviter

        self.context["tasks"] = tasks
        self.context["partnerTasks"] = partnerTasks
        self.context["user"] = user
        self.render('index.html')
示例#9
0
    def get_alternative_for_user(user_data, current_user=False):
        """ Returns the experiment alternative for the specified user, or
        the current logged in user. If the user is the logged in user, will
        opt in for an experiment, as well. Will not affect experiments if
        not the current user.

        """
        exp_name = "Suggested activity on profile page"

        # If it's not the current user, then it must be an admin or coach
        # viewing a dashboard. Don't affect the actual experiment as only the
        # actions of the user affect her participation in the experiment.
        if current_user:
            return ab_test(exp_name,
                           SuggestedActivityExperiment._ab_test_alternatives,
                           SuggestedActivityExperiment._conversion_names,
                           SuggestedActivityExperiment._conversion_types)

        return find_alternative_for_user(exp_name, user_data)
示例#10
0
 def participate_in_crocodiles(self):
     # Weighted test
     return ab_test("crocodiles", {"a": 100, "b": 200, "c": 400})
示例#11
0
 def participate_in_skunks(self):
     # Too many alternatives
     return ab_test("skunks", ["a", "b", "c", "d", "e"])
示例#12
0
 def participate_in_chimpanzees(self):
     # Multiple conversions test
     return ab_test("chimpanzees", conversion_name=["chimps_conversion_1", "chimps_conversion_2"])
示例#13
0
 def participate_in_gorillas(self):
     return ab_test("gorillas", ["a", "b", "c"])
示例#14
0
 def participate_in_monkeys(self):
     return ab_test("monkeys")
示例#15
0
 def ab_test():
     """gaebingo.ab_test() wrapper"""
     return ab_test(InteractiveTranscriptExperiment.NAME,
                    InteractiveTranscriptExperiment._ab_test_alternatives,
                    InteractiveTranscriptExperiment._conversion_names,
                    InteractiveTranscriptExperiment._conversion_types)
示例#16
0
 def get_render_type():
     return ab_test("Homepage Restructuring 2",
         HomepageRestructuringExperiment._ab_test_alternatives,
         HomepageRestructuringExperiment._conversion_names,
         HomepageRestructuringExperiment._conversion_types)
示例#17
0
    def get(self):
        version_number = None

        if user_models.UserData.current() and user_models.UserData.current().developer:
            version_number = self.request_string('version', default=None)

        thumbnail_link_sets = new_and_noteworthy_link_sets()

        # If all else fails, just show the TED talk on the homepage
        marquee_video = {
            "youtube_id": "gM95HHI4gLk",
            "href": "/video?v=%s" % "gM95HHI4gLk",
            "thumb_urls": video_models.Video.youtube_thumbnail_urls("gM95HHI4gLk"),
            "title": "Salman Khan talk at TED 2011",
            "key": "",
        }

        if len(thumbnail_link_sets) > 1:

            day = datetime.datetime.now().day

            # Switch up the first 4 New & Noteworthy videos on a daily basis
            current_link_set_offset = day % len(thumbnail_link_sets)

            # Switch up the marquee video on a daily basis
            marquee_videos = []
            for thumbnail_link_set in thumbnail_link_sets:
                marquee_videos += filter(lambda item: item["marquee"],
                                         thumbnail_link_set)

            if marquee_videos:
                marquee_video = marquee_videos[day % len(marquee_videos)]
                marquee_video["selected"] = True

            if len(thumbnail_link_sets[current_link_set_offset]) < ITEMS_PER_SET:
                # If the current offset lands on a set of videos that isn't a full set, just start
                # again at the first set, which is most likely full.
                current_link_set_offset = 0

            thumbnail_link_sets = thumbnail_link_sets[current_link_set_offset:] + thumbnail_link_sets[:current_link_set_offset]

        default = topic_models.TopicVersion.get_default_version()
        if App.is_dev_server and default is None:
            library_content = "<h1>Content not initialized. <a href=\"/devadmin/content?autoupdate=1\">Click here</a> to autoupdate from khanacademy.org."
        elif version_number:
            layer_cache.disable()
            library_content = library.library_content_html(version_number=int(version_number))
        elif not self.is_mobile_capable():
            # Only running ajax version of homepage for non-mobile clients
            library_content = library.library_content_html(ajax = True)
        else:
            library_content = library.library_content_html()
            
        from gae_bingo.gae_bingo import ab_test, create_redirect_url

        donate_button_test = ab_test("hp_donate_button",
                                     {"button":1, "text":99},
                                     conversion_name=['hp_donate_button_click', 'hp_donate_button_paypal'])
        donate_redirect_url = create_redirect_url("/donate", "hp_donate_button_click")

        template_values = {
                            'marquee_video': marquee_video,
                            'thumbnail_link_sets': thumbnail_link_sets,
                            'library_content': library_content,
                            'DVD_list': DVD_list,
                            'is_mobile_allowed': True,
                            'approx_vid_count': video_models.Video.approx_count(),
                            'link_heat': self.request_bool("heat", default=False),
                            'version_number': version_number,
                            'donate_button_test': donate_button_test,
                            'donate_redirect_url': donate_redirect_url
                        }

        self.render_jinja2_template('homepage.html', template_values)

        layer_cache.enable()
示例#18
0
 def participate_in_baboons(self):
     # Multiple conversions test
     return ab_test("baboons")
    def add_global_template_values(self, template_values):
        template_values['App'] = App
        template_values['None'] = None

        if not template_values.has_key('user_data'):
            user_data = user_models.UserData.current()
            template_values['user_data'] = user_data

        user_data = template_values['user_data']

        template_values['username'] = user_data.nickname if user_data else ""
        template_values['viewer_profile_root'] = user_data.profile_root if user_data else "/profile/nouser/"
        template_values['points'] = user_data.points if user_data else 0
        template_values['logged_in'] = not user_data.is_phantom if user_data else False
        template_values['http_host'] = os.environ["HTTP_HOST"]

        # Always insert a post-login request before our continue url
        template_values['continue'] = util.create_post_login_url(template_values.get('continue') or self.request.uri)
        template_values['login_url'] = ('%s&direct=1' % util.create_login_url(template_values['continue']))
        template_values['logout_url'] = util.create_logout_url(self.request.uri)

        template_values['is_mobile'] = False
        template_values['is_mobile_capable'] = False
        template_values['is_ipad'] = False

        if self.is_mobile_capable():
            template_values['is_mobile_capable'] = True
            template_values['is_ipad'] = self.is_ipad()

            if 'is_mobile_allowed' in template_values and template_values['is_mobile_allowed']:
                template_values['is_mobile'] = self.is_mobile()

        # overridable hide_analytics querystring that defaults to true in dev
        # mode but false for prod.
        hide_analytics = self.request_bool("hide_analytics", App.is_dev_server)
        template_values['hide_analytics'] = hide_analytics

        # client-side error logging
        template_values['include_errorception'] = gandalf('errorception')

        # Analytics
        template_values['mixpanel_enabled'] = gandalf('mixpanel_enabled')

        if False: # Enable for testing only
            template_values['mixpanel_test'] = "70acc4fce4511b89477ac005639cfee1"
            template_values['mixpanel_enabled'] = True
            template_values['hide_analytics'] = False

        if template_values['mixpanel_enabled']:
            template_values['mixpanel_id'] = gae_bingo.identity.identity()

        if not template_values['hide_analytics']:
            superprops_list = user_models.UserData.get_analytics_properties(user_data)

            # Create a superprops dict for MixPanel with a version number
            # Bump the version number if changes are made to the client-side analytics
            # code and we want to be able to filter by version.
            template_values['mixpanel_superprops'] = dict(superprops_list)

            # Copy over first 4 per-user properties for GA (5th is reserved for Bingo)
            template_values['ga_custom_vars'] = superprops_list[0:4]

        if user_data:
            user_goals = goals.models.GoalList.get_current_goals(user_data)
            goals_data = [g.get_visible_data() for g in user_goals]
            if goals_data:
                template_values['global_goals'] = jsonify(goals_data)

        # Disable topic browser in the header on mobile devices
        template_values['watch_topic_browser_enabled'] = not self.is_mobile_capable()

        # Begin topic pages A/B test
        if template_values['mixpanel_enabled']:
            show_topic_pages = ab_test("Show topic pages", ["show", "hide"], ["topic_pages_view_page", "topic_pages_started_video", "topic_pages_completed_video"])
            analytics_bingo = {"name": "Bingo: Topic pages", "value": show_topic_pages}
            template_values['analytics_bingo'] = analytics_bingo
        else:
            show_topic_pages = "hide"
        template_values['show_topic_pages'] = (show_topic_pages == "show")
        # End topic pages A/B test

        return template_values
示例#20
0
 def ab_test():
     """gaebingo.ab_test() wrapper"""
     return ab_test(InteractiveTranscriptExperiment.NAME,
                    InteractiveTranscriptExperiment._ab_test_alternatives,
                    InteractiveTranscriptExperiment._conversion_names,
                    InteractiveTranscriptExperiment._conversion_types)
示例#21
0
 def get_render_type():
     return ab_test("Homepage Restructuring 2",
                    HomepageRestructuringExperiment._ab_test_alternatives,
                    HomepageRestructuringExperiment._conversion_names,
                    HomepageRestructuringExperiment._conversion_types)
示例#22
0
    def get(self):
        user_data = models.UserData.current() or models.UserData.pre_phantom()

        exid = self.request_string("exid", default="addition_1")
        exercise = models.Exercise.get_by_name(exid)

        if not exercise:
            raise MissingExerciseException("Missing exercise w/ exid '%s'" %
                                           exid)

        user_exercise = user_data.get_or_insert_exercise(exercise)

        # Cache this so we don't have to worry about future lookups
        user_exercise.exercise_model = exercise
        user_exercise._user_data = user_data
        user_exercise.summative = exercise.summative

        # Temporarily work around in-app memory caching bug
        exercise.user_exercise = None

        problem_number = self.request_int('problem_number',
                                          default=(user_exercise.total_done +
                                                   1))

        user_data_student = self.request_user_data(
            "student_email") or user_data
        if user_data_student.key_email != user_data.key_email and not user_data_student.is_visible_to(
                user_data):
            user_data_student = user_data

        viewing_other = user_data_student.key_email != user_data.key_email

        # Can't view your own problems ahead of schedule
        if not viewing_other and problem_number > user_exercise.total_done + 1:
            problem_number = user_exercise.total_done + 1

        # When viewing another student's problem or a problem out-of-order, show read-only view
        read_only = viewing_other or problem_number != (
            user_exercise.total_done + 1)

        exercise_template_html = exercise_template()

        exercise_body_html, exercise_inline_script, exercise_inline_style, data_require, sha1 = exercise_contents(
            exercise)
        user_exercise.exercise_model.sha1 = sha1

        user_exercise.exercise_model.related_videos = map(
            lambda exercise_video: exercise_video.video,
            user_exercise.exercise_model.related_videos_fetch())
        for video in user_exercise.exercise_model.related_videos:
            video.id = video.key().id()

        renderable = True

        if read_only:
            # Override current problem number and user being inspected
            # so proper exercise content will be generated
            user_exercise.total_done = problem_number - 1
            user_exercise.user = user_data_student.user
            user_exercise.read_only = True

            if not self.request_bool("renderable", True):
                # We cannot render old problems that were created in the v1 exercise framework.
                renderable = False

            query = models.ProblemLog.all()
            query.filter("user = "******"exercise = ", exid)

            # adding this ordering to ensure that query is served by an existing index.
            # could be ok if we remove this
            query.order('time_done')
            problem_logs = query.fetch(500)

            problem_log = None
            for p in problem_logs:
                if p.problem_number == problem_number:
                    problem_log = p
                    break

            user_activity = []
            previous_time = 0

            if not problem_log or not hasattr(problem_log,
                                              "hint_after_attempt_list"):
                renderable = False
            else:
                # Don't include incomplete information
                problem_log.hint_after_attempt_list = filter(
                    lambda x: x != -1, problem_log.hint_after_attempt_list)

                while len(problem_log.hint_after_attempt_list
                          ) and problem_log.hint_after_attempt_list[0] == 0:
                    user_activity.append([
                        "hint-activity", "0",
                        max(
                            0, problem_log.hint_time_taken_list[0] -
                            previous_time)
                    ])

                    previous_time = problem_log.hint_time_taken_list[0]
                    problem_log.hint_after_attempt_list.pop(0)
                    problem_log.hint_time_taken_list.pop(0)

                # For each attempt, add it to the list and then add any hints
                # that came after it
                for i in range(0, len(problem_log.attempts)):
                    user_activity.append([
                        "correct-activity"
                        if problem_log.correct else "incorrect-activity",
                        unicode(problem_log.attempts[i] if problem_log.
                                attempts[i] else 0),
                        max(0,
                            problem_log.time_taken_attempts[i] - previous_time)
                    ])

                    previous_time = 0

                    # Here i is 0-indexed but problems are numbered starting at 1
                    while len(
                            problem_log.hint_after_attempt_list
                    ) and problem_log.hint_after_attempt_list[0] == i + 1:
                        user_activity.append([
                            "hint-activity", "0",
                            max(
                                0, problem_log.hint_time_taken_list[0] -
                                previous_time)
                        ])

                        previous_time = problem_log.hint_time_taken_list[0]
                        # easiest to just pop these instead of maintaining
                        # another index into this list
                        problem_log.hint_after_attempt_list.pop(0)
                        problem_log.hint_time_taken_list.pop(0)

                user_exercise.user_activity = user_activity

                if problem_log.count_hints is not None:
                    user_exercise.count_hints = problem_log.count_hints

        is_webos = self.is_webos()
        browser_disabled = is_webos or self.is_older_ie()
        renderable = renderable and not browser_disabled

        url_pattern = "/exercises?exid=%s&student_email=%s&problem_number=%d"
        user_exercise.previous_problem_url = url_pattern % \
            (exid, user_data_student.key_email , problem_number-1)
        user_exercise.next_problem_url = url_pattern % \
            (exid, user_data_student.key_email , problem_number+1)

        user_exercise_json = jsonify.jsonify(user_exercise)

        template_values = {
            'exercise':
            exercise,
            'user_exercise_json':
            user_exercise_json,
            'exercise_body_html':
            exercise_body_html,
            'exercise_template_html':
            exercise_template_html,
            'exercise_inline_script':
            exercise_inline_script,
            'exercise_inline_style':
            exercise_inline_style,
            'data_require':
            data_require,
            'read_only':
            read_only,
            'selected_nav_link':
            'practice',
            'browser_disabled':
            browser_disabled,
            'is_webos':
            is_webos,
            'renderable':
            renderable,
            'issue_labels':
            ('Component-Code,Exercise-%s,Problem-%s' % (exid, problem_number)),
            'alternate_hints_treatment':
            ab_test('Hints or Show Solution',
                    ViewExercise._hints_ab_test_alternatives,
                    ViewExercise._hints_conversion_names,
                    ViewExercise._hints_conversion_types)
        }

        self.render_jinja2_template("exercise_template.html", template_values)
示例#23
0
文件: exercises.py 项目: di445/server
    def get(self, exid=None):

        # TODO(david): Is there some webapp2 magic that will allow me not to
        #     repeat this URL string in main.py?
        review_mode = self.request.path == "/review" 

        if not exid and not review_mode:
            self.redirect("/exercise/%s" % self.request_string("exid", default="addition_1"))
            return

        user_data = models.UserData.current() or models.UserData.pre_phantom()
        user_exercise_graph = models.UserExerciseGraph.get(user_data)

        if review_mode:
            # Take the first review exercise if available
            exid = (user_exercise_graph.review_exercise_names() or
                    user_exercise_graph.proficient_exercise_names() or
                    ["addition_1"])[0]
            reviews_left_count = user_exercise_graph.reviews_left_count()

        exercise = models.Exercise.get_by_name(exid)

        if not exercise:
            raise MissingExerciseException("Missing exercise w/ exid '%s'" % exid)

        user_exercise = user_data.get_or_insert_exercise(exercise)

        # Cache these so we don't have to worry about future lookups
        user_exercise.exercise_model = exercise
        user_exercise._user_data = user_data
        user_exercise._user_exercise_graph = user_exercise_graph
        user_exercise.summative = exercise.summative

        # Temporarily work around in-app memory caching bug
        exercise.user_exercise = None

        problem_number = self.request_int('problem_number', default=(user_exercise.total_done + 1))

        user_data_student = self.request_student_user_data(legacy=True) or user_data
        if user_data_student.key_email != user_data.key_email and not user_data_student.is_visible_to(user_data):
            user_data_student = user_data

        viewing_other = user_data_student.key_email != user_data.key_email

        # Can't view your own problems ahead of schedule
        if not viewing_other and problem_number > user_exercise.total_done + 1:
            problem_number = user_exercise.total_done + 1

        # When viewing another student's problem or a problem out-of-order, show read-only view
        read_only = viewing_other or problem_number != (user_exercise.total_done + 1)

        exercise_template_html = exercise_template()

        exercise_body_html, exercise_inline_script, exercise_inline_style, data_require, sha1 = exercise_contents(exercise)
        user_exercise.exercise_model.sha1 = sha1

        user_exercise.exercise_model.related_videos = map(lambda exercise_video: exercise_video.video, user_exercise.exercise_model.related_videos_fetch())
        for video in user_exercise.exercise_model.related_videos:
            video.id = video.key().id()

        renderable = True

        if read_only:
            # Override current problem number and user being inspected
            # so proper exercise content will be generated
            user_exercise.total_done = problem_number - 1
            user_exercise.user = user_data_student.user
            user_exercise.read_only = True

            if not self.request_bool("renderable", True):
                # We cannot render old problems that were created in the v1 exercise framework.
                renderable = False

            query = models.ProblemLog.all()
            query.filter("user = "******"exercise = ", exid)

            # adding this ordering to ensure that query is served by an existing index.
            # could be ok if we remove this
            query.order('time_done')
            problem_logs = query.fetch(500)

            problem_log = None
            for p in problem_logs:
                if p.problem_number == problem_number:
                    problem_log = p
                    break

            user_activity = []
            previous_time = 0

            if not problem_log or not hasattr(problem_log, "hint_after_attempt_list"):
                renderable = False
            else:
                # Don't include incomplete information
                problem_log.hint_after_attempt_list = filter(lambda x: x != -1, problem_log.hint_after_attempt_list)

                while len(problem_log.hint_after_attempt_list) and problem_log.hint_after_attempt_list[0] == 0:
                    user_activity.append([
                        "hint-activity",
                        "0",
                        max(0, problem_log.hint_time_taken_list[0] - previous_time)
                        ])

                    previous_time = problem_log.hint_time_taken_list[0]
                    problem_log.hint_after_attempt_list.pop(0)
                    problem_log.hint_time_taken_list.pop(0)

                # For each attempt, add it to the list and then add any hints
                # that came after it
                for i in range(0, len(problem_log.attempts)):
                    user_activity.append([
                        "correct-activity" if problem_log.correct else "incorrect-activity",
                        unicode(problem_log.attempts[i] if problem_log.attempts[i] else 0),
                        max(0, problem_log.time_taken_attempts[i] - previous_time)
                        ])

                    previous_time = 0

                    # Here i is 0-indexed but problems are numbered starting at 1
                    while (len(problem_log.hint_after_attempt_list) and
                            problem_log.hint_after_attempt_list[0] == i + 1):
                        user_activity.append([
                            "hint-activity",
                            "0",
                            max(0, problem_log.hint_time_taken_list[0] - previous_time)
                            ])

                        previous_time = problem_log.hint_time_taken_list[0]
                        # easiest to just pop these instead of maintaining
                        # another index into this list
                        problem_log.hint_after_attempt_list.pop(0)
                        problem_log.hint_time_taken_list.pop(0)

                user_exercise.user_activity = user_activity

                if problem_log.count_hints is not None:
                    user_exercise.count_hints = problem_log.count_hints

                user_exercise.current = problem_log.sha1 == sha1
        else:
            # Not read_only
            suggested_exercise_names = user_exercise_graph.suggested_exercise_names()
            if exercise.name in suggested_exercise_names:
                bingo('suggested_activity_visit_suggested_exercise')

        is_webos = self.is_webos()
        browser_disabled = is_webos or self.is_older_ie()
        renderable = renderable and not browser_disabled

        url_pattern = "/exercise/%s?student_email=%s&problem_number=%d"
        user_exercise.previous_problem_url = url_pattern % \
            (exid, user_data_student.key_email, problem_number - 1)
        user_exercise.next_problem_url = url_pattern % \
            (exid, user_data_student.key_email, problem_number + 1)

        user_exercise_json = jsonify.jsonify(user_exercise)

        template_values = {
            'exercise': exercise,
            'user_exercise_json': user_exercise_json,
            'exercise_body_html': exercise_body_html,
            'exercise_template_html': exercise_template_html,
            'exercise_inline_script': exercise_inline_script,
            'exercise_inline_style': exercise_inline_style,
            'data_require': data_require,
            'read_only': read_only,
            'selected_nav_link': 'practice',
            'browser_disabled': browser_disabled,
            'is_webos': is_webos,
            'renderable': renderable,
            'issue_labels': ('Component-Code,Exercise-%s,Problem-%s' % (exid, problem_number)),
            'alternate_hints_treatment': ab_test('Hints or Show Solution Dec 10',
                ViewExercise._hints_ab_test_alternatives,
                ViewExercise._hints_conversion_names,
                ViewExercise._hints_conversion_types,
                'Hints or Show Solution Nov 5'),
            'reviews_left_count': reviews_left_count if review_mode else "null",
        }
        self.render_jinja2_template("exercise_template.html", template_values)
示例#24
0
    def get(self):
	    if ab_test("new button design"):
	        self.response.write('Hello world! <a href="/click">Click Me!</a>')
	    else:
	        self.response.write('Hello world! <a href="/click">Click Here!</a>')