def fill_class_summaries_from_logs(user_data_coach, students_data, dt_start_utc): dt_end_utc = dt_start_utc + datetime.timedelta(days = 1) # Asynchronously grab all student data at once async_queries = [] for user_data_student in students_data: query_problem_logs = ProblemLog.get_for_user_data_between_dts(user_data_student, dt_start_utc, dt_end_utc) query_video_logs = VideoLog.get_for_user_data_between_dts(user_data_student, dt_start_utc, dt_end_utc) async_queries.append(query_problem_logs) async_queries.append(query_video_logs) # Wait for all queries to finish results = util.async_queries(async_queries, limit=10000) for i, user_data_student in enumerate(students_data): logging.info("working on student "+str(user_data_student.user)) problem_and_video_logs = [] problem_logs = results[i * 2].get_result() video_logs = results[i * 2 + 1].get_result() for problem_log in problem_logs: problem_and_video_logs.append(problem_log) for video_log in video_logs: problem_and_video_logs.append(video_log) problem_and_video_logs = sorted(problem_and_video_logs, key=lambda log: log.time_started()) if problem_and_video_logs: LogSummary.add_or_update_entry(user_data_coach, problem_and_video_logs, ClassDailyActivitySummary, LogSummaryTypes.CLASS_DAILY_ACTIVITY, 1440)
def get_classtime_table(self, student_emails, dt_start_utc): dt_start_ctz = self.dt_to_ctz(dt_start_utc) dt_end_ctz = dt_start_ctz + datetime.timedelta(days=1) column = 0 classtime_table = ClassTimeTable(dt_start_ctz, dt_end_ctz) for student_email in student_emails: student = users.User(email=student_email) problem_logs = ProblemLog.get_for_user_between_dts( student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) video_logs = VideoLog.get_for_user_between_dts( student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) problem_and_video_logs = [] for problem_log in problem_logs: problem_and_video_logs.append(problem_log) for video_log in video_logs: problem_and_video_logs.append(video_log) problem_and_video_logs = sorted(problem_and_video_logs, key=lambda log: log.time_started()) chunk_current = None for activity in problem_and_video_logs: if chunk_current is not None and self.dt_to_ctz( activity.time_started()) > (chunk_current.end + self.chunk_delta): classtime_table.drop_into_column(chunk_current, column) chunk_current.description() chunk_current = None if chunk_current is None: chunk_current = ClassTimeChunk() chunk_current.student = student chunk_current.start = self.dt_to_ctz( activity.time_started()) chunk_current.end = self.dt_to_ctz(activity.time_ended()) chunk_current.activities.append(activity) chunk_current.end = min(self.dt_to_ctz(activity.time_ended()), dt_end_ctz) if chunk_current is not None: classtime_table.drop_into_column(chunk_current, column) chunk_current.description() column += 1 classtime_table.balance() return classtime_table
def save_video_log(request): if "facility_user" not in request.session: return JsonResponse({}) data = simplejson.loads(request.raw_post_data or "{}") videolog = VideoLog() videolog.user = request.session["facility_user"] videolog.youtube_id = data.get("youtube_id", "") old_videolog = videolog.get_existing_instance() or VideoLog() videolog.total_seconds_watched = old_videolog.total_seconds_watched + data.get("seconds_watched", 0) videolog.points = max(old_videolog.points or 0, data.get("points", 0)) or 0 try: videolog.full_clean() videolog.save() return JsonResponse({ "points": videolog.points, "complete": videolog.complete, }) except ValidationError as e: return JsonResponse({"error": "Could not save VideoLog: %s" % e}, status=500)
def get_classtime_table(self, student_emails, dt_start_utc): dt_start_ctz = self.dt_to_ctz(dt_start_utc) dt_end_ctz = dt_start_ctz + datetime.timedelta(days = 1) column = 0 classtime_table = ClassTimeTable(dt_start_ctz, dt_end_ctz) for student_email in student_emails: student = users.User(email=student_email) problem_logs = ProblemLog.get_for_user_between_dts(student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) video_logs = VideoLog.get_for_user_between_dts(student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) problem_and_video_logs = [] for problem_log in problem_logs: problem_and_video_logs.append(problem_log) for video_log in video_logs: problem_and_video_logs.append(video_log) problem_and_video_logs = sorted(problem_and_video_logs, key=lambda log: log.time_started()) chunk_current = None for activity in problem_and_video_logs: if chunk_current is not None and self.dt_to_ctz(activity.time_started()) > (chunk_current.end + self.chunk_delta): classtime_table.drop_into_column(chunk_current, column) chunk_current.description() chunk_current = None if chunk_current is None: chunk_current = ClassTimeChunk() chunk_current.student = student chunk_current.start = self.dt_to_ctz(activity.time_started()) chunk_current.end = self.dt_to_ctz(activity.time_ended()) chunk_current.activities.append(activity) chunk_current.end = min(self.dt_to_ctz(activity.time_ended()), dt_end_ctz) if chunk_current is not None: classtime_table.drop_into_column(chunk_current, column) chunk_current.description() column += 1 classtime_table.balance() return classtime_table
def get(self): user_data = UserData.current() video_points_total = 0 if user_data: video = None key_str = self.request_string("video_key") if key_str: key = db.Key(key_str) app_id = os.environ['APPLICATION_ID'] if key.app() != app_id: new_key = db.Key.from_path(key.kind(), key.id() or key.name(), _app=app_id) logging.warning( "Key '%s' had invalid app_id '%s'. Changed to new key '%s'", str(key), key.app(), str(new_key)) key = new_key video = db.get(key) else: youtube_id = self.request_string("youtube_id") if youtube_id: video = Video.all().filter('youtube_id =', youtube_id).get() if video: # Seconds watched is restricted by both the scrubber's position # and the amount of time spent on the video page # so we know how *much* of each video each student has watched seconds_watched = int( self.request_float("seconds_watched", default=0)) last_second_watched = int( self.request_float("last_second_watched", default=0)) user_video, video_log, video_points_total = VideoLog.add_entry( user_data, video, seconds_watched, last_second_watched) user_points_html = self.render_jinja2_template_to_string( "user_points_only.html", user_points(user_data)) json = simplejson.dumps( { "user_points_html": user_points_html, "video_points": video_points_total }, ensure_ascii=False) self.response.out.write(json)
def get(self): user_data = UserData.current() video_points_total = 0 if user_data: video = None key_str = self.request_string("video_key") if key_str: key = db.Key(key_str) app_id = os.environ['APPLICATION_ID'] if key.app() != app_id: new_key = db.Key.from_path( key.kind(), key.id() or key.name(), _app=app_id) logging.warning("Key '%s' had invalid app_id '%s'. Changed to new key '%s'", str(key), key.app(), str(new_key)) key = new_key video = db.get(key) else: youtube_id = self.request_string("youtube_id") if youtube_id: video = Video.all().filter('youtube_id =', youtube_id).get() if video: # Seconds watched is restricted by both the scrubber's position # and the amount of time spent on the video page # so we know how *much* of each video each student has watched seconds_watched = int(self.request_float("seconds_watched", default=0)) last_second_watched = int(self.request_float("last_second_watched", default=0)) user_video, video_log, video_points_total = VideoLog.add_entry(user_data, video, seconds_watched, last_second_watched) user_points_html = self.render_jinja2_template_to_string("user_points_only.html", user_points(user_data)) json = simplejson.dumps({"user_points_html": user_points_html, "video_points": video_points_total}, ensure_ascii=False) self.response.out.write(json)
def fill_class_summaries_from_logs(user_data_coach, students_data, dt_start_utc): dt_end_utc = dt_start_utc + datetime.timedelta(days=1) # Asynchronously grab all student data at once async_queries = [] for user_data_student in students_data: query_problem_logs = ProblemLog.get_for_user_data_between_dts( user_data_student, dt_start_utc, dt_end_utc) query_video_logs = VideoLog.get_for_user_data_between_dts( user_data_student, dt_start_utc, dt_end_utc) async_queries.append(query_problem_logs) async_queries.append(query_video_logs) # Wait for all queries to finish results = util.async_queries(async_queries, limit=10000) for i, user_data_student in enumerate(students_data): logging.info("working on student " + str(user_data_student.user)) problem_and_video_logs = [] problem_logs = results[i * 2].get_result() video_logs = results[i * 2 + 1].get_result() for problem_log in problem_logs: problem_and_video_logs.append(problem_log) for video_log in video_logs: problem_and_video_logs.append(video_log) problem_and_video_logs = sorted(problem_and_video_logs, key=lambda log: log.time_started()) if problem_and_video_logs: LogSummary.add_or_update_entry( user_data_coach, problem_and_video_logs, ClassDailyActivitySummary, LogSummaryTypes.CLASS_DAILY_ACTIVITY, 1440)
def get(self): from exercises import attempt_problem login_user = UserData.current() exercises_list = [exercise for exercise in Exercise.all()] videos_list = [video for video in Video.all()] user_count = self.request_int('users', 5) for user_id in xrange(0, user_count): # Create a new user first_name = random.choice(CreateRandomGoalData.first_names) last_name = random.choice(CreateRandomGoalData.last_names) nickname = "%s %s" % (first_name, last_name) email = 'test_%i@automatedrandomdata' % user_id user = users.User(email) logging.info("Creating user %s: (%i/%i)" % (nickname, user_id + 1, user_count)) user_data = UserData.get_or_insert( key_name="test_user_%i" % user_id, user=user, current_user=user, user_id=str(user_id), moderator=False, last_login=datetime.now(), proficient_exercises=[], suggested_exercises=[], need_to_reassess=True, points=0, coaches=[login_user.user_email], user_email=email, user_nickname=nickname, ) user_data.put() # Delete user exercise & video progress query = UserExercise.all() query.filter('user = '******'user = '******'type': 'GoalObjectiveExerciseProficiency', 'exercise': random.choice(exercises_list)}) for objective in xrange(1, random.randint(2, 4)): obj_descriptors.append({ 'type': 'GoalObjectiveWatchVideo', 'video': random.choice(videos_list)}) title = first_name + "'s Goal #" + str(goal_idx) logging.info("Creating goal " + title) objectives = GoalObjective.from_descriptors(obj_descriptors, user_data) goal = Goal(parent=user_data, title=title, objectives=objectives) user_data.save_goal(goal) for objective in obj_descriptors: if objective['type'] == 'GoalObjectiveExerciseProficiency': user_exercise = user_data.get_or_insert_exercise( objective['exercise']) chooser = random.randint(1, 120) if chooser >= 60: continue elif chooser > 15: count = 1 hints = 0 elif chooser < 7: count = 20 hints = 0 else: count = 25 hints = 1 logging.info( "Starting exercise: %s (%i problems, %i hints)" % (objective['exercise'].name, count, hints * count)) for i in xrange(1, count): attempt_problem(user_data, user_exercise, i, 1, 'TEST', 'TEST', 'TEST', True, hints, 0, False, "TEST", 'TEST', '0.0.0.0') elif objective['type'] == 'GoalObjectiveWatchVideo': seconds = random.randint(1, 1200) logging.info("Watching %i seconds of video %s" % (seconds, objective['video'].title)) VideoLog.add_entry(user_data, objective['video'], seconds, 0, detect_cheat=False) self.response.out.write('OK')
def save_video_log(request): if "facility_user" not in request.session: return JsonResponse({}) data = simplejson.loads(request.raw_post_data or "{}") videolog = VideoLog() videolog.user = request.session["facility_user"] videolog.youtube_id = data.get("youtube_id", "") old_videolog = videolog.get_existing_instance() or VideoLog() videolog.total_seconds_watched = old_videolog.total_seconds_watched + data.get( "seconds_watched", 0) videolog.points = max(old_videolog.points or 0, data.get("points", 0)) or 0 try: videolog.full_clean() videolog.save() return JsonResponse({ "points": videolog.points, "complete": videolog.complete, }) except ValidationError as e: return JsonResponse({"error": "Could not save VideoLog: %s" % e}, status=500)
def get_classtime_table_old(self, students_data, dt_start_utc): dt_start_ctz = self.dt_to_ctz(dt_start_utc) dt_end_ctz = dt_start_ctz + datetime.timedelta(days=1) column = 0 classtime_table = ClassTimeTable(dt_start_ctz, dt_end_ctz) # Asynchronously grab all student data at once async_queries = [] for user_data_student in students_data: query_problem_logs = ProblemLog.get_for_user_data_between_dts( user_data_student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) query_video_logs = VideoLog.get_for_user_data_between_dts( user_data_student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) async_queries.append(query_problem_logs) async_queries.append(query_video_logs) # Wait for all queries to finish results = util.async_queries(async_queries, limit=10000) rows = 0 chunks = 0 for i, user_data_student in enumerate(students_data): problem_logs = results[i * 2].get_result() video_logs = results[i * 2 + 1].get_result() problem_and_video_logs = [] for problem_log in problem_logs: problem_and_video_logs.append(problem_log) for video_log in video_logs: problem_and_video_logs.append(video_log) problem_and_video_logs = sorted(problem_and_video_logs, key=lambda log: log.time_started()) rows += len(problem_and_video_logs) chunk_current = None for activity in problem_and_video_logs: if chunk_current is not None and self.dt_to_ctz( activity.time_started()) > (chunk_current.end + self.chunk_delta): chunks += 1 classtime_table.drop_into_column_old(chunk_current, column) chunk_current.description() chunk_current = None if chunk_current is None: chunk_current = ClassTimeChunk() chunk_current.user_data_student = user_data_student chunk_current.start = self.dt_to_ctz( activity.time_started()) chunk_current.end = self.dt_to_ctz(activity.time_ended()) chunk_current.activities.append(activity) chunk_current.end = min(self.dt_to_ctz(activity.time_ended()), dt_end_ctz) if chunk_current is not None: chunks += 1 classtime_table.drop_into_column_old(chunk_current, column) chunk_current.description() column += 1 logging.info("old rows=" + str(rows) + ", old chunks=" + str(chunks)) classtime_table.balance() return classtime_table
def get(self): from exercises import attempt_problem login_user = UserData.current() exercises_list = [exercise for exercise in Exercise.all()] videos_list = [video for video in Video.all()] user_count = self.request_int('users', 5) for user_id in xrange(0, user_count): # Create a new user first_name = random.choice(CreateRandomGoalData.first_names) last_name = random.choice(CreateRandomGoalData.last_names) nickname = "%s %s" % (first_name, last_name) email = 'test_%i@automatedrandomdata' % user_id user = users.User(email) logging.info("Creating user %s: (%i/%i)" % (nickname, user_id + 1, user_count)) user_data = UserData.get_or_insert( key_name="test_user_%i" % user_id, user=user, current_user=user, user_id=str(user_id), moderator=False, last_login=datetime.now(), proficient_exercises=[], suggested_exercises=[], need_to_reassess=True, points=0, coaches=[login_user.user_email], user_email=email, user_nickname=nickname, ) user_data.put() # Delete user exercise & video progress query = UserExercise.all() query.filter('user = '******'user = '******'type': 'GoalObjectiveExerciseProficiency', 'exercise': random.choice(exercises_list)}) for objective in xrange(1, random.randint(2, 4)): obj_descriptors.append({ 'type': 'GoalObjectiveWatchVideo', 'video': random.choice(videos_list)}) title = first_name + "'s Goal #" + str(goal_idx) logging.info("Creating goal " + title) objectives = GoalObjective.from_descriptors(obj_descriptors, user_data) goal = Goal(parent=user_data, title=title, objectives=objectives) user_data.save_goal(goal) for objective in obj_descriptors: if objective['type'] == 'GoalObjectiveExerciseProficiency': user_exercise = user_data.get_or_insert_exercise( objective['exercise']) chooser = random.randint(1, 120) if chooser >= 60: continue elif chooser > 15: count = 1 hints = 0 elif chooser < 7: count = 20 hints = 0 else: count = 25 hints = 1 logging.info( "Starting exercise: %s (%i problems, %i hints)" % (objective['exercise'].name, count, hints * count)) for i in xrange(1, count): attempt_problem(user_data, user_exercise, i, 1, 'TEST', 'TEST', 'TEST', True, hints, 0, "TEST", 'TEST', '0.0.0.0') elif objective['type'] == 'GoalObjectiveWatchVideo': seconds = random.randint(1, 1200) logging.info("Watching %i seconds of video %s" % (seconds, objective['video'].title)) VideoLog.add_entry(user_data, objective['video'], seconds, 0, detect_cheat=False) self.response.out.write('OK')
def get(self): if not hasattr(secrets, 'ka_api_consumer_key') or \ not hasattr(secrets, 'ka_api_consumer_secret') or \ not hasattr(secrets_dev, 'ka_api_token_key') or \ not hasattr(secrets_dev, 'ka_api_token_secret'): return self.redirect("/") self.setup_oauth() self.email = self.request_string("email") if not self.email: raise "Must supply email for user to import" params = copy.copy(self._default_kinds) params.update(self.request.params) # get proper user from addition 1 userexercise user_id_json = json.loads( self.api("/api/v1/user/exercises/addition_1")) user = users.User(user_id_json['user']) # UserData user_data_json_raw = self.api("/api/v1/user") user_data = UserData.from_json(json.loads(user_data_json_raw), user=user) self.output('user_data', user_data, user_data_json_raw) user_data.put() if 'UserVideo' in params: user_videos_json = json.loads(self.api("/api/v1/user/videos")) user_videos = [] for user_video_json in user_videos_json[:params['UserVideo']]: user_video = UserVideo.from_json(user_video_json, user_data=user_data) user_videos.append(user_video) self.output('user_video', user_video, jsonify(user_video_json)) video_logs = defaultdict(list) if 'VideoLog' in params: for user_video in user_videos: ytid = user_video.video.youtube_id video_logs_json = json.loads( self.api("/api/v1/user/videos/%s/log" % ytid)) for video_log_json in video_logs_json[:params[ 'ProblemLog']]: video_log = VideoLog.from_json(video_log_json, user_video.video, user) video_logs[user_video].append(video_log) self.output("video_log", video_log, jsonify(video_log_json)) # delete old video logs query = VideoLog.all(keys_only=True) query.filter('user ='******'UserExercise' in params: user_exercises_json = json.loads( self.api("/api/v1/user/exercises")) user_exercises = [] for user_exercise_json in user_exercises_json[:params[ 'UserExercise']]: user_exercise = UserExercise.from_json(user_exercise_json, user_data) if user_exercise: user_exercises.append(user_exercise) self.output("user_exercise", user_exercise, jsonify(user_exercise_json)) problem_logs = defaultdict(list) if 'ProblemLog' in params: for user_exercise in user_exercises: problem_logs_json = json.loads( self.api("/api/v1/user/exercises/%s/log" % user_exercise.exercise)) for problem_log_json in problem_logs_json[:params[ 'ProblemLog']]: problem_log = ProblemLog.from_json( problem_log_json, user_data=user_data, exercise=user_exercise.exercise_model) problem_logs[user_exercise].append(problem_log) self.output("problem_log", problem_log, jsonify(problem_log_json)) db.put(user_exercises) for k, v in problem_logs.iteritems(): db.put(v) if 'Goal' in params: with AutoNowDisabled(Goal): goals_json = json.loads(self.api("/api/v1/user/goals")) goals = [] for goal_json in goals_json[:params['Goal']]: goal = Goal.from_json(goal_json, user_data=user_data) goals.append(goal) self.output("goal", goal, jsonify(goal_json)) db.put(goals) # need to tell the userdata that it has goals user_data.has_current_goals = not all( [g.completed for g in goals]) user_data.put()
def get_classtime_table_old(self, students_data, dt_start_utc): dt_start_ctz = self.dt_to_ctz(dt_start_utc) dt_end_ctz = dt_start_ctz + datetime.timedelta(days = 1) column = 0 classtime_table = ClassTimeTable(dt_start_ctz, dt_end_ctz) # Asynchronously grab all student data at once async_queries = [] for user_data_student in students_data: query_problem_logs = ProblemLog.get_for_user_data_between_dts(user_data_student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) query_video_logs = VideoLog.get_for_user_data_between_dts(user_data_student, self.dt_to_utc(dt_start_ctz), self.dt_to_utc(dt_end_ctz)) async_queries.append(query_problem_logs) async_queries.append(query_video_logs) # Wait for all queries to finish results = util.async_queries(async_queries, limit=10000) rows = 0 chunks = 0 for i, user_data_student in enumerate(students_data): problem_logs = results[i * 2].get_result() video_logs = results[i * 2 + 1].get_result() problem_and_video_logs = [] for problem_log in problem_logs: problem_and_video_logs.append(problem_log) for video_log in video_logs: problem_and_video_logs.append(video_log) problem_and_video_logs = sorted(problem_and_video_logs, key=lambda log: log.time_started()) rows += len(problem_and_video_logs) chunk_current = None for activity in problem_and_video_logs: if chunk_current is not None and self.dt_to_ctz(activity.time_started()) > (chunk_current.end + self.chunk_delta): chunks += 1 classtime_table.drop_into_column_old(chunk_current, column) chunk_current.description() chunk_current = None if chunk_current is None: chunk_current = ClassTimeChunk() chunk_current.user_data_student = user_data_student chunk_current.start = self.dt_to_ctz(activity.time_started()) chunk_current.end = self.dt_to_ctz(activity.time_ended()) chunk_current.activities.append(activity) chunk_current.end = min(self.dt_to_ctz(activity.time_ended()), dt_end_ctz) if chunk_current is not None: chunks += 1 classtime_table.drop_into_column_old(chunk_current, column) chunk_current.description() column += 1 logging.info("old rows="+str(rows)+", old chunks="+str(chunks)) classtime_table.balance() return classtime_table
def get(self): if not hasattr(secrets, 'ka_api_consumer_key') or \ not hasattr(secrets, 'ka_api_consumer_secret') or \ not hasattr(secrets_dev, 'ka_api_token_key') or \ not hasattr(secrets_dev, 'ka_api_token_secret'): return self.redirect("/") self.setup_oauth() self.email = self.request_string("email") if not self.email: raise "Must supply email for user to import" params = copy.copy(self._default_kinds) params.update(self.request.params) # get proper user from addition 1 userexercise user_id_json = json.loads(self.api("/api/v1/user/exercises/addition_1")) user = users.User(user_id_json['user']) # UserData user_data_json_raw = self.api("/api/v1/user") user_data = UserData.from_json(json.loads(user_data_json_raw), user=user) self.output('user_data', user_data, user_data_json_raw) user_data.put() if 'UserVideo' in params: user_videos_json = json.loads(self.api("/api/v1/user/videos")) user_videos = [] for user_video_json in user_videos_json[:params['UserVideo']]: user_video = UserVideo.from_json(user_video_json, user_data=user_data) user_videos.append(user_video) self.output('user_video', user_video, jsonify(user_video_json)) video_logs = defaultdict(list) if 'VideoLog' in params: for user_video in user_videos: ytid = user_video.video.youtube_id video_logs_json = json.loads( self.api("/api/v1/user/videos/%s/log" % ytid)) for video_log_json in video_logs_json[:params['ProblemLog']]: video_log = VideoLog.from_json(video_log_json, user_video.video, user) video_logs[user_video].append(video_log) self.output("video_log", video_log, jsonify(video_log_json)) # delete old video logs query = VideoLog.all(keys_only=True) query.filter('user ='******'UserExercise' in params: user_exercises_json = json.loads(self.api("/api/v1/user/exercises")) user_exercises = [] for user_exercise_json in user_exercises_json[:params['UserExercise']]: user_exercise = UserExercise.from_json(user_exercise_json, user_data) if user_exercise: user_exercises.append(user_exercise) self.output("user_exercise", user_exercise, jsonify(user_exercise_json)) problem_logs = defaultdict(list) if 'ProblemLog' in params: for user_exercise in user_exercises: problem_logs_json = json.loads(self.api( "/api/v1/user/exercises/%s/log" % user_exercise.exercise)) for problem_log_json in problem_logs_json[:params['ProblemLog']]: problem_log = ProblemLog.from_json(problem_log_json, user_data=user_data, exercise=user_exercise.exercise_model) problem_logs[user_exercise].append(problem_log) self.output("problem_log", problem_log, jsonify(problem_log_json)) db.put(user_exercises) for k, v in problem_logs.iteritems(): db.put(v) if 'Goal' in params: with AutoNowDisabled(Goal): goals_json = json.loads(self.api("/api/v1/user/goals")) goals = [] for goal_json in goals_json[:params['Goal']]: goal = Goal.from_json(goal_json, user_data=user_data) goals.append(goal) self.output("goal", goal, jsonify(goal_json)) db.put(goals) # need to tell the userdata that it has goals user_data.has_current_goals = not all([g.completed for g in goals]) user_data.put()