def disable_account_recovery_token(): token_id = request.form['tokenId'] token = database.token.account_recovery.disable(token_id) response = { 'message': 'WebUserResetPasswordToken {id} disabled.'.format(id=token.id) } return Success(status_code=201, headers={'Location': '/account-recovery/deactivate'}, resource_type='DeactivateNewSurveyToken', body=response)
def post(self): survey = database.survey.get(current_identity.survey_id) response = { 'token': database.web_user.create_invite_researcher_token(survey).token } return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body=response)
def get(self): survey = database.survey.get(current_identity.survey_id) response = { 'stations': to_prompts_geojson(survey.subway_stops), 'bufferSize': survey.trip_subway_buffer } return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=response)
def post(self): json_data = json.loads(request.data.decode('utf-8')) data = rename_json_keys(json_data, camelcase_to_underscore) survey_name = data['survey_name'].lower().strip() survey = database.survey.find_by_name(survey_name) if not survey: return Error(status_code=410, headers=self.headers, resource_type=self.resource_type, errors=['Specified survey not found']) user = database.user.create(survey=survey, user_data=data['user']) if user: survey_json = database.survey.formatted_survey_questions(survey) prompts_json = database.survey.formatted_survey_prompts(survey) # supply a default max_prompts value of 0 if no prompts are set instead of None max_prompts = survey.max_prompts if len(prompts_json) > 0 else 0 response = { 'user': '******', 'uuid': data['user']['uuid'], 'contact_email': survey.contact_email, 'default_avatar': get_default_avatar_path(), 'avatar': survey.avatar_uri, 'survey': survey_json, 'prompt': { 'max_days': survey.max_survey_days, 'max_prompts': max_prompts, 'num_prompts': len(prompts_json), 'prompts': prompts_json }, 'lang': survey.language, 'about_text': survey.about_text, 'terms_of_service': survey.terms_of_service, 'survey_name': survey.pretty_name, 'record_acceleration': survey.record_acceleration, 'record_mode': survey.record_mode } # add in deprecation warning for v1 api return Success( status_code=201, headers=self.headers, resource_type=self.resource_type, status= 'Warning (deprecated): API v1 will soon be phased out. Please refer to documentation for v2 calls.', body=rename_json_keys(response, underscore_to_camelcase)) return Error(status_code=400, headers=self.headers, resource_type=self.resource_type, errors=['Could not register new user.'])
def delete(self, email): survey = database.survey.get(current_identity.survey_id) user = survey.web_users.filter_by(email=email).one_or_none() if user: database.web_user.delete(user) return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body={}) return Error(status_code=401, headers=self.headers, resource_type=self.resource_type, errors=['Web user could not be deleted from survey.'])
def get(self): survey = database.survey.get(current_identity.survey_id) prompts = database.prompts.formatted_prompt_questions(survey) response = { 'survey_id': survey.id, 'prompts': prompts, 'started': True if database.survey.get_start_time(survey) else False } return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=make_keys_camelcase(response))
def put(self): email = request.json.get('email') password = request.json.get('password') token = request.json.get('token') user = database.web_user.update_password(email, password, token) if user: return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body={}) return Error(status_code=401, headers=self.headers, resource_type=self.resource_type, errors=[])
def get(self): survey = database.survey.get(current_identity.survey_id) uri = survey.avatar_uri # use default avatar if a custom one is not set if not uri: with current_app.app_context(): uri = '{base}/static/{avatar}'.format( base=current_app.config['ASSETS_ROUTE'], avatar=current_app.config['DEFAULT_AVATAR_FILENAME']) return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body={'avatarUri': uri})
def get(self): survey = database.survey.get(current_identity.survey_id) sort_fields = json.loads(request.values.get('sorting', '{}')) page_index = int(request.values.get('pageIndex')) items_per_page = int(request.values.get('itemsPerPage')) response = database.web_user.paginated_table( survey=survey, page_index=page_index, items_per_page=items_per_page, sort_fields=sort_fields) return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=response)
def post(self): data = json.loads(request.data) survey_name = data['survey_name'].lower() survey = database.survey.find_by_name(survey_name) if not survey: return Error(status_code=400, headers=self.headers, resource_type=self.resource_type, errors=['Specified survey not found']) user = database.user.create(survey=survey, user_data=data['user']) if user: survey_json = database.survey.formatted_survey_questions(survey) prompts_json = database.survey.formatted_survey_prompts(survey) # supply a default max_prompts value of 0 if no prompts are set instead of None max_prompts = survey.max_prompts if len(prompts_json) > 0 else 0 response = { 'survey_id': survey.id, 'user': '******', 'uuid': data['user']['uuid'], 'default_avatar': get_default_avatar_path(), 'avatar': survey.avatar_uri, 'survey': survey_json, 'prompt': { 'max_days': survey.max_survey_days, 'max_prompts': max_prompts, 'num_prompts': len(prompts_json), 'prompts': prompts_json }, 'lang': survey.language, 'about_text': survey.about_text, 'terms_of_service': survey.terms_of_service, 'survey_name': survey.pretty_name, 'record_acceleration': survey.record_acceleration, 'record_mode': survey.record_mode } return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body=make_keys_camelcase(response)) return Error(status_code=400, headers=self.headers, resource_type=self.resource_type, errors=['Could not register new user.'])
def upload_survey_schema_json(): if not request.json.get('surveyName'): return Error(status_code=400, headers={'Location': '/manage-surveys/schema'}, resource_type='NewSurveySchema', errors=['A unique survey name must be provided.']) errors = None if request.json.get('schema'): survey_name = request.json['surveyName'] error = database.survey_admin.create_from_schema( survey_name=survey_name, admin_email=request.json['schema']['adminEmail'], admin_password=request.json['schema']['adminPassword'], language=request.json['schema']['language'], survey_questions=request.json['schema']['surveyQuestions'], survey_prompts=request.json['schema']['surveyPrompts']) if not error: # format the same as jinja2 renders the template response = { 'recent_signups': [], 'message': 'Survey "{}" created.'.format(survey_name) } for survey in database.survey_admin.get_recent_signups(10): response['recent_signups'].append({ 'name': survey.name, 'pretty_name': survey.pretty_name, 'created_at': str(survey.created_at.replace(microsecond=0)), 'active': 'True' if survey.mobile_coordinates.first() else 'False' }) return Success(status_code=201, headers={'Location': '/manage-surveys/schema'}, resource_type='NewSurveySchema', body=response) errors = [error] if not errors: errors = ['New survey schema could not be uploaded.'] return Error(status_code=400, headers={'Location': '/manage-surveys/schema'}, resource_type='NewSurveySchema', errors=errors)
def delete(self): survey = database.survey.get(current_identity.survey_id) if survey.avatar_uri: filehandler.delete(survey.avatar_uri) # reset to default avatar with current_app.app_context(): default_avatar_uri = '{base}/user/{avatar}'.format( base=current_app.config['ASSETS_ROUTE'], avatar=current_app.config['DEFAULT_AVATAR_FILENAME']) survey.avatar_uri = default_avatar_uri database.survey.update(survey) return Success(status_code=202, headers=self.headers, resource_type=self.resource_type, body={'avatarUri': default_avatar_uri})
def get(self): survey = database.survey.get(current_identity.survey_id) response = { 'language': survey.language, 'about_text': survey.about_text, 'terms_of_service': survey.terms_of_service, 'max_days': survey.max_survey_days, 'max_prompts': survey.max_prompts, 'survey': database.survey.get_survey_questions_json(survey), 'survey_id': survey.id, 'started': True if database.survey.get_start_time(survey) else False } return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=make_keys_camelcase(response))
def get(self): survey = database.survey.get(current_identity.survey_id) start = database.survey.get_start_time(survey) response = { 'message': 'Survey has not begun.', 'start_time': None, 'last_export': None } if start: response['message'] = 'Survey has started' response['start_time'] = start.isoformat() response['last_export'] = survey.last_export return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=make_keys_camelcase(response))
def get(self): survey_id = current_identity.survey_id start = ciso8601.parse_datetime(request.values.get('start')) end = ciso8601.parse_datetime(request.values.get('end')) timezone = request.values.get('timezone') sse_channel = request.values.get('channel') # sse.publish({'msg': 'starting exports...', 'type': 'request-ack'}, # channel=sse_channel) mobile_data_dump.queue(survey_id, start, end, timezone, sse_channel) # mobile_data_dump(survey_id, start, end, timezone, sse_channel) response = { 'start': start.isoformat(), 'end': end.isoformat() } return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=response)
def generate_new_survey_token(): database.token.new_survey.create() response = { 'recent_tokens': [], 'message': 'New survey sign-up token successfully created.' } # format the same as jinja2 renders the template for token in database.token.new_survey.get_recent(10): response['recent_tokens'].append({ 'token': token.token, 'created_at': str(token.created_at.replace(microsecond=0)), 'active': str(token.active), 'usages': token.usages }) return Success(status_code=201, headers={'Location': '/signup-tokens/token'}, resource_type='NewSurveyToken', body=response)
def get(self): survey = database.survey.get(current_identity.survey_id) start = request.values.get('start') end = request.values.get('end') period = request.values.get('period') get_counts_overview = request.values.get( 'countsTable').lower() == 'true' response = { 'installationsBarGraph': mobile_installations_bargraph(survey, start, end, period), 'activeUsersLineGraph': active_users_linegraph(survey) } if get_counts_overview is True: response['overview'] = survey_overview(survey) return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=response)
def post(self): email = request.json.get('email') base_url = request.json.get('baseUrl') token = database.web_user.create_reset_password_token(email) if token: email_password_token.queue(current_app.config['MAILGUN_DOMAIN'], current_app.config['MAILGUN_API_KEY'], base_url, email, token.token) # email_password_token(current_app.config['MAILGUN_DOMAIN'], # current_app.config['MAILGUN_API_KEY'], # base_url, email, token.token) return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body={}) return Error(status_code=401, headers=self.headers, resource_type=self.resource_type, errors=['Email not found.'])
def get(self): if current_identity.has_role('admin') or current_identity.has_role('researcher'): survey = database.survey.get(current_identity.survey_id) survey_users = [] users_with_coordinates = (survey.mobile_users.filter( db.exists().where(MobileUser.id == MobileCoordinate.mobile_id))) for user in users_with_coordinates: survey_users.append({ 'uuid': user.uuid, 'created_at': user.created_at.isoformat() }) else: survey_users = [{ 'uuid': current_identity.participant_uuid, 'created_at': current_identity.created_at.isoformat() }] return Success(status_code=200, headers=self.headers, resource_type=self.resource_type, body=survey_users)
def post(self): validations = [{ 'uuid': { 'key': 'uuid', 'validator': value_exists, 'response': Error, 'error': 'UUID must be supplied. No action taken.' }, 'survey_answers': { 'key': 'survey', 'validator': None }, 'coordinates': { 'key': 'coordinates', 'validator': None }, 'prompts_answers': { 'key': 'prompts', 'validator': None }, 'cancelled_prompts': { 'key': 'cancelledPrompts', 'validator': None } }] validated = validate_json(validations, self.headers, self.resource_type) user = database.user.find_by_uuid(validated['uuid']) if user: survey_answers, coordinates, prompts_answers, cancelled_prompts = None, None, None, None response = { 'survey': 'No new survey data supplied.', 'coordinates': 'No new coordinates data supplied.', 'prompts': 'No new prompt answers supplied.', 'cancelledPrompts': 'No cancelled prompts supplied.' } if validated['survey_answers']: survey_answers = database.survey.upsert(user=user, answers=validated['survey_answers']) if survey_answers: response['survey'] = 'Survey answer for {} upserted.'.format(user.uuid) if validated['coordinates']: coordinates = database.coordinates.insert(user=user, coordinates=validated['coordinates']) if coordinates: response['coordinates'] = ( 'New coordinates for {} inserted.'.format(user.uuid)) # upsert prompts answers and remove any existing conflicting cancelled prompt responses if validated['prompts_answers']: prompts_answers = database.prompts.upsert(user=user, prompts=validated['prompts_answers']) prompts_uuids = [p.prompt_uuid for p in prompts_answers] database.cancelled_prompts.delete(prompts_uuids) if prompts_answers: response['prompts'] = ( 'New prompt answers for {} inserted.'.format(user.uuid)) # filter cancelled prompts which conflict with a provided response by uuid and insert cancelled prompts if validated['cancelled_prompts']: if validated['prompts_answers']: answers_uuids = {p['uuid'] for p in validated['prompts_answers']} filtered_cancelled_prompts = [] for c in validated['cancelled_prompts']: if c['uuid'] not in answers_uuids: filtered_cancelled_prompts.append(c) else: filtered_cancelled_prompts = validated['cancelled_prompts'] cancelled_prompts = database.cancelled_prompts.insert(user=user, cancelled_prompts=filtered_cancelled_prompts) if cancelled_prompts: response['cancelledPrompts'] = ( 'New cancelled prompts for {} inserted.'.format(user.uuid)) status = None if any([survey_answers, coordinates, prompts_answers, cancelled_prompts]): database.commit() status = 201 else: status = 200 return Success(status_code=status, headers=self.headers, resource_type=self.resource_type, body=response) return Error(status_code=400, headers=self.headers, resource_type=self.resource_type, errors=['Could not find survey for {}.'.format(validated['uuid'])])
def post(self): validations = [{ 'email': { 'key': 'email', 'validator': value_exists, 'response': Error, 'error': 'Email cannot be blank.', }, 'password': { 'key': 'password', 'validator': value_exists, 'response': Error, 'error': 'Password cannot be blank.', }, 'survey_name': { 'key': 'surveyName', 'validator': value_exists, 'response': Error, 'error': 'Survey name cannot be blank.', } }] validated = validate_json(validations, self.headers, self.resource_type) survey = database.survey.find_by_name(validated['survey_name']) # create a researcher user if a signup token is provided researcherToken = request.json.get('registrationToken', '').strip() if researcherToken: user = database.web_user.create_researcher( survey=survey, email=validated['email'], password=validated['password'], token=researcherToken) if user is False: return Error(status_code=400, headers=self.headers, resource_type=self.resource_type, errors=['Web user already exists for email.']) elif user is None: return Error(status_code=403, headers=self.headers, resource_type=self.resource_type, errors=['Researcher user could not be created.']) else: mobile_user = database.mobile_user.find_by_email( email=validated['email']) if not mobile_user: return Error( status_code=404, headers=self.headers, resource_type=self.resource_type, errors=[ 'Participant email not found in any survey response.' ]) else: user = database.web_user.create_participant( survey, email=validated['email'], password=validated['password'], uuid=mobile_user.uuid) if user is False: return Error( status_code=400, headers=self.headers, resource_type=self.resource_type, errors=['Participant user could not be created.']) return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body=make_keys_camelcase(validated))
def get(self): return Success(status_code=200, headers=self.headers, resource_type='BaseIndex', body=None)
def post(self): validations = [{ 'about_text': { 'key': 'aboutText', 'validator': None, }, 'terms_of_service': { 'key': 'termsOfService', 'validator': None }, 'contact_email': { 'key': 'contactEmail', 'validator': value_exists, 'response': Error, 'error': 'A contact email address must be specified.' }, 'survey_max_days': { 'key': 'surveyMaxDays', 'validator': value_exists, 'response': Error, 'error': 'A maximum number of survey prompt days must be entered.', }, 'survey_max_prompts': { 'key': 'surveyMaxPrompts', 'validator': value_exists, 'response': Error, 'error': 'A maximum number of survey prompts must be entered.', }, 'gps_accuracy_meters': { 'key': 'gpsAccuracyThresholdMeters', 'validator': value_exists, 'response': Error, 'error': 'A minimum GPS accuracy threshold must be specified. (Higher threshold is lower accuracy)' }, 'tripbreaker_interval_seconds': { 'key': 'tripbreakerIntervalSeconds', 'validator': value_exists, 'response': Error, 'error': 'Trip breaking interval must be provided.' }, 'tripbreaker_cold_start_meters': { 'key': 'tripbreakerColdStartDistanceMeters', 'validator': value_exists, 'response': Error, 'error': 'Trip breaking cold start distance must be provided.' }, 'tripbreaker_subway_buffer_meters': { 'key': 'tripbreakerSubwayBufferMeters', 'validator': value_exists, 'response': Error, 'error': 'Trip breaking subway buffer must be provided.' } }] validated = validate_json(validations, self.headers, self.resource_type) survey = database.survey.get(current_identity.survey_id) survey.about_text = validated['about_text'] survey.terms_of_service = validated['terms_of_service'] survey.contact_email = validated['contact_email'] survey.max_survey_days = validated['survey_max_days'] survey.max_prompts = validated['survey_max_prompts'] survey.gps_accuracy_threshold = validated['gps_accuracy_meters'] survey.trip_break_interval = validated['tripbreaker_interval_seconds'] survey.trip_break_cold_start_distance = validated[ 'tripbreaker_cold_start_meters'] survey.trip_subway_buffer = validated[ 'tripbreaker_subway_buffer_meters'] db.session.commit() return Success(status_code=201, headers=self.headers, resource_type=self.resource_type, body=make_keys_camelcase(validated))
def post(self): validations = [{ 'uuid': { 'key': 'uuid', 'validator': value_exists, 'response': Error, 'error': 'UUID must be supplied. No action taken.' }, 'survey_answers': { 'key': 'survey', 'validator': None }, 'coordinates': { 'key': 'coordinates', 'validator': None }, 'prompts_answers': { 'key': 'prompts', 'validator': None }, 'cancelled_prompts': { 'key': 'cancelledPrompts', 'validator': None } }] validated = validate_json(validations, self.headers, self.resource_type) user = database.user.find_by_uuid(validated['uuid']) if user: survey_answers, coordinates, prompts_answers, cancelled_prompts = None, None, None, None response = { 'survey': 'No new survey data supplied.', 'coordinates': 'No new coordinates data supplied.', 'prompts': 'No new prompt answers supplied.', 'cancelledPrompts': 'No cancelled prompts supplied.' } if validated['survey_answers']: survey_answers = database.survey.upsert( user=user, answers=validated['survey_answers']) if survey_answers: response[ 'survey'] = 'Survey answer for {} upserted.'.format( user.uuid) if validated['coordinates']: coordinates = rename_json_keys(validated['coordinates'], camelcase_to_underscore) coordinates = database.coordinates.insert( user=user, coordinates=coordinates) if coordinates: response['coordinates'] = ( 'New coordinates for {} inserted.'.format(user.uuid)) # upsert prompts answers and remove any existing conflicting cancelled prompt responses if validated['prompts_answers']: formatted_prompts = rename_json_keys( validated['prompts_answers'], camelcase_to_underscore) error = self._fail_on_deprecated_prompts(formatted_prompts) if error: return error prompts_answers = database.prompts.upsert( user=user, prompts=formatted_prompts) prompts_uuids = {p.prompt_uuid for p in prompts_answers} database.cancelled_prompts.delete(prompts_uuids) if prompts_answers: response['prompts'] = ( 'New prompt answers for {} inserted.'.format( user.uuid)) # filter cancelled prompts which conflict with a provided response by uuid and insert cancelled prompts if validated['cancelled_prompts']: formatted_cancelled_prompts = rename_json_keys( validated['cancelled_prompts'], camelcase_to_underscore) # fail gracefully on older version of mobile app that do not provide a prompt uuid error = self._fail_on_deprecated_prompts( formatted_cancelled_prompts) if error: return error if validated['prompts_answers']: answers_uuids = { p['uuid'] for p in validated['prompts_answers'] } filtered_cancelled_prompts = [] for c in formatted_cancelled_prompts: if c['uuid'] not in answers_uuids: filtered_cancelled_prompts.append(c) else: filtered_cancelled_prompts = formatted_cancelled_prompts cancelled_prompts = database.cancelled_prompts.insert( user=user, cancelled_prompts=filtered_cancelled_prompts) if cancelled_prompts: response['cancelledPrompts'] = ( 'New cancelled prompts for {} inserted.'.format( user.uuid)) status = None if any([ survey_answers, coordinates, prompts_answers, cancelled_prompts ]): database.commit() status = 201 else: status = 200 # add in deprecation warning for v1 api return Success( status_code=status, headers=self.headers, resource_type=self.resource_type, status= 'Warning (deprecated): API v1 will soon be phased out. Please refer to documentation for v2 calls.', body=response) return Error( status_code=410, headers=self.headers, resource_type=self.resource_type, errors=['Could not find survey for {}.'.format(validated['uuid'])])