def test_user_has_not_logged_in_last_n_days(self): query_id = user_query_services.save_new_query_model( self.submitter_id, has_not_logged_in_for_n_days=6) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # List of users who has not logged_in in last 6 days. self.assertItemsEqual(query.user_ids, [self.user_e_id]) query_id = user_query_services.save_new_query_model( self.submitter_id, has_not_logged_in_for_n_days=2) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # List of users logged_in in last 2 days. qualifying_user_ids = [self.user_a_id, self.user_e_id] self.assertItemsEqual(query.user_ids, qualifying_user_ids) # Test for legacy user. user_settings = user_services.get_user_settings(self.user_a_id) user_services.update_last_logged_in(user_settings, None) query_id = user_query_services.save_new_query_model( self.submitter_id, has_not_logged_in_for_n_days=6) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # Make sure that legacy user is included in qualified user's list. self.assertItemsEqual(query.user_ids, [self.user_a_id, self.user_e_id])
def test_bulk_email_handler_with_mismatch_of_query_id_raises_401(self): self.login(self.SUBMITTER_EMAIL) query_id = user_query_services.save_new_query_model( self.submitter_id, inactive_in_last_n_days=10, created_at_least_n_exps=5, has_not_logged_in_for_n_days=30) query_id_1 = user_query_services.save_new_query_model( self.new_submitter_id, inactive_in_last_n_days=10, created_at_least_n_exps=5, has_not_logged_in_for_n_days=30) job_id = user_query_jobs_one_off.UserQueryOneOffJob.create_new() user_query_jobs_one_off.UserQueryOneOffJob.enqueue( job_id, additional_job_params={'query_id': query_id}) job_id_1 = user_query_jobs_one_off.UserQueryOneOffJob.create_new() user_query_jobs_one_off.UserQueryOneOffJob.enqueue( job_id_1, additional_job_params={'query_id': query_id_1}) self.assertEqual( self.count_jobs_in_taskqueue( taskqueue_services.QUEUE_NAME_ONE_OFF_JOBS), 2) # Complete execution of query. with self.swap(feconf, 'CAN_SEND_EMAILS', True): self.process_and_flush_pending_tasks() self.assertEqual( self.count_jobs_in_taskqueue( taskqueue_services.QUEUE_NAME_ONE_OFF_JOBS), 0) response = self.get_html_response('/emaildashboardresult/%s' % query_id) csrf_token = self.get_csrf_token_from_response(response) # Raises authorization error when passing a query id whose associated # query model is not created by the logged in user. response = self.post_json('/emaildashboardtestbulkemailhandler/%s' % query_id_1, {}, csrf_token=csrf_token, expected_status_int=401) self.assertEqual( response['error'], '%s is not an authorized user for this query.' % (self.submitter_id)) self.logout()
def post(self): """Post handler for query.""" data = self.payload['data'] kwargs = {key: data[key] for key in data if data[key] is not None} self._validate(kwargs) query_id = user_query_services.save_new_query_model( self.user_id, **kwargs) # Start MR job in background. job_id = user_query_jobs_one_off.UserQueryOneOffJob.create_new() params = {'query_id': query_id} user_query_jobs_one_off.UserQueryOneOffJob.enqueue( job_id, additional_job_params=params) query_model = user_models.UserQueryModel.get(query_id) query_data = { 'id': query_model.id, 'submitter_username': ( user_services.get_username(query_model.submitter_id)), 'created_on': query_model.created_on.strftime('%d-%m-%y %H:%M:%S'), 'status': query_model.query_status, 'num_qualified_users': len(query_model.user_ids) } data = { 'query': query_data } self.render_json(data)
def setUp(self): super(UserBulkEmailsModelValidatorTests, self).setUp() self.signup(USER_EMAIL, USER_NAME) self.user_id = self.get_user_id_from_email(USER_EMAIL) self.signup(self.OWNER_EMAIL, self.OWNER_USERNAME) self.owner_id = self.get_user_id_from_email(self.OWNER_EMAIL) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.query_id = user_query_services.save_new_query_model( self.admin_id, inactive_in_last_n_days=10, created_at_least_n_exps=5, has_not_logged_in_for_n_days=30) query_model = user_models.UserQueryModel.get_by_id(self.query_id) query_model.user_ids = [self.owner_id, self.user_id] query_model.put() with self.swap(feconf, 'CAN_SEND_EMAILS', True): user_query_services.send_email_to_qualified_users( self.query_id, 'subject', 'body', feconf.BULK_EMAIL_INTENT_MARKETING, 5) self.model_instance = user_models.UserBulkEmailsModel.get_by_id( self.user_id) self.sent_mail_id = query_model.sent_email_model_id self.job_class = ( prod_validation_jobs_one_off.UserBulkEmailsModelAuditOneOffJob)
def test_email_dashboard_data_handler(self): self.login(self.SUBMITTER_EMAIL) response = self.get_json('/emaildashboarddatahandler', params={'num_queries_to_fetch': 1}) self.assertEqual(response['recent_queries'], []) query_id = user_query_services.save_new_query_model( self.submitter_id, inactive_in_last_n_days=10, created_at_least_n_exps=5, has_not_logged_in_for_n_days=30) response = self.get_json('/emaildashboarddatahandler', params={'num_queries_to_fetch': 1}) self.assertEqual(len(response['recent_queries']), 1) recent_query = response['recent_queries'][0] self.assertEqual(recent_query['id'], query_id) self.assertEqual(recent_query['status'], feconf.USER_QUERY_STATUS_PROCESSING) self.logout()
def test_that_user_unsubscribed_from_emails_is_skipped(self): query_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) self.assertNotIn(self.user_f_id, query.user_ids)
def test_user_has_edited_fewer_than_n_exps(self): query_id = user_query_services.save_new_query_model( self.submitter_id, edited_fewer_than_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) self.assertItemsEqual(query.user_ids, [self.user_a_id])
def test_bulk_email_handler_with_invalid_query_id_raises_400(self): self.login(self.SUBMITTER_EMAIL) query_id = user_query_services.save_new_query_model( self.submitter_id, inactive_in_last_n_days=10, created_at_least_n_exps=5, has_not_logged_in_for_n_days=30) job_id = user_query_jobs_one_off.UserQueryOneOffJob.create_new() user_query_jobs_one_off.UserQueryOneOffJob.enqueue( job_id, additional_job_params={'query_id': query_id}) self.assertEqual( self.count_jobs_in_taskqueue( taskqueue_services.QUEUE_NAME_ONE_OFF_JOBS), 1) # Complete execution of query. with self.swap(feconf, 'CAN_SEND_EMAILS', True): self.process_and_flush_pending_tasks() self.assertEqual( self.count_jobs_in_taskqueue( taskqueue_services.QUEUE_NAME_ONE_OFF_JOBS), 0) csrf_token = self.get_new_csrf_token() response = self.post_json('/emaildashboardtestbulkemailhandler/%s' % 'invalid_query_id', {}, csrf_token=csrf_token, expected_status_int=400) self.assertEqual(response['error'], '400 Invalid query id.') self.logout()
def test_user_has_created_at_least_n_exps(self): query_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) self.assertItemsEqual(query.user_ids, [self.user_b_id, self.user_d_id, self.user_e_id])
def test_user_has_created_fewer_than_n_exps(self): query_id = user_query_services.save_new_query_model( self.submitter_id, created_fewer_than_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) qualifying_user_ids = [self.user_a_id, self.user_c_id] self.assertEqual(len(query.user_ids), 2) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids))
def test_user_has_edited_fewer_than_n_exps(self): query_id = user_query_services.save_new_query_model( self.submitter_id, edited_fewer_than_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) qualifying_user_ids = [self.user_a_id] self.assertEqual(len(query.user_ids), 1) self.assertEqual(query.user_ids, qualifying_user_ids)
def test_user_has_created_at_least_n_exps(self): query_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) qualifying_user_ids = [self.user_b_id, self.user_d_id, self.user_e_id] self.assertEqual(len(query.user_ids), 3) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids))
def test_user_is_inactive_in_last_n_days(self): query_id = user_query_services.save_new_query_model( self.submitter_id, inactive_in_last_n_days=3) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # List of users who were not active in last 3 days. self.assertItemsEqual(query.user_ids, [self.user_e_id])
def test_user_has_edited_at_least_n_exps(self): query_id = user_query_services.save_new_query_model( self.submitter_id, edited_at_least_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) qualifying_user_ids = ( [self.user_b_id, self.user_c_id, self.user_d_id, self.user_e_id]) self.assertEqual(len(query.user_ids), 4) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids))
def test_user_is_inactive_in_last_n_days(self): query_id = user_query_services.save_new_query_model( self.submitter_id, inactive_in_last_n_days=3) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # List of users who were not active in last 3 days. qualifying_user_ids = [self.user_e_id] self.assertEqual(len(query.user_ids), 1) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids))
def test_combination_of_query_params(self): query_a_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1) self._run_one_off_job(query_a_id) query_b_id = user_query_services.save_new_query_model( self.submitter_id, edited_at_least_n_exps=1) self._run_one_off_job(query_b_id) query_combined_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1, edited_at_least_n_exps=1) self._run_one_off_job(query_combined_id) qualifying_user_ids_a = [ self.user_b_id, self.user_d_id, self.user_e_id ] qualifying_user_ids_b = ([ self.user_b_id, self.user_c_id, self.user_d_id, self.user_e_id ]) qualifying_user_ids_combined = ([ self.user_b_id, self.user_d_id, self.user_e_id ]) query_a = user_models.UserQueryModel.get(query_a_id) query_b = user_models.UserQueryModel.get(query_b_id) query_combined = user_models.UserQueryModel.get(query_combined_id) self.assertEqual(len(query_a.user_ids), 3) self.assertEqual(sorted(query_a.user_ids), sorted(qualifying_user_ids_a)) self.assertEqual(len(query_b.user_ids), 4) self.assertEqual(sorted(query_b.user_ids), sorted(qualifying_user_ids_b)) self.assertEqual(len(query_combined.user_ids), 3) self.assertEqual(sorted(query_combined.user_ids), sorted(qualifying_user_ids_combined))
def test_user_has_not_logged_in_last_n_days(self): query_id = user_query_services.save_new_query_model( self.submitter_id, has_not_logged_in_for_n_days=6) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # List of users who has not logged_in in last 6 days. qualifying_user_ids = [self.user_e_id] self.assertEqual(len(query.user_ids), 1) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids)) query_id = user_query_services.save_new_query_model( self.submitter_id, has_not_logged_in_for_n_days=2) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) # List of users logged_in in last 2 days. qualifying_user_ids = ( [self.user_a_id, self.user_e_id]) self.assertEqual(len(query.user_ids), 2) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids)) # Test for legacy user. user_settings = user_services.get_user_settings(self.user_a_id) user_settings.last_logged_in = None user_services._save_user_settings(user_settings) # pylint: disable=protected-access query_id = user_query_services.save_new_query_model( self.submitter_id, has_not_logged_in_for_n_days=6) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) qualifying_user_ids = ([self.user_a_id, self.user_e_id]) # Make sure that legacy user is included in qualified user's list. self.assertEqual(len(query.user_ids), 2) self.assertEqual(sorted(query.user_ids), sorted(qualifying_user_ids))
def test_combination_of_query_params(self): query_a_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1) self._run_one_off_job(query_a_id) query_b_id = user_query_services.save_new_query_model( self.submitter_id, edited_at_least_n_exps=1) self._run_one_off_job(query_b_id) query_combined_id = user_query_services.save_new_query_model( self.submitter_id, created_at_least_n_exps=1, edited_at_least_n_exps=1) self._run_one_off_job(query_combined_id) qualifying_user_ids_a = [self.user_b_id, self.user_d_id, self.user_e_id] qualifying_user_ids_b = ( [self.user_b_id, self.user_c_id, self.user_d_id, self.user_e_id]) qualifying_user_ids_combined = ( [self.user_b_id, self.user_d_id, self.user_e_id]) query_a = user_models.UserQueryModel.get(query_a_id) query_b = user_models.UserQueryModel.get(query_b_id) query_combined = user_models.UserQueryModel.get(query_combined_id) self.assertEqual(len(query_a.user_ids), 3) self.assertEqual( sorted(query_a.user_ids), sorted(qualifying_user_ids_a)) self.assertEqual(len(query_b.user_ids), 4) self.assertEqual( sorted(query_b.user_ids), sorted(qualifying_user_ids_b)) self.assertEqual(len(query_combined.user_ids), 3) self.assertEqual( sorted(query_combined.user_ids), sorted(qualifying_user_ids_combined))
def test_that_correct_email_is_sent_upon_completion(self): query_id = user_query_services.save_new_query_model( self.submitter_id, edited_fewer_than_n_exps=1) self._run_one_off_job(query_id) query = user_models.UserQueryModel.get(query_id) self.assertEqual( query.query_status, feconf.USER_QUERY_STATUS_COMPLETED) expected_email_html_body = ( 'Hi submit,<br>' 'Your query with id %s has succesfully completed its ' 'execution. Visit the result page ' '<a href="https://www.oppia.org/emaildashboardresult/%s">' 'here</a> ' 'to see result of your query.<br><br>' 'Thanks!<br>' '<br>' 'Best wishes,<br>' 'The Oppia Team<br>' '<br>' 'You can change your email preferences via the ' '<a href="https://www.example.com">Preferences</a> page.' ) % (query_id, query_id) expected_email_text_body = ( 'Hi submit,\n' 'Your query with id %s has succesfully completed its ' 'execution. Visit the result page here ' 'to see result of your query.\n\n' 'Thanks!\n' '\n' 'Best wishes,\n' 'The Oppia Team\n' '\n' 'You can change your email preferences via the ' 'Preferences page.' ) % query_id messages = self.mail_stub.get_sent_messages( to=self.USER_SUBMITTER_EMAIL) self.assertEqual( messages[0].html.decode(), expected_email_html_body) self.assertEqual( messages[0].body.decode(), expected_email_text_body)
def test_query_status_check_handler(self): self.login(self.SUBMITTER_EMAIL) query_id = user_query_services.save_new_query_model( self.submitter_id, inactive_in_last_n_days=10, created_at_least_n_exps=5, has_not_logged_in_for_n_days=30) query_data = self.get_json( '/querystatuscheck', params={'query_id': query_id})['query'] self.assertEqual(query_data['id'], query_id) self.assertEqual( query_data['status'], feconf.USER_QUERY_STATUS_PROCESSING) self.assertEqual( query_data['submitter_username'], self.SUBMITTER_USERNAME) self.logout()
def test_that_correct_email_is_sent_upon_failure(self): query_id = user_query_services.save_new_query_model( self.submitter_id, edited_fewer_than_n_exps=1) self._run_one_off_job_resulting_in_failure(query_id) query = user_models.UserQueryModel.get(query_id) self.assertEqual( query.query_status, feconf.USER_QUERY_STATUS_FAILED) expected_email_html_body = ( 'Hi submit,<br>' 'Your query with id %s has failed due to error ' 'during execution. ' 'Please check the query parameters and submit query again.<br><br>' 'Thanks!<br>' '<br>' 'Best wishes,<br>' 'The Oppia Team<br>' '<br>' 'You can change your email preferences via the ' '<a href="https://www.example.com">Preferences</a> page.' ) % query_id expected_email_text_body = ( 'Hi submit,\n' 'Your query with id %s has failed due to error ' 'during execution. ' 'Please check the query parameters and submit query again.\n\n' 'Thanks!\n' '\n' 'Best wishes,\n' 'The Oppia Team\n' '\n' 'You can change your email preferences via the Preferences page.' ) % query_id messages = self.mail_stub.get_sent_messages( to=self.USER_SUBMITTER_EMAIL) self.assertEqual( messages[0].html.decode(), expected_email_html_body) self.assertEqual( messages[0].body.decode(), expected_email_text_body)
def test_save_new_query_model(self): submitter_id = 'submitter' inactive_in_last_n_days = 10 created_at_least_n_exps = 5 has_not_logged_in_for_n_days = 30 query_id = user_query_services.save_new_query_model( submitter_id, inactive_in_last_n_days=inactive_in_last_n_days, created_at_least_n_exps=created_at_least_n_exps, has_not_logged_in_for_n_days=has_not_logged_in_for_n_days) query_model = user_models.UserQueryModel.get(query_id) self.assertEqual(query_model.submitter_id, submitter_id) self.assertEqual(query_model.inactive_in_last_n_days, inactive_in_last_n_days) self.assertEqual(query_model.created_at_least_n_exps, created_at_least_n_exps) self.assertEqual(query_model.has_not_logged_in_for_n_days, has_not_logged_in_for_n_days) self.assertIsNone(query_model.created_fewer_than_n_exps) self.assertIsNone(query_model.edited_at_least_n_exps) self.assertIsNone(query_model.edited_fewer_than_n_exps)
def test_save_new_query_model(self): submitter_id = 'submitter' inactive_in_last_n_days = 10 created_at_least_n_exps = 5 has_not_logged_in_for_n_days = 30 query_id = user_query_services.save_new_query_model( submitter_id, inactive_in_last_n_days=inactive_in_last_n_days, created_at_least_n_exps=created_at_least_n_exps, has_not_logged_in_for_n_days=has_not_logged_in_for_n_days) query_model = user_models.UserQueryModel.get(query_id) self.assertEqual(query_model.submitter_id, submitter_id) self.assertEqual( query_model.inactive_in_last_n_days, inactive_in_last_n_days) self.assertEqual( query_model.created_at_least_n_exps, created_at_least_n_exps) self.assertEqual( query_model.has_not_logged_in_for_n_days, has_not_logged_in_for_n_days) self.assertIsNone(query_model.created_fewer_than_n_exps) self.assertIsNone(query_model.edited_at_least_n_exps) self.assertIsNone(query_model.edited_fewer_than_n_exps)