def test_cant_have_multiple_parent_accounts(self): parent = self.make_user("*****@*****.**") parent2 = self.make_user("*****@*****.**") child = self.make_child_account(parent, "child") with mock.patch("logging.error") as errorlog: # Going to fail because the child already has a parent. self.assertFalse(ParentChildPair.make_bond(parent2, child)) self.assertEquals(1, errorlog.call_count) self.assertTrue(ParentChildPair.is_pair(parent, child)) self.assertFalse(ParentChildPair.is_pair(parent2, child))
def test_basic_bond(self): parent = self.make_user("*****@*****.**") child = self.make_child_account(parent, "child") retrieved_bonds = ParentChildPair.get_for_parent(parent) self.assertEquals(1, len(retrieved_bonds.fetch(1000))) self.assertEquals(child.key(), retrieved_bonds[0].resolve_child().key()) retrieved_parent_bond = ParentChildPair.get_for_child(child) self.assertEquals(parent.key(), retrieved_parent_bond.resolve_parent().key())
def get(self, username=None, subpath=None): """Render a student profile. Keyword arguments: email_or_username -- matches the first grouping in /profile/(.+?)/(.*) subpath -- matches the second grouping, and is ignored server-side, but is used to route client-side """ current_user_data = UserData.current() or UserData.pre_phantom() if current_user_data.is_pre_phantom and username is None: # Pre-phantom users don't have any profiles - just redirect them # to the homepage if they try to view their own. self.redirect(url_util.create_login_url(self.request.uri)) return if not current_user_data.is_phantom and username == 'nouser': # If anybody has bookmarked, or gets redirected to, or otherwise # finds their way to /profile/nouser while they're logged in, just # redirect them to their actual profile. # # /profile/nouser is only sensible for phantom users and is never # used to look at another user's profile. self.redirect(current_user_data.profile_root) return if not username: user_data = current_user_data elif username == 'nouser' and current_user_data.is_phantom: user_data = current_user_data else: user_data = UserData.get_from_url_segment(username) if (user_models.UniqueUsername.is_valid_username(username) and user_data and user_data.username and user_data.username != username): # The path segment is a username and resolved to the user, # but is not actually their canonical name. Redirect to the # canonical version. if subpath: self.redirect("/profile/%s/%s" % (user_data.username, subpath)) else: self.redirect("/profile/%s" % user_data.username) return profile = util_profile.UserProfile.from_user(user_data, current_user_data) if profile is None: self.render_jinja2_template('noprofile.html', {}) return is_self = user_data.user_id == current_user_data.user_id show_intro = False show_discussion_intro = False if is_self: promo_record = promo_record_model.PromoRecord.get_for_values( "New Profile Promo", user_data.user_id) if promo_record is None: # The user has never seen the new profile page! Show a tour. if subpath: # But if they're not on the root profile page, force them. self.redirect("/profile") return show_intro = True promo_record_model.PromoRecord.record_promo( "New Profile Promo", user_data.user_id, skip_check=True) # We also mark the "new discussion promo" as having been seen, # because it is a sub-set of the full tour, and new users don't # need to see it twice. promo_record_model.PromoRecord.record_promo( "New Discussion Promo", user_data.user_id, skip_check=True) else: # The user has already seen the original profile page tour, but # not necessarily the "new discussion tab" tour. discussion_promo_record = ( promo_record_model.PromoRecord.get_for_values( "New Discussion Promo", user_data.user_id)) if discussion_promo_record is None: # The user hasn't seen the new discussion promo. show_discussion_intro = True promo_record_model.PromoRecord.record_promo( "New Discussion Promo", user_data.user_id, skip_check=True) # This is the main capability bit - it indicates whether or not the # actor can view exercise, video, and goals data on the site for the # current profile. is_activity_visible = user_data.is_visible_to(current_user_data) # Resolve any other miscellaneous capabilities. This may need to be # changed if ACLing gets signicantly more complicated. if is_self: is_settings_available = not user_data.is_child_account() is_discussion_available = not user_data.is_child_account() is_coach_list_readable = True is_coach_list_writable = user_data.can_modify_coaches() else: is_actor_parent = ParentChildPair.is_pair( parent_user_data=current_user_data, child_user_data=user_data) is_settings_available = is_actor_parent is_discussion_available = (is_activity_visible and not user_data.is_child_account()) is_coach_list_readable = is_actor_parent is_coach_list_writable = False tz_offset = self.request_int("tz_offset", default=0) # If profile is public and / or activity is visible, # include all the relevant data. if profile.is_public or is_activity_visible: template_values = { 'show_intro': show_intro, 'show_discussion_intro': show_discussion_intro, 'profile': profile, 'tz_offset': tz_offset, 'count_videos': setting_model.Setting.count_videos(), 'count_exercises': exercise_models.Exercise.get_count(), 'user_data_student': user_data if is_activity_visible else None, 'profile_root': user_data.profile_root, 'is_settings_available': is_settings_available, 'is_coach_list_readable': is_coach_list_readable, 'is_coach_list_writable': is_coach_list_writable, 'is_discussion_available': is_discussion_available, 'view': self.request_string("view", default=""), } # For private profiles else: template_values = { 'profile': profile, 'profile_root': profile.profile_root, 'user_data_student': None, 'count_videos': 0, 'count_exercises': 0 } self.render_jinja2_template('viewprofile.html', template_values)
def test_invalid_bonds(self): too_old = self.make_user("*****@*****.**") parent = self.make_user("*****@*****.**") with mock.patch("logging.error") as errorlog: self.assertFalse(ParentChildPair.make_bond(parent, too_old)) self.assertEquals(1, errorlog.call_count)