def test_verify_google_recaptcha(self): """ Test the function responsible for contacting the google recaptcha API and verifying the captcha response, using a mocked API """ self.setup_google_recaptcha_response() # Set up a fake request object that will be passed directly to # the function being tested class FakeRequest: pass fakerequest = FakeRequest() fakerequest.remote_addr = 'placeholder' # Test a "success" response fakerequest.get_json = lambda **x: \ {'g-recaptcha-response': 'correct_response'} res = utils.verify_recaptcha(fakerequest) self.assertTrue(res) # Test a "fail" response fakerequest.get_json = lambda **x: \ {'g-recaptcha-response': 'incorrect_response'} res = utils.verify_recaptcha(fakerequest) self.assertFalse(res) # Test a 503 response fakerequest.get_json = lambda **x: \ {'g-recaptcha-response': 'dont_return_200'} self.assertRaises( requests.HTTPError, utils.verify_recaptcha, fakerequest ) # Test a malformed request fakerequest = FakeRequest() self.assertRaises( (KeyError, AttributeError), utils.verify_recaptcha, fakerequest )
def test_verify_google_recaptcha(self): """ Test the function responsible for contacting the google recaptcha API and verifying the captcha response, using a mocked API """ self.setup_google_recaptcha_response() # Set up a fake request object that will be passed directly to # the function being tested class FakeRequest: pass fakerequest = FakeRequest() fakerequest.remote_addr = 'placeholder' # Test a "success" response fakerequest.get_json = lambda **x: \ {'g-recaptcha-response': 'correct_response'} res = utils.verify_recaptcha(fakerequest) self.assertTrue(res) # Test a "fail" response fakerequest.get_json = lambda **x: \ {'g-recaptcha-response': 'incorrect_response'} res = utils.verify_recaptcha(fakerequest) self.assertFalse(res) # Test a 503 response fakerequest.get_json = lambda **x: \ {'g-recaptcha-response': 'dont_return_200'} self.assertRaises(requests.HTTPError, utils.verify_recaptcha, fakerequest) # Test a malformed request fakerequest = FakeRequest() self.assertRaises((KeyError, AttributeError), utils.verify_recaptcha, fakerequest)
def post(self): """ HTTP POST request :return: status code from the slack end point """ post_data = get_post_data(request) current_app.logger.info('Received feedback: {0}'.format(post_data)) if not post_data.get('g-recaptcha-response', False) or \ not verify_recaptcha(request): current_app.logger.info('The captcha was not verified!') return err(ERROR_UNVERIFIED_CAPTCHA) else: current_app.logger.info('Skipped captcha!') try: current_app.logger.info('Prettifiying post data: {0}' .format(post_data)) formatted_post_data = json.dumps(self.prettify_post(post_data)) current_app.logger.info('Data prettified: {0}' .format(formatted_post_data)) except BadRequestKeyError as error: current_app.logger.error('Missing keywords: {0}, {1}' .format(error, post_data)) return err(ERROR_MISSING_KEYWORDS) try: slack_response = requests.post( url=current_app.config['FEEDBACK_SLACK_END_POINT'], data=formatted_post_data, timeout=60 ) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): return b'504 Gateway Timeout', 504 current_app.logger.info('slack response: {0}' .format(slack_response.status_code)) # Slack annoyingly redirects if you have the wrong end point current_app.logger.info('Slack API' in slack_response.text) if 'Slack API' in slack_response.text: return err(ERROR_WRONG_ENDPOINT) elif slack_response.status_code == 200: return {}, 200 else: return {'msg': 'Unknown error'}, slack_response.status_code
def post(self): """ HTTP POST request :return: status code from the slack end point and for sending user feedback emails """ post_data = get_post_data(request) current_app.logger.info('Received feedback of type {0}: {1}'.format(post_data.get('_subject'), post_data)) if not post_data.get('g-recaptcha-response', False) or \ not verify_recaptcha(request): current_app.logger.info('The captcha was not verified!') return err(ERROR_UNVERIFIED_CAPTCHA) else: current_app.logger.info('Skipped captcha!') # We only allow POST data from certain origins allowed_origins = [v for k,v in current_app.config.items() if k.endswith('_ORIGIN')] origin = post_data.get('origin', 'NA') if origin == 'NA' or origin not in allowed_origins: return err(ERROR_UNKNOWN_ORIGIN) # Some variable definitions email_body = '' slack_data = '' attachments=[] # Generate the email body based on the data in the POST payload try: email_body = self.create_email_body(post_data) except BadRequestKeyError as error: current_app.logger.error('Missing keywords: {0}, {1}' .format(error, post_data)) return err(ERROR_MISSING_KEYWORDS) except Exception as error: current_app.logger.error('Fatal error creating email body: {0}'.format(error)) return err(ERROR_EMAILBODY_PROBLEM) # Retrieve the name of the person submitting the feedback name = post_data.get('name', 'TownCrier') # There are some origin-specific actions if origin == current_app.config['FEEDBACK_FORMS_ORIGIN']: # The reply_to for feedback form data reply_to = post_data.get('email') # In the case of new or corrected records, attachments are sent along if post_data.get('_subject') == 'New Record': attachments.append(('new_record.json', post_data['new'])) if post_data.get('_subject') == 'Updated Record': attachments.append(('updated_record.json', post_data['new'])) attachments.append(('original_record.json', post_data['original'])) # Prepare a minimal Slack message channel = post_data.get('channel', '#feedback') username = post_data.get('username', 'TownCrier') icon_emoji = current_app.config['FORM_SLACK_EMOJI'] text = 'Received data from feedback form "{0}" from {1}'.format(post_data.get('_subject'), post_data.get('email')) slack_data = { 'text': text, 'username': username, 'channel': channel, 'icon_emoji': icon_emoji } elif origin == current_app.config['BBB_FEEDBACK_ORIGIN']: # The reply_to for the general feedback data reply_to = post_data.get('_replyto', '*****@*****.**') # Prepare the Slack message with submitted data text = '```Incoming Feedback```\n' + email_body channel = post_data.get('channel', '#feedback') username = post_data.get('username', 'TownCrier') icon_emoji = current_app.config['FEEDBACK_SLACK_EMOJI'] slack_data = { 'text': text, 'username': username, 'channel': channel, 'icon_emoji': icon_emoji } # If we have an email body (should always be the case), send out the email if email_body: email_sent = False try: res = send_feedback_email(name, reply_to, post_data['_subject'], email_body, attachments=attachments) email_sent = True except Exception as e: current_app.logger.error('Fatal error while processing feedback form data: {0}'.format(e)) email_sent = False if not email_sent: # If the email could not be sent, we can still log the data submitted current_app.logger.error('Sending of email failed. Feedback data submitted by {0}: {1}'.format(post_data.get('email'), post_data)) return err(ERROR_EMAIL_NOT_SENT) # If we have Slack data, post the message to Slack if slack_data: slack_data['text'] += '\n*sent to adshelp*: {0}'.format(email_sent) try: slack_response = requests.post( url=current_app.config['FEEDBACK_SLACK_END_POINT'], data=json.dumps(slack_data), timeout=60 ) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): return b'504 Gateway Timeout', 504 current_app.logger.info('slack response: {0}' .format(slack_response.status_code)) # Slack annoyingly redirects if you have the wrong end point current_app.logger.info('Slack API' in slack_response.text) if 'Slack API' in slack_response.text: return err(ERROR_WRONG_ENDPOINT) elif slack_response.status_code == 200: return {}, 200 else: return {'msg': 'Unknown error'}, slack_response.status_code return {}, 200