def put(self, id=None): if id is None: # Somebody called PUT /api/<collection> which we don't support. return self.http_method_not_allowed('GET, HEAD, POST') id = self.model.get_long_uid(id) if not owns(self.get_current_user(), id): return self.http_forbidden() force = self.request.get('force', None) == 'true' # from query str params = self.get_params(self.model.property_types()) # json body # Don't allow any changes to response privacy. params.pop('private', None) try: entity = Response.update_or_conflict(id, params, force) except ResponseNotFound: return self.http_not_found() except JsonTextValueLengthError: return self.http_payload_too_large("Value too long.") except JsonTextDictLengthError: return self.http_payload_too_large("Body has too many keys.") except ResponseBodyKeyConflict as e: return self.http_conflict({ 'message': ("Keys conflict: {}. Repeat with ?force=true to override.". format(', '.join(e.args[0]))), 'keys': e.args[0], }) self.write(entity)
def set_up(self): # Let ConsistencyTestCase set up the datastore testing stub. super(TestApiResponses, self).set_up() application = webapp2.WSGIApplication(api_routes, config={ 'webapp2_extras.sessions': { 'secret_key': self.cookie_key } }, debug=True) self.testapp = webtest.TestApp(application) with mysql_connection.connect() as sql: sql.reset({ 'classroom': Classroom.get_table_definition(), 'cycle': Cycle.get_table_definition(), 'organization': Organization.get_table_definition(), 'program': Program.get_table_definition(), 'response': Response.get_table_definition(), 'team': Team.get_table_definition(), 'user': User.get_table_definition(), }) self.program = Program.create( name="Engagement Project", label='ep18', min_cycles=3, active=True, preview_url='foo.com', ) self.program.put()
def test_update_force(self): """Force flag is set, override conflicts and save.""" other, teammate, team, cycles, responses = self.create() # Value is changed and timestamp is old response_id = responses['team_team'].uid now = datetime.datetime.now().strftime(config.iso_datetime_format) old_time = '2000-01-01T00:00:00Z' body = { # based on stale data, but will be accepted anyway 'question': { 'value': 'bar', 'modified': old_time }, # this should be accepted also 'question_new': { 'value': 'foo', 'modified': old_time }, } self.testapp.put_json( '/api/responses/{}?force=true'.format(response_id), {'body': body}, headers=jwt_headers(teammate), ) fetched = Response.get_by_id(response_id) for k, info in body.items(): self.assertIn(k, fetched.body) self.assertEqual(info['value'], fetched.body[k]['value']) self.assertTrue(fetched.body[k]['modified'] >= now)
def test_update_with_conflicts(self): other, teammate, team, cycles, responses = self.create() # Value is changed and timestamp is old response_id = responses['team_team'].uid self.testapp.put_json( '/api/responses/{}'.format(response_id), { 'body': { # based on stale data 'question': { 'value': 'bar', 'modified': '2000-01-01T00:00:00Z', }, # this should be ignored b/c of above 'question_new': { 'value': 'foo', 'modified': '2000-01-01T00:00:00Z', }, }, }, headers=jwt_headers(teammate), status=409, ) fetched = Response.get_by_id(response_id) # Whole update is rejected, body unchanged. self.assertEqual(responses['team_team'].body, fetched.body)
def album_song(): album = request.form['album'] tracks = music_player.album_content(album) resp = Response(type=response_type['track'], status=1, message='', contents=tracks).to_dict() return jsonify(resp)
def test_update_simple(self): """Check ownership-based update permission, no conflicts.""" other, teammate, team, cycles, responses = self.create() new_body = self.default_body() new_body['question']['value'] = 'change' # Forbidden to update other people's responses. self.testapp.put_json( '/api/responses/{}'.format(responses['user_team_other'].uid), {'body': new_body}, headers=jwt_headers(teammate), status=403, ) # Successful to update your own. self.testapp.put_json( '/api/responses/{}'.format(responses['user_team_user1'].uid), {'body': new_body}, headers=jwt_headers(teammate), ) self.assertTrue( self.body_values_match( Response.get_by_id(responses['user_team_user1'].uid).body, new_body, )) # Forbidden to update other teams. self.testapp.put_json( '/api/responses/{}'.format(responses['team_other'].uid), {'body': new_body}, headers=jwt_headers(teammate), status=403, ) # Successful to update team-level. self.testapp.put_json( '/api/responses/{}'.format(responses['team_team'].uid), {'body': new_body}, headers=jwt_headers(teammate), ) self.assertTrue( self.body_values_match( Response.get_by_id(responses['team_team'].uid).body, new_body, ))
def movie_trailer(): movie_name = request.form['movie'] year = request.form['year'] video_info = video_service.youtube_search(movie_name, year)[0] resp = Response(type=response_type['video'], status=1, message='Here is the trailer of ' + movie_name, contents=video_info).to_dict() return jsonify(resp)
def artist_top_tracks(): artist_name = request.form['artist'] top_tracks = music_player.artist_top_tracks(artist_name) resp = Response(type=response_type['track'], status=1, message='Here is ' + artist_name + ' most heat tracks. Choose one or loop the these songs', contents=top_tracks).to_dict() return jsonify(resp)
def playlist(): playlists = music_player.show_playlist() resp = Response( type=response_type['playlist'], status=1, message= 'Here is all your own playlists, you can select one of them to play.', contents=playlists).to_dict() return jsonify(resp)
def artist_album(): artist_name = request.form['artist'] album = music_player.show_artist_albums(artist_name) resp = Response(type=response_type['playlist'], status=1, message='Here is ' + artist_name + "'s albums. Pick one that interests you", contents=album).to_dict() return jsonify(resp)
def test_dashboard(self): org = Organization.create( name='Org Foo', program_id=self.program.uid, ) org.put() org_admin = User.create( name='Org Admin', email='*****@*****.**', owned_organizations=[org.uid], ) org_admin.put() zipped = [] for x in range(5): zipped.append(self.create_for_dashboard(org, x)) teams, users, cycles, responses = zip(*zipped) Team.put_multi(teams) User.put_multi(users) Cycle.put_multi(cycles) Response.put_multi(responses) raw_result = self.testapp.get( '/api/organization_dashboards/{}'.format(org.uid), headers=self.login_headers(org_admin), ) result = json.loads(raw_result.body) # Expected ids. team_ids = set(t.uid for t in teams) user_ids = set(u.uid for u in users) cycle_ids = set(c.uid for c in cycles) response_ids = set(r.uid for r in responses) # All ids present. self.assertEqual(set(t['uid'] for t in result['teams']), team_ids) self.assertEqual(set(u['uid'] for u in result['users']), user_ids) self.assertEqual(set(c['uid'] for c in result['cycles']), cycle_ids) self.assertEqual(set(r['uid'] for r in result['responses']), response_ids) # Responses have no body. self.assertTrue(all(len(r['body']) == 0 for r in result['responses']))
def team_module_response(self, cycle, module_label, progress=100): return Response.create( type=Response.TEAM_LEVEL_SYMBOL, user_id="", team_id=cycle.team_id, parent_id=cycle.uid, module_label=module_label, progress=progress, body={}, )
def add_to_responses(response, timestamp, user_id, text_id): """Adds response associated with text to responses table.""" response = Response(response=response, timestamp=timestamp, user_id=user_id, text_id=text_id) db.session.add(response) db.session.commit()
def result(subject_id): username = request.get_cookie("username") print(username) subject = Subject.get(Subject.id == subject_id) user = User.get(User.id == int(username)) responses = Response.select().where(Response.user == user, Response.subject_code == subject) result = Result.get(Result.username == user, Result.subject_code == subject) return {"result": result, "subject": subject, "responses": responses}
def post(self): # Anyone is allowed to post responses. params = self.get_params(Response.property_types()) user = self.get_current_user() if 'user_id' not in params: params['user_id'] = user.uid required_params = ('team_id', 'parent_id', 'module_label') for k in required_params: if not params.get(k, None): return self.http_bad_request("{} required.".format(k)) # Validate the parent, if it's a cycle. parent_id = params.get('parent_id', None) parent_kind = SqlModel.get_kind(parent_id) if parent_kind == 'Cycle': cycle = SqlModel.kind_to_class(parent_kind).get_by_id(parent_id) if not cycle or not owns(user, parent_id): return self.http_forbidden("Must own the parent to respond.") # ...else this is a step label, so allow any truthy string. # Permission to create varies by type/level. params['type'] = params.get('type', Response.USER_LEVEL_SYMBOL) if params['type'] == Response.TEAM_LEVEL_SYMBOL: if not owns(user, params['team_id']): return self.http_forbidden("Must own the team to respond.") elif not owns(user, params['user_id']): return self.http_forbidden("May not create responses for others.") try: new_entity = Response.insert_or_conflict(params) except ResponseIndexConflict: return self.http_conflict( "Response for this type-user-team-parent-module combination " "exists. Send a request like `PUT /api/responses/:id`.") except JsonTextValueLengthError: return self.http_payload_too_large("Value too long.") except JsonTextDictLengthError: return self.http_payload_too_large("Body has too many keys.") self.write(new_entity)
def add_poll_to_db(): """Adds poll form data to database""" # get data from form prompt = request.form.get('prompt') poll_type = int(request.form.get('poll_type')) is_results_visible = bool(request.form.get('is_results_visible')) title = prompt # create and add objects to db if current_user.is_authenticated: user = current_user else: user = User() poll = Poll(poll_type_id=poll_type, title=title, prompt=prompt, is_results_visible=is_results_visible) PollAdmin(poll_id=poll.poll_id, user_id=user.user_id) # TODO: send poll creation email to user # email = request.form.get('email') # if not open-ended, create Response objects if not poll.poll_type.collect_response: # parse responses from form responses = request.form.get('responses') responses = responses.split('\n') for response in responses: response = Response(poll_id=poll.poll_id, user_id=user.user_id, text=response.strip(), weight=responses.index(response) + 1) db.session.add(response) db.session.commit() # only commit once all Responses are added route = '/' + poll.short_code return redirect(route)
def playlist_detail(): playlist_id = request.form['playlist_id'] playlist_type = int(request.form['playlist_type']) if playlist_type == response_type['album']: tracks = music_player.album_content(playlist_id) elif playlist_type == response_type['playlist']: tracks = music_player.playlist_track(playlist_id) resp = Response(type=response_type['track'], status=1, message='', contents=tracks).to_dict() return jsonify(resp)
def has_completed_exit_survey(self, user, team_id): [response] = Response.get( user_id=user.uid, team_id=team_id, module_label='EPExitSurvey', progress=100, ) or [None] if response: return True return False
def get_info_from_omdb(): mn = request.form['movie'] type = request.form['type'] year = request.form['year'] data = movie_info.get_movie_info(mn, year) contents = {'type': type, 'movie': data} recommend_movie.init_feedback(mn, int(year)) resp = Response(type=response_type['movie_info'], status=1, message=mn, contents=contents).to_dict() return jsonify(resp)
def process_input_text(text, min_prob=0.9): """Identify language and suggest correction in case of misspellings Takes input text and minimum desired probability for language detection :return detected language, probability, suggestion and similarity """ lang, prob = detect_language(text, min_prob) d = map_language_to_dict(lang) suggestion, similarity = spellcheck(text, d) result = Response(Language(lang, prob), SpellCheck(suggestion, similarity)) return result
def from_requests_response(self, url, response): return Response( url=url, status_code=response.status_code, headers=dict([(key, value) for key, value in response.headers.items()]), cookies=dict([(key, value) for key, value in response.cookies.items()]), text=response.text, effective_url=response.url, error=response.status_code > 399 and response.text or None, request_time=response.elapsed and response.elapsed.total_seconds or 0)
def test_update_creates_task(self): # **Don't** use .put() here, because responses are saved with a # custom transaction via insert_or_conflict() and update_or_conflict(). user_response_params = dict( self.response_params, type=Response.USER_LEVEL_SYMBOL, private=True, user_id='User_foo', ) r = Response.create(**user_response_params) r.put() # Creates one task. # Modifying should create a (second) task. new_params = dict(user_response_params, progress = 100) updated = Response.update_or_conflict(r.uid, new_params, False) expected_payload = json.dumps( updated.to_dict(), default=util.json_dumps_default, ) tasks = self.taskqueue_stub.get_filtered_tasks() self.assertEqual(len(tasks), 2) self.assertEqual(tasks[1].payload, expected_payload)
def sub2(subject_id): username = request.get_cookie("username") subject = Subject.get(Subject.id == subject_id) user = User.get(User.id == int(username)) print(user) result = Result.select().where(Result.username == int(username)) if (len(result) != 0) and (result[0].is_taken == True): return redirect("/result") for question in Question.filter(Question.subject_code == subject): res = request.forms.get(f"question-{question.id}") response = Response(qid=question.id, subject_code=subject_id, user=user, response=res) response.save() try: result = Result.get(Result.username == user, Result.subject_code == subject) except: result = Result(username=user, subject_code=subject, is_taken=True) if int(res) == question.right_option: result.marks_obtained += 1 if result.marks_obtained == 20: result.grade = "A" result.state = "Outstanding!" elif result.marks_obtained > 13: result.grade = "B" result.state = "Good!" elif result.marks_obtained > 7: result.grade = "C" result.state = "Average!" else: result.grade = "D" result.state = "Poor!" else: result.marks_obtained += 0 result.save() subject = subject.select()[0] return redirect("/choosesub")
def test_atomic_updates(self): """Not exactly a test; more of a proof of concept that mysql row locking works.""" r = Response.create( user_id='User_foo', team_id='Team_foo', parent_id='Cycle_foo', module_label='ModuleFoo', body={'foo': 'bar'}, progress=0, ) r.put() table = 'response' with mysql_connection.connect(retry_on_error=False) as sql: # This simulates one user clicking "submit" to a module. sql.select_row_for_update(table, 'uid', r.uid) # locks with self.assertRaises(MySQLdb.OperationalError): with mysql_connection.connect(retry_on_error=False) as sql: # This default to 50, which is too long to wait. sql.query('SET innodb_lock_wait_timeout = 1', tuple()) # This simulates another user clicking submit on their # client at the exact same time, which if it weren't for the # lock would be a race condition. Here it should just wait, # and then reach the timeout and raise. sql.update_row(table, 'uid', r.uid, progress=1) # Unfortunately exiting here will close _both_ connections, # so we'll have to let that happen and open a third. # If lock succeeded, the data should be unchanged. fetched = Response.get_by_id(r.uid) self.assertEqual(fetched.progress, 0)
def set_up(self): # Let ConsistencyTestCase set up the datastore testing stub. super(TestTasks, self).set_up() with mysql_connection.connect() as sql: sql.reset({ 'classroom': Classroom.get_table_definition(), 'cycle': Cycle.get_table_definition(), 'metric': Metric.get_table_definition(), 'program': Program.get_table_definition(), 'response': Response.get_table_definition(), 'survey': Survey.get_table_definition(), 'team': Team.get_table_definition(), 'user': User.get_table_definition(), })
def process_contact(): """Show contact form.""" email = request.form.get("email") fname = request.form.get("fname") lname = request.form.get("lname") phone = request.form.get("phone") role = request.form.get("role") interested_in = request.form.get("interested_in") is_beta_tester = request.form.get("beta_tester") is_subscriber = request.form.get("newsletter") response = request.form.get("response") user = User.query.filter_by(email=email).first() if not user: user = User(fname=fname, lname=lname, email=email, phone=phone, role=role, is_beta_tester=is_beta_tester, is_subscriber=is_subscriber, entered_at=datetime.now()) db.session.add(user) db.session.commit() else: if newsletter and user.newsletter != newsletter: user.newsletter = newsletter if beta_tester and beta_tester != beta_tester: user.beta_tester = beta_tester if role and user.role != role: user.role = role if fname and user.fname != fname: user.fname = fname if lname and user.lname != lname: user.lname = lname db.session.commit() if interested_in or response: new_response = Response(user_id=user.user_id, type_response=interested_in, response=response, entered_at=datetime.now()) db.session.add(new_response) db.session.commit() return render_template("contact.html")
def set_up(self): # Let ConsistencyTestCase set up the datastore testing stub. super(TestResponses, self).set_up() with mysql_connection.connect() as sql: sql.reset({ 'response': Response.get_table_definition(), 'response_backup': ResponseBackup.get_table_definition(), 'user': User.get_table_definition(), }) application = webapp2.WSGIApplication(task_routes) self.testapp = webtest.TestApp(application) self.taskqueue_stub = self.testbed.get_stub( testbed.TASKQUEUE_SERVICE_NAME)
def load_responses(combined_pairs): """Loads responses into db.""" i = 1 for pair in combined_pairs: response = Response(response=pair, timestamp=response_times[i], user_id=1, text_id=i) db.session.add(response) response_times[i], i i += 1 db.session.commit()
def test_update_privacy_ignored(self): other, teammate, team, cycles, responses = self.create() # Starts private. to_update = responses['user_team_user1'] self.assertTrue(to_update.private) # Try to make it non-private. self.testapp.put_json( '/api/responses/{}'.format(to_update.uid), dict(to_update.to_client_dict(), private=False), headers=jwt_headers(teammate), ) # Privacy unchanged. fetched = Response.get_by_id(to_update.uid) self.assertEqual(to_update.private, fetched.private)
def load_responses(): """Load response data into database.""" print("* Loading responses") for row in open("response.data"): row = row.rstrip() response_id, name, description = row.split('|') response = Response(response_id=response_id, name=name, description=description) db.session.add(response) db.session.commit() print("* Responses loaded")