def test_user_exercise_preserved_after_consuming(self):
        # A user goes on as a phantom...
        phantom = UserData.insert_for("phantom", "phantom")
        exercises = [
            self.make_exercise("Adding 1"),
            self.make_exercise("Multiplication yo"),
            self.make_exercise("All about chickens"),
        ]

        # Does some exercises....
        for e in exercises:
            ue = phantom.get_or_insert_exercise(e)
            ue.total_done = 7
            ue.put()

        # Signs up!
        jimmy = UserData.insert_for("*****@*****.**",
                                    email="*****@*****.**")
        phantom.consume_identity(jimmy)

        # Make sure we can still see the old user exercises
        shouldbejimmy = UserData.get_from_user_id("*****@*****.**")
        user_exercises = (exercise_models.UserExercise.get_for_user_data(
            shouldbejimmy).fetch(100))
        self.assertEqual(len(exercises), len(user_exercises))
        for ue in user_exercises:
            self.assertEqual(7, ue.total_done)
    def test_url_segment_generation(self):
        # Pre-phantom users can't have profile URL's
        prephantom = UserData.pre_phantom()
        self.assertTrue(self.from_url(self.to_url(prephantom)) is None)

        # Phantom users can't have profile URL's
        phantom = self.create_phantom()
        self.assertTrue(self.from_url(self.to_url(phantom)) is None)

        # Normal users are cool, though.
        bob = UserData.insert_for(
                "http://googleid.khanacademy.org/1234",
                "*****@*****.**")
        bob.put()
        self.assertEqual(
                self.from_url(self.to_url(bob)).user_id,
                bob.user_id)

        sally = UserData.insert_for(
                "http://facebookid.khanacademy.org/1234",
                "http://facebookid.khanacademy.org/1234")
        sally.put()
        self.assertEqual(
                self.from_url(self.to_url(sally)).user_id,
                sally.user_id)
    def test_user_identity_consumption(self):
        superman = UserData.insert_for(
            "*****@*****.**",
            email="*****@*****.**",
            username="******",
            password="******",
            gender="male",
        )

        clark = UserData.insert_for(
            "*****@*****.**",
            email="*****@*****.**",
            username=None,
            password=None,
        )

        clark.consume_identity(superman)
        self.assertEqual("*****@*****.**", clark.user_id)
        self.assertEqual("*****@*****.**", clark.email)
        self.assertEqual(clark.key(),
                         UserData.get_from_username("superman").key())
        self.assertEqual(
            clark.key(),
            UserData.get_from_user_id("*****@*****.**").key())
        self.assertTrue(clark.validate_password("Password1"))
    def test_user_exercise_preserved_after_consuming(self):
        # A user goes on as a phantom...
        phantom = UserData.insert_for("phantom", "phantom")
        exercises = [
                self.make_exercise("Adding 1"),
                self.make_exercise("Multiplication yo"),
                self.make_exercise("All about chickens"),
                ]

        # Does some exercises....
        for e in exercises:
            ue = phantom.get_or_insert_exercise(e)
            ue.total_done = 7
            ue.put()

        # Signs up!
        jimmy = UserData.insert_for("*****@*****.**",
                                    email="*****@*****.**")
        phantom.consume_identity(jimmy)

        # Make sure we can still see the old user exercises
        shouldbejimmy = UserData.get_from_user_id("*****@*****.**")
        user_exercises = (exercise_models.UserExercise.
                          get_for_user_data(shouldbejimmy).fetch(100))
        self.assertEqual(len(exercises), len(user_exercises))
        for ue in user_exercises:
            self.assertEqual(7, ue.total_done)
示例#5
0
    def get(self):
        coach = UserData.current()

        user_override = self.request_user_data("coach_email")
        if user_override and user_override.are_students_visible_to(coach):
            # Only allow looking at a student list other than your own
            # if you are a dev, admin, or coworker.
            coach = user_override

        student_lists = StudentList.get_for_coach(coach.key())

        student_lists_list = [{
            'key': 'allstudents',
            'name': 'All students',
        }]
        for student_list in student_lists:
            student_lists_list.append({
                'key': str(student_list.key()),
                'name': student_list.name,
            })

        list_id, _ = get_last_student_list(self, student_lists,
                                           coach == UserData.current())
        current_list = None
        for student_list in student_lists_list:
            if student_list['key'] == list_id:
                current_list = student_list

        selected_graph_type = self.request_string(
            "selected_graph_type") or ClassProgressReportGraph.GRAPH_TYPE
        if selected_graph_type == 'progressreport' or selected_graph_type == 'goals':  # TomY This is temporary until all the graphs are API calls
            initial_graph_url = "/api/v1/user/students/%s?coach_email=%s&%s" % (
                selected_graph_type, urllib.quote(coach.email),
                urllib.unquote(
                    self.request_string("graph_query_params", default="")))
        else:
            initial_graph_url = "/profile/graph/%s?coach_email=%s&%s" % (
                selected_graph_type, urllib.quote(coach.email),
                urllib.unquote(
                    self.request_string("graph_query_params", default="")))
        initial_graph_url += 'list_id=%s' % list_id

        template_values = {
            'user_data_coach': coach,
            'coach_email': coach.email,
            'list_id': list_id,
            'student_list': current_list,
            'student_lists': student_lists_list,
            'student_lists_json': json.dumps(student_lists_list),
            'coach_nickname': coach.nickname,
            'selected_graph_type': selected_graph_type,
            'initial_graph_url': initial_graph_url,
            'exercises': exercise_models.Exercise.get_all_use_cache(),
            'is_profile_empty': not coach.has_students(),
            'selected_nav_link': 'coach',
            "view": self.request_string("view", default=""),
            'stats_charts_class': 'coach-view',
        }
        self.render_jinja2_template('viewclassprofile.html', template_values)
    def test_creation_with_existing_username(self):
        self.flush([self.insert_user("larry", "*****@*****.**", "larry")])
        self.assertEqual(1, UserData.all().count())
        self.assertEqual("larry", UserData.all()[0].user_id)
        self.assertEqual("larry", UserData.all()[0].username)

        self.assertTrue(self.insert_user("larry2", "*****@*****.**",
            "larry") is None)
    def test_creation_with_existing_username(self):
        self.flush([self.insert_user("larry", "*****@*****.**", "larry")])
        self.assertEqual(1, UserData.all().count())
        self.assertEqual("larry", UserData.all()[0].user_id)
        self.assertEqual("larry", UserData.all()[0].username)

        self.assertTrue(
            self.insert_user("larry2", "*****@*****.**", "larry") is None)
 def test_creation_with_password(self):
     self.flush([
         self.insert_user("larry", "*****@*****.**", "larry", "Password1")
     ])
     self.assertEqual(1, UserData.all().count())
     retrieved = UserData.all()[0]
     self.assertEqual("larry", retrieved.user_id)
     self.assertTrue(retrieved.validate_password("Password1"))
     self.assertFalse(retrieved.validate_password("Password2"))
 def test_creation_with_password(self):
     self.flush([self.insert_user("larry",
                                  "*****@*****.**",
                                  "larry",
                                  "Password1")])
     self.assertEqual(1, UserData.all().count())
     retrieved = UserData.all()[0]
     self.assertEqual("larry", retrieved.user_id)
     self.assertTrue(retrieved.validate_password("Password1"))
     self.assertFalse(retrieved.validate_password("Password2"))
示例#10
0
    def get(self):
        coach = UserData.current()

        user_override = self.request_user_data("coach_email")
        if user_override and user_override.are_students_visible_to(coach):
            # Only allow looking at a student list other than your own
            # if you are a dev, admin, or coworker.
            coach = user_override

        student_lists = StudentList.get_for_coach(coach.key())

        student_lists_list = [{
            'key': 'allstudents',
            'name': 'All students',
        }];
        for student_list in student_lists:
            student_lists_list.append({
                'key': str(student_list.key()),
                'name': student_list.name,
            })

        list_id, _ = get_last_student_list(self, student_lists, coach==UserData.current())
        current_list = None
        for student_list in student_lists_list:
            if student_list['key'] == list_id:
                current_list = student_list

        selected_graph_type = self.request_string("selected_graph_type") or ClassProgressReportGraph.GRAPH_TYPE
        if selected_graph_type == 'progressreport' or selected_graph_type == 'goals': # TomY This is temporary until all the graphs are API calls
            initial_graph_url = "/api/v1/user/students/%s?coach_email=%s&%s" % (selected_graph_type, urllib.quote(coach.email), urllib.unquote(self.request_string("graph_query_params", default="")))
        else:
            initial_graph_url = "/profile/graph/%s?coach_email=%s&%s" % (selected_graph_type, urllib.quote(coach.email), urllib.unquote(self.request_string("graph_query_params", default="")))
        initial_graph_url += 'list_id=%s' % list_id

        template_values = {
                'user_data_coach': coach,
                'coach_email': coach.email,
                'list_id': list_id,
                'student_list': current_list,
                'student_lists': student_lists_list,
                'student_lists_json': json.dumps(student_lists_list),
                'coach_nickname': coach.nickname,
                'selected_graph_type': selected_graph_type,
                'initial_graph_url': initial_graph_url,
                'exercises': exercise_models.Exercise.get_all_use_cache(),
                'is_profile_empty': not coach.has_students(),
                'selected_nav_link': 'coach',
                "view": self.request_string("view", default=""),
                'stats_charts_class': 'coach-view',
                }
        self.render_jinja2_template('viewclassprofile.html', template_values)
示例#11
0
def create_scratchpad():
    """Create a new Scratchpad and associated ScratchpadRevision.

    The POST data should be a JSON-encoded dict, which is passed verbatim to
    Scratchpad.create as keyword arguments.
    """
    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    if not request.json:
        return api_invalid_param_response("Bad data supplied: Not JSON")

    # TODO(jlfwong): Support phantom users
    user = UserData.current()

    if not (user and user.developer):
        # Certain fields are only modifiable by developers
        for field in scratchpad_models.Scratchpad._developer_only_fields:
            if request.json.get(field):
                return api_forbidden_response(
                    "Forbidden: Only developers can change the %s" % field)

    try:
        # Convert unicode encoded JSON keys to strings
        create_args = dict_keys_to_strings(request.json)
        if user:
            create_args['user_id'] = user.user_id
        return scratchpad_models.Scratchpad.create(**create_args)
    except (db.BadValueError, db.BadKeyError), e:
        return api_invalid_param_response("Bad data supplied: " + e.message)
示例#12
0
    def post(self):
        user_data = UserData.current()
        if not user_data:
            return

        if user_data.is_child_account():
            self.render_json({"error": "You cannot vote yet."})
            return

        vote_type = self.request_int(
            "vote_type", default=discussion_models.FeedbackVote.ABSTAIN)

        if (vote_type == discussion_models.FeedbackVote.UP
                and not Privileges.can_up_vote(user_data)):
            self.render_json({
                "error":
                Privileges.need_points_desc(Privileges.UP_VOTE_THRESHOLD,
                                            "up vote")
            })
            return
        elif (vote_type == discussion_models.FeedbackVote.DOWN
              and not Privileges.can_down_vote(user_data)):
            self.render_json({
                "error":
                Privileges.need_points_desc(Privileges.DOWN_VOTE_THRESHOLD,
                                            "down vote")
            })
            return

        entity_key = self.request_string("entity_key", default="")
        if entity_key:
            entity = db.get(entity_key)
            if entity and entity.authored_by(user_data):
                self.render_json(
                    {"error": "You cannot vote for your own posts."})
                return

        if vote_type != discussion_models.FeedbackVote.ABSTAIN:
            limiter = VoteRateLimiter(user_data)
            if not limiter.increment():
                self.render_json({"error": limiter.denied_desc()})
                return

        # We kick off a taskqueue item to perform the actual vote insertion
        # so we don't have to worry about fast writes to the entity group
        # causing contention problems for the HR datastore, because
        # the taskqueue will just retry w/ exponential backoff.
        # TODO(marcia): user_data.email may change. user_id is preferred
        taskqueue.add(url='/admin/discussion/finishvoteentity',
                      queue_name='voting-queue',
                      params={
                          "email":
                          user_data.email,
                          "vote_type":
                          self.request_int(
                              "vote_type",
                              default=discussion_models.FeedbackVote.ABSTAIN),
                          "entity_key":
                          entity_key
                      })
 def test_request_video(self):
     exs = exercise_models.Exercise.all().fetch(1000)
     user = UserData.current()
     self.assertFalse(exs[0].video_requested)
     exs[0].request_video()
     self.assertTrue(exs[0].video_requested)
     self.assertEqual(exs[0].video_requests_count, 1)
示例#14
0
    def post(self):
        template_values = {}
        user_data = UserData.current()

        status_file = StringIO.StringIO(self.request_string('status_file'))
        reader = csv.reader(status_file)
        student_list = []
        for line in reader:
            student_email = line[0]
            student_status = line[1]
            student_comment = line[2]

            student = SummerStudent.all().filter('email =', student_email).get()
            if student is None:
                logging.error("Student %s not found" % student_email)
                continue

            student.application_status = student_status
            student.comment = student_comment
            if student_status == "Accepted":
                student.accepted = True

            student_list.append(student)

        db.put(student_list)

        self.response.out.write("OK")
        self.response.set_status(200)
    def test_creation_without_username(self):
        added = [
            self.insert_user("larry", "*****@*****.**"),
            self.insert_user("curly", "*****@*****.**"),
            self.insert_user("moe", "*****@*****.**"),
        ]
        # We don't care about consistency policy issues - we just want proper
        # counts and such.
        self.flush(added)
        self.assertEqual(3, UserData.all().count())
        self.assertEqual(set(["larry", "curly", "moe"]),
                         set(user.user_id for user in UserData.all()))

        # "Re-adding" moe doesn't duplicate.
        self.flush([self.insert_user("moe", "*****@*****.**")])
        self.assertEqual(3, UserData.all().count())
示例#16
0
def update_coaches(user_data, coaches_json):
    """ Add as coaches those in coaches_json with isCoachingLoggedInUser
    value True, and remove any old coaches not in coaches_json.
    
    Return a list of requesters' emails.
    """
    updated_coach_key_emails = []
    current_coaches_data = user_data.get_coaches_data()
    outstanding_coaches_dict = dict([(coach.email, coach.key_email)
            for coach in current_coaches_data])
    requester_emails = []

    for coach_json in coaches_json:
        email = coach_json['email']
        is_coaching_logged_in_user = coach_json['isCoachingLoggedInUser']
        if is_coaching_logged_in_user:
            if email in outstanding_coaches_dict:
                # Email corresponds to a current coach
                updated_coach_key_emails.append(outstanding_coaches_dict[email])
                del outstanding_coaches_dict[email]
            else:
                # Look up this new coach's key_email
                coach_user_data = UserData.get_from_username_or_email(email)
                if coach_user_data is not None:
                    updated_coach_key_emails.append(coach_user_data.key_email)
                else:
                    raise custom_exceptions.InvalidEmailException()
        else:
            requester_emails.append(email)

    user_data.remove_student_lists(outstanding_coaches_dict.keys())
    user_data.coaches = updated_coach_key_emails
    user_data.put()

    return requester_emails
示例#17
0
def delete_scratchpad(scratchpad_id):
    """Mark a pre-existing Scratchpad as deleted.

    An empty request body is expected."""

    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    user = UserData.current()
    scratchpad = scratchpad_models.Scratchpad.get_by_id(scratchpad_id)

    if not scratchpad or scratchpad.deleted:
        return api_not_found_response("No scratchpad with id %s" %
                                      scratchpad_id)

    # Users can only delete scratchpad they created
    # EXCEPTION: Developres can delete any scratchpad
    if not user.developer and scratchpad.user_id != user.user_id:
        return api_forbidden_response(
            "Forbidden: Scratchpad owned by different user")

    scratchpad.deleted = True
    scratchpad.put()

    return api_success_no_content_response()
    def test_creation_without_username(self):
        added = [
            self.insert_user("larry", "*****@*****.**"),
            self.insert_user("curly", "*****@*****.**"),
            self.insert_user("moe", "*****@*****.**"),
        ]
        # We don't care about consistency policy issues - we just want proper
        # counts and such.
        self.flush(added)
        self.assertEqual(3, UserData.all().count())
        self.assertEqual(set(["larry", "curly", "moe"]),
                         set(user.user_id for user in UserData.all()))

        # "Re-adding" moe doesn't duplicate.
        self.flush([self.insert_user("moe", "*****@*****.**")])
        self.assertEqual(3, UserData.all().count())
示例#19
0
def delete_scratchpad(scratchpad_id):
    """Mark a pre-existing Scratchpad as deleted.

    An empty request body is expected."""

    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    user = UserData.current()
    scratchpad = scratchpad_models.Scratchpad.get_by_id(scratchpad_id)

    if not scratchpad or scratchpad.deleted:
        return api_not_found_response(
            "No scratchpad with id %s" % scratchpad_id)

    # Users can only delete scratchpad they created
    # EXCEPTION: Developres can delete any scratchpad
    if not user.developer and scratchpad.user_id != user.user_id:
        return api_forbidden_response(
            "Forbidden: Scratchpad owned by different user")

    scratchpad.deleted = True
    scratchpad.put()

    return api_success_no_content_response()
示例#20
0
def create_scratchpad():
    """Create a new Scratchpad and associated ScratchpadRevision.

    The POST data should be a JSON-encoded dict, which is passed verbatim to
    Scratchpad.create as keyword arguments.
    """
    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    if not request.json:
        return api_invalid_param_response("Bad data supplied: Not JSON")

    # TODO(jlfwong): Support phantom users
    user = UserData.current()

    if not (user and user.developer):
        # Certain fields are only modifiable by developers
        for field in scratchpad_models.Scratchpad._developer_only_fields:
            if request.json.get(field):
                return api_forbidden_response(
                    "Forbidden: Only developers can change the %s" % field)

    try:
        # Convert unicode encoded JSON keys to strings
        create_args = dict_keys_to_strings(request.json)
        if user:
            create_args['user_id'] = user.user_id
        return scratchpad_models.Scratchpad.create(**create_args)
    except (db.BadValueError, db.BadKeyError), e:
        return api_invalid_param_response("Bad data supplied: " + e.message)
示例#21
0
    def test_return_key_in_profile_root_for_users_without_username(self):
        bob = UserData.insert_for(
            "http://googleid.khanacademy.org/1234",
            "*****@*****.**")

        desired_profile_root = ("/profile/" + _USER_KEY_PREFIX + str(bob.key())
                + "/")
        self.assertEquals(desired_profile_root, bob.profile_root)
示例#22
0
    def post(self):
        user_data = UserData.current()
        if not user_data:
            return

        if user_data.is_child_account():
            self.render_json({"error": "Je kan nog niet stemmen."})
            return

        vote_type = self.request_int(
            "vote_type", default=discussion_models.FeedbackVote.ABSTAIN)

        if (vote_type == discussion_models.FeedbackVote.UP and
            not Privileges.can_up_vote(user_data)):
            self.render_json({
                "error": Privileges.need_points_desc(
                    Privileges.UP_VOTE_THRESHOLD, "up vote")
            })
            return
        elif (vote_type == discussion_models.FeedbackVote.DOWN and
              not Privileges.can_down_vote(user_data)):
            self.render_json({
                "error": Privileges.need_points_desc(
                    Privileges.DOWN_VOTE_THRESHOLD, "down vote")
            })
            return

        entity_key = self.request_string("entity_key", default="")
        if entity_key:
            entity = db.get(entity_key)
            if entity and entity.authored_by(user_data):
                self.render_json({
                    "error": "Je kan niet op je eigen opmerking stemmen."
                })
                return

        if vote_type != discussion_models.FeedbackVote.ABSTAIN:
            limiter = VoteRateLimiter(user_data)
            if not limiter.increment():
                self.render_json({"error": limiter.denied_desc()})
                return

        # We kick off a taskqueue item to perform the actual vote insertion
        # so we don't have to worry about fast writes to the entity group
        # causing contention problems for the HR datastore, because
        # the taskqueue will just retry w/ exponential backoff.
        # TODO(marcia): user_data.email may change. user_id is preferred
        taskqueue.add(
            url='/admin/discussion/finishvoteentity',
            queue_name='voting-queue',
            params={
                "email": user_data.email,
                "vote_type": self.request_int(
                    "vote_type",
                    default=discussion_models.FeedbackVote.ABSTAIN),
                "entity_key": entity_key
            }
        )
示例#23
0
    def get(self):
        developers = UserData.all()
        developers.filter('developer = ', True).fetch(1000)
        template_values = { 
            "developers": developers,
            "selected_id": "devs",
        }

        self.render_jinja2_template('devpanel/devs.html', template_values) 
示例#24
0
    def get(self):
        developers = UserData.all()
        developers.filter('developer = ', True).fetch(1000)
        template_values = {
            "developers": developers,
            "selected_id": "devs",
        }

        self.render_jinja2_template('devpanel/devs.html', template_values)
示例#25
0
    def get(self):
        user_data = UserData.current()
        user_data_override = self.request_user_data("coach_email")
        if user_util.is_current_user_developer() and user_data_override:
            user_data = user_data_override

        invalid_student = self.request_bool("invalid_student", default=False)

        coach_requests = [req.student_requested_identifier
                          for req in CoachRequest.get_for_coach(user_data)
                          if req.student_requested_data]

        student_lists_models = StudentList.get_for_coach(user_data.key())
        student_lists_list = []
        for student_list in student_lists_models:
            student_lists_list.append({
                'key': str(student_list.key()),
                'name': student_list.name,
            })
        student_lists_dict = dict((g['key'], g) for g in student_lists_list)

        def student_to_dict(s):
            """Convert the UserData s to a dictionary for rendering."""
            return {
                'key': str(s.key()),
                'email': s.email,
                'username': s.username,
                # Note that child users don't have an email.
                'identifier': s.username or s.email,
                'nickname': s.nickname,
                'profile_root': s.profile_root,
                'can_modify_coaches': s.can_modify_coaches(),
                'studentLists':
                        [l for l in [student_lists_dict.get(str(list_id))
                           for list_id in s.student_lists] if l],
            }

        students_data = user_data.get_students_data()
        students = map(student_to_dict, students_data)
        students.sort(key=lambda s: s['nickname'])

        child_accounts = map(student_to_dict, user_data.get_child_users())
        template_values = {
            'students': students,
            'child_accounts': child_accounts,
            'child_account_keyset': set([c['key'] for c in child_accounts]),
            'students_json': json.dumps(students),
            'student_lists': student_lists_list,
            'student_lists_json': json.dumps(student_lists_list),
            'invalid_student': invalid_student,
            'coach_requests': coach_requests,
            'coach_requests_json': json.dumps(coach_requests),
            'selected_nav_link': 'coach',
            'email': user_data.email,
        }
        self.render_jinja2_template('viewstudentlists.html', template_values)
示例#26
0
def get_coaches_all_students():
    users = UserData.all()
    coaches_dict = {}
    for user in users:
        for coach in user.coaches:
            if not coach in coaches_dict:
                coaches_dict[coach] = [user.user_email]
            else:
                coaches_dict[coach].append(user.user_email)
    return coaches_dict
示例#27
0
    def do_request(self, student, coach, redirect_to):
        if not UserData.current():
            self.redirect(util.create_login_url(self.request.uri))
            return

        if student and coach:
            self.remove_student_from_coach(student, coach)

        if not self.is_ajax_request():
            self.redirect(redirect_to)
示例#28
0
def get_user_scratchpads():
    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    user_data = (get_visible_user_data_from_request() or
                 UserData.pre_phantom())
    return list(scratchpad_models.Scratchpad
        .get_for_user_data(user_data)
        .run(batch_size=1000))
示例#29
0
def get_coaches_all_students():
    users = UserData.all()
    coaches_dict = {}
    for user in users:
        for coach in user.coaches:
            if not coach in coaches_dict:
                coaches_dict[coach] = [user.user_email]
            else:
                coaches_dict[coach].append(user.user_email)
    return coaches_dict
示例#30
0
    def do_request(self, student, coach, redirect_to):
        if not UserData.current():
            self.redirect(url_util.create_login_url(self.request.uri))
            return

        if student and coach:
            self.remove_student_from_coach(student, coach)

        if not self.is_ajax_request():
            self.redirect(redirect_to)
示例#31
0
    def get(self):
        user_data = UserData.current()
        user_video_css = video_models.UserVideoCss.get_for_user_data(user_data)
        self.response.headers['Content-Type'] = 'text/css'

        if user_video_css.version == user_data.uservideocss_version:
            # Don't cache if there's a version mismatch and update isn't finished
            self.response.headers['Cache-Control'] = 'public,max-age=1000000'

        self.response.out.write(user_video_css.video_css)
示例#32
0
    def get(self):
        coach = UserData.current()

        self.render_jinja2_template('coach_resources/view_demo.html', {
            "selected_id": "demo",
            "base_url": "/toolkit",
            "not_in_toolkit_format": 1,
            "is_logged_in": json.dumps(not coach.is_phantom if coach
                                       else False),
        })
示例#33
0
def get_user_scratchpads():
    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    user_data = (get_visible_user_data_from_request()
                 or UserData.pre_phantom())
    return list(
        scratchpad_models.Scratchpad.get_for_user_data(user_data).run(
            batch_size=1000))
示例#34
0
    def get(self):
        user_data = UserData.current()
        user_video_css = video_models.UserVideoCss.get_for_user_data(user_data)
        self.response.headers['Content-Type'] = 'text/css'

        if user_video_css.version == user_data.uservideocss_version:
            # Don't cache if there's a version mismatch and update isn't finished
            self.response.headers['Cache-Control'] = 'public,max-age=1000000'

        self.response.out.write(user_video_css.video_css)
示例#35
0
    def get_profile_target_user_data(self):
        coach = UserData.current()

        if coach:
            user_override = self.request_user_data("coach_email")
            if user_override and user_override.are_students_visible_to(coach):
                # Only allow looking at a student list other than your own
                # if you are a dev, admin, or coworker.
                coach = user_override

        return coach
示例#36
0
    def test_return_username_in_profile_root_if_exists(self):
        bob = UserData.insert_for(
            "http://googleid.khanacademy.org/1234",
            "*****@*****.**")

        username = "******"
        bob.claim_username(username)

        desired_profile_root = "/profile/" + username + "/"

        self.assertEquals(desired_profile_root, bob.profile_root)
示例#37
0
    def get_profile_target_user_data(self):
        coach = UserData.current()

        if coach:
            user_override = self.request_user_data("coach_email")
            if user_override and user_override.are_students_visible_to(coach):
                # Only allow looking at a student list other than your own
                # if you are a dev, admin, or coworker.
                coach = user_override

        return coach
    def test_url_segment_generation(self):
        # Pre-phantom users can't have profile URL's
        prephantom = UserData.pre_phantom()
        self.assertTrue(self.from_url(self.to_url(prephantom)) is None)

        # Phantom users can't have profile URL's
        phantom = self.create_phantom()
        self.assertTrue(self.from_url(self.to_url(phantom)) is None)

        # Normal users are cool, though.
        bob = UserData.insert_for("http://googleid.khanacademy.org/1234",
                                  "*****@*****.**")
        bob.put()
        self.assertEqual(self.from_url(self.to_url(bob)).user_id, bob.user_id)

        sally = UserData.insert_for("http://facebookid.khanacademy.org/1234",
                                    "http://facebookid.khanacademy.org/1234")
        sally.put()
        self.assertEqual(
            self.from_url(self.to_url(sally)).user_id, sally.user_id)
    def test_releasing_usernames(self):
        clock = testutil.MockDatetime()
        u1 = self.make_user("bob")
        u2 = self.make_user("robert")

        # u1 gets "superbob", but changes his mind.
        self.assertTrue(u1.claim_username("superbob", clock))
        self.assertEqual("superbob", u1.username)
        self.assertTrue(u1.claim_username("ultrabob", clock))
        self.assertEqual("ultrabob", u1.username)

        # TOTAL HACK - for some reason without this read (which shouldn't
        # actually have any side effect), the following assert fails because
        # there's no strong consistency ensured on the HRD.
        db.get([u1.key()])
        self.assertEqual(
                u1.user_id,
                UserData.get_from_username("ultrabob").user_id)
        self.assertEqual(
                None,
                UserData.get_from_username("superbob"))

        # Usernames go into a holding pool, even after they're released
        self.assertFalse(u2.claim_username("superbob", clock))

        # Note that the original owner can't even have it back
        self.assertFalse(u1.claim_username("superbob", clock))

        # Still no good at the border of the holding period
        clock.advance(UniqueUsername.HOLDING_PERIOD_DELTA)
        self.assertFalse(u2.claim_username("superbob", clock))

        # OK - now u2 can have it.
        clock.advance_days(1)
        self.assertTrue(u2.claim_username("superbob", clock))
        self.assertEqual("superbob", u2.username)

        db.get([u2.key()])
        self.assertEqual(
                u2.user_id,
                UserData.get_from_username("superbob").user_id)
示例#40
0
    def get(self):
        template_values = {}
        user_data = UserData.current()

        if user_data is not None:
            return self.authenticated_response()

        else:
            template_values = {
                "authenticated" : False,
            }

        self.add_global_template_values(template_values)
        self.render_jinja2_template('summer/summer_process.html', template_values)
示例#41
0
    def get(self):
        coach = UserData.current()

        self.render_jinja2_template(
            'coach_resources/view_demo.html', {
                "selected_id":
                "demo",
                "base_url":
                "/toolkit",
                "not_in_toolkit_format":
                1,
                "is_logged_in":
                json.dumps(not coach.is_phantom if coach else False),
            })
示例#42
0
def get_coaches_students_count():
    coaches_dict = get_coaches_all_students()
    coaches_list = []
    for coach_email, students_list in coaches_dict.items():
        coach = UserData.all().filter("user_email = ", coach_email).get()
        if coach:
            coach_dict = {
                "joined": str(coach.joined),
                "last_activity": str(coach.last_activity),
                "coach_email": coach_email,
                "number_of_students": len(students_list)
            }
            coaches_list.append(coach_dict)
    return coaches_list
示例#43
0
def get_coaches_students_count():
    coaches_dict = get_coaches_all_students()
    coaches_list = []
    for coach_email, students_list in coaches_dict.items():
        coach = UserData.all().filter("user_email = ", coach_email).get()
        if coach:
            coach_dict = { 
                            "joined": str(coach.joined),
                            "last_activity": str(coach.last_activity),
                            "coach_email": coach_email,
                            "number_of_students": len(students_list)
                         }
            coaches_list.append(coach_dict)
    return coaches_list
    def test_releasing_usernames(self):
        clock = testutil.MockDatetime()
        u1 = self.make_user("bob")
        u2 = self.make_user("robert")

        # u1 gets "superbob", but changes his mind.
        self.assertTrue(u1.claim_username("superbob", clock))
        self.assertEqual("superbob", u1.username)
        self.assertTrue(u1.claim_username("ultrabob", clock))
        self.assertEqual("ultrabob", u1.username)

        # TOTAL HACK - for some reason without this read (which shouldn't
        # actually have any side effect), the following assert fails because
        # there's no strong consistency ensured on the HRD.
        db.get([u1.key()])
        self.assertEqual(u1.user_id,
                         UserData.get_from_username("ultrabob").user_id)
        self.assertEqual(None, UserData.get_from_username("superbob"))

        # Usernames go into a holding pool, even after they're released
        self.assertFalse(u2.claim_username("superbob", clock))

        # Note that the original owner can't even have it back
        self.assertFalse(u1.claim_username("superbob", clock))

        # Still no good at the border of the holding period
        clock.advance(UniqueUsername.HOLDING_PERIOD_DELTA)
        self.assertFalse(u2.claim_username("superbob", clock))

        # OK - now u2 can have it.
        clock.advance_days(1)
        self.assertTrue(u2.claim_username("superbob", clock))
        self.assertEqual("superbob", u2.username)

        db.get([u2.key()])
        self.assertEqual(u2.user_id,
                         UserData.get_from_username("superbob").user_id)
示例#45
0
    def get(self):
        coach = UserData.current()

        if coach is not None:
            coach_email = coach.email
            is_profile_empty = not coach.has_students()
        else:
            coach_email = None
            is_profile_empty = True

        self.render_jinja2_template('coach_resources/view_resources.html', {
            'selected_id': 'coach-resources',
            'coach_email': coach_email,
            'is_profile_empty': is_profile_empty,
        })
    def test_user_identity_consumption(self):
        superman = UserData.insert_for(
                "*****@*****.**",
                email="*****@*****.**",
                username="******",
                password="******",
                gender="male",
                )

        clark = UserData.insert_for(
                "*****@*****.**",
                email="*****@*****.**",
                username=None,
                password=None,
                )

        clark.consume_identity(superman)
        self.assertEqual("*****@*****.**", clark.user_id)
        self.assertEqual("*****@*****.**", clark.email)
        self.assertEqual(clark.key(),
                         UserData.get_from_username("superman").key())
        self.assertEqual(clark.key(),
                         UserData.get_from_user_id("*****@*****.**").key())
        self.assertTrue(clark.validate_password("Password1"))
示例#47
0
    def get(self):
        coach = UserData.current()

        if coach is not None:
            coach_email = coach.email
            is_profile_empty = not coach.has_students()
        else:
            coach_email = None
            is_profile_empty = True

        self.render_jinja2_template(
            'coach_resources/view_resources.html', {
                'selected_id': 'coach-resources',
                'coach_email': coach_email,
                'is_profile_empty': is_profile_empty,
            })
示例#48
0
    def get(self):
        user_data = UserData.current()

        from exercises.exercise_util import exercise_graph_dict_json

        context = {
            'graph_dict_data': exercise_graph_dict_json(user_data),
            'user_data': user_data,
            'map_coords':
            json.dumps(deserializeMapCoords(user_data.map_coords)),

            # Get pregenerated library content from our in-memory/memcache
            # two-layer cache
            'library_content': library_content_html(),
        }
        self.render_jinja2_template("goals/creategoal.html", context)
示例#49
0
    def post(self):
        user_data = UserData.current()

        user_data_student = self.request_student_user_data()
        if user_data_student:
            if not user_data_student.is_coached_by(user_data):
                coach_request = CoachRequest.get_or_insert_for(user_data, user_data_student)
                if coach_request:
                    if not self.is_ajax_request():
                        self.redirect("/students")
                    return

        if self.is_ajax_request():
            self.response.set_status(404)
        else:
            self.redirect("/students?invalid_student=1")
示例#50
0
    def get(self):
        user_data = UserData.current()
        sort = self.request_int("sort",
                                default=VotingSortOrder.HighestPointsFirst)

        if user_data:
            user_data.question_sort_order = sort
            user_data.put()

        readable_id = self.request_string("readable_id", default="")
        topic_title = self.request_string("topic_title", default="")

        if readable_id and topic_title:
            self.redirect("/video/%s?topic=%s&sort=%s" % (
                urllib.quote(readable_id), urllib.quote(topic_title), sort))
        else:
            self.redirect("/")
示例#51
0
    def get(self):
        user_data = UserData.current()
        sort = self.request_int("sort",
                                default=VotingSortOrder.HighestPointsFirst)

        if user_data:
            user_data.question_sort_order = sort
            user_data.put()

        readable_id = self.request_string("readable_id", default="")
        topic_title = self.request_string("topic_title", default="")

        if readable_id and topic_title:
            self.redirect("/video/%s?topic=%s&sort=%s" % (
                urllib.quote(readable_id), urllib.quote(topic_title), sort))
        else:
            self.redirect("/")
示例#52
0
    def get(self):
        template_values = {}
        user_data = UserData.current()

        if user_data is not None:
            template_values = self.authenticated_response()
            if template_values is None:
                self.redirect("/summer/application")
                return

        else:
            template_values = {
                "authenticated" : False,
            }

        self.add_global_template_values(template_values)
        self.render_jinja2_template('summer/summer_status.html', template_values)
示例#53
0
def update_scratchpad(scratchpad_id):
    """Update a pre-existing Scratchpad and create a new ScratchpadRevision.

    The POST data should be a JSON-encoded dict, which is passsed verbatim to
    Scratchpad.update as keyword arguments.
    """
    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    if not request.json:
        return api_invalid_param_response("Bad data supplied: Not JSON")

    user = UserData.current()
    scratchpad = scratchpad_models.Scratchpad.get_by_id(scratchpad_id)

    if not scratchpad or scratchpad.deleted:
        return api_not_found_response("No scratchpad with id %s" %
                                      scratchpad_id)

    if not user.developer:
        # Certain fields are only modifiable by developers
        for field in scratchpad_models.Scratchpad._developer_only_fields:
            if request.json.get(field):
                return api_forbidden_response(
                    "Forbidden: Only developers can change the %s" % field)

    # The user can update the scratchpad if any of the following are true:
    #  1. The scratchpad is tutorial/official and the user is a developer
    #  2. The scratchpad was created by the user
    if scratchpad.category in ("tutorial", "official") and user.developer:
        pass
    elif scratchpad.user_id != user.user_id:
        # Only the creator of a scratchpad can update it
        return api_forbidden_response(
            "Forbidden: Scratchpad owned by different user")

    try:
        # Convert unicode encoded JSON keys to strings
        update_args = dict_keys_to_strings(request.json)
        if 'id' in update_args:
            # Backbone passes the id in update calls - ignore it
            del update_args['id']
        return scratchpad.update(**update_args)
    except (db.BadValueError, db.BadKeyError), e:
        return api_invalid_param_response("Bad data supplied: " + e.message)
示例#54
0
def update_scratchpad(scratchpad_id):
    """Update a pre-existing Scratchpad and create a new ScratchpadRevision.

    The POST data should be a JSON-encoded dict, which is passsed verbatim to
    Scratchpad.update as keyword arguments.
    """
    if not gandalf.bridge.gandalf("scratchpads"):
        return api_forbidden_response(
            "Forbidden: You don't have permission to do this")

    if not request.json:
        return api_invalid_param_response("Bad data supplied: Not JSON")

    user = UserData.current()
    scratchpad = scratchpad_models.Scratchpad.get_by_id(scratchpad_id)

    if not scratchpad or scratchpad.deleted:
        return api_not_found_response(
            "No scratchpad with id %s" % scratchpad_id)

    if not user.developer:
        # Certain fields are only modifiable by developers
        for field in scratchpad_models.Scratchpad._developer_only_fields:
            if request.json.get(field):
                return api_forbidden_response(
                    "Forbidden: Only developers can change the %s" % field)

    # The user can update the scratchpad if any of the following are true:
    #  1. The scratchpad is tutorial/official and the user is a developer
    #  2. The scratchpad was created by the user
    if scratchpad.category in ("tutorial", "official") and user.developer:
        pass
    elif scratchpad.user_id != user.user_id:
        # Only the creator of a scratchpad can update it
        return api_forbidden_response(
            "Forbidden: Scratchpad owned by different user")

    try:
        # Convert unicode encoded JSON keys to strings
        update_args = dict_keys_to_strings(request.json)
        if 'id' in update_args:
            # Backbone passes the id in update calls - ignore it
            del update_args['id']
        return scratchpad.update(**update_args)
    except (db.BadValueError, db.BadKeyError), e:
        return api_invalid_param_response("Bad data supplied: " + e.message)
示例#55
0
    def award_author_badges(self, entity):

        user_data_author = UserData.get_from_db_key_email(entity.author.email())

        if not user_data_author:
            return

        possible_badges = badges_with_context_type(BadgeContextType.FEEDBACK)

        awarded = False
        for badge in possible_badges:
            if not badge.is_already_owned_by(user_data=user_data_author, feedback=entity):
                if badge.is_satisfied_by(user_data=user_data_author, feedback=entity):
                    badge.award_to(user_data=user_data_author, feedback=entity)
                    awarded = True

        if awarded:
            user_data_author.put()
示例#56
0
    def authenticated_response(self):
        user_data = UserData.current()
        user_email = user_data.user_email
        nickname = ""
        if facebook_util.is_facebook_user_id(user_email):
            nickname = facebook_util.get_facebook_nickname(user_email)

        query = SummerStudent.all()
        query.filter('email = ', user_email)
        student = query.get()

        students = []
        is_parent = False

        if student is None:
            query = SummerParentData.all()
            query.filter('email = ', user_email)
            parent = query.get()
            if parent is None:
                return None

            is_parent = True
            number_of_students = 0
            for student_key in parent.students:
                student = SummerStudent.get(student_key)
                students.append(student)
                if student.accepted and not student.tuition_paid:
                    number_of_students += 1

        else:
            number_of_students = 1
            students.append(student)

        template_values = {
            "authenticated" : True,
            "is_parent" : is_parent,
            "students" : students,
            "number_of_students": json.dumps(number_of_students),
            "student" : students[0],
            "user_email" : user_email,
            "nickname" : nickname,
        }

        return template_values