def setUp(self): self.app_helper = self.add_helper(AppWorkerHelper(OptOutApplication)) self.app = yield self.app_helper.get_app_worker({}) conv = yield self.app_helper.create_conversation() yield self.app_helper.start_conversation(conv) self.conversation = yield self.app_helper.get_conversation(conv.key) vumi_api = self.app_helper.vumi_helper.get_vumi_api() self.opt_out_store = OptOutStore(vumi_api.manager, self.conversation.user_account.key)
def show_opt_outs(self, user_api, email_address): opt_out_store = OptOutStore(user_api.manager, user_api.user_account_key) opt_outs = opt_out_store.list_opt_outs() print "Address Type, Address, Message ID, Timestamp" print "============================================" for key in opt_outs: addr_type, _colon, addr = key.partition(":") opt_out = opt_out_store.get_opt_out(addr_type, addr) print "%s, %s, %s, %s" % (addr_type, addr, opt_out.message, opt_out.created_at)
class TestOptOutApplication(VumiTestCase): @inlineCallbacks def setUp(self): self.app_helper = self.add_helper(AppWorkerHelper(OptOutApplication)) self.app = yield self.app_helper.get_app_worker({}) conv = yield self.app_helper.create_conversation() yield self.app_helper.start_conversation(conv) self.conversation = yield self.app_helper.get_conversation(conv.key) vumi_api = self.app_helper.vumi_helper.get_vumi_api() self.opt_out_store = OptOutStore(vumi_api.manager, self.conversation.user_account.key) @inlineCallbacks def test_sms_opt_out(self): yield self.app_helper.make_dispatch_inbound("STOP", from_addr="12345", to_addr="666", conv=self.conversation) [msg] = self.app_helper.get_dispatched_outbound() self.assertEqual(msg.get('content'), "You have opted out") opt_out = yield self.opt_out_store.get_opt_out("msisdn", "12345") self.assertNotEqual(opt_out, None) @inlineCallbacks def test_sms_opt_out_no_account(self): yield self.app_helper.make_dispatch_inbound("STOP", from_addr="12345", to_addr="666") [msg] = self.app_helper.get_dispatched_outbound() self.assertEqual( msg.get('content'), "Your opt-out was received but we failed to link it " "to a specific service, please try again later.") @inlineCallbacks def test_http_opt_out(self): yield self.app_helper.make_dispatch_inbound("STOP", from_addr="12345", to_addr="666", conv=self.conversation, transport_type="http_api") [msg] = self.app_helper.get_dispatched_outbound() self.assertEqual(json.loads(msg['content']), { "msisdn": "12345", "opted_in": False, }) opt_out = yield self.opt_out_store.get_opt_out("msisdn", "12345") self.assertNotEqual(opt_out, None)
def test_optout_filtering(self): group = yield self.user_api.contact_store.new_group(u'test-group') user_account = yield self.user_helper.get_user_account() optout_store = OptOutStore.from_user_account(user_account) contact_store = ContactStore.from_user_account(user_account) # Create two random contacts yield self.user_api.contact_store.new_contact(msisdn=u'+27761234567', groups=[group.key]) yield self.user_api.contact_store.new_contact(msisdn=u'+27760000000', groups=[group.key]) conv = yield self.user_helper.create_conversation( u'dummy', delivery_class=u'sms', groups=[group]) # Opt out the first contact yield optout_store.new_opt_out(u'msisdn', u'+27761234567', {'message_id': u'the-message-id'}) contact_keys = yield contact_store.get_contacts_for_conversation(conv) all_addrs = [] for contacts in contact_store.contacts.load_all_bunches(contact_keys): for contact in (yield contacts): all_addrs.append(contact.addr_for(conv.delivery_class)) self.assertEqual(set(all_addrs), set(['+27760000000', '+27761234567'])) optedin_addrs = [] for contacts in (yield conv.get_opted_in_contact_bunches( conv.delivery_class)): for contact in (yield contacts): optedin_addrs.append(contact.addr_for(conv.delivery_class)) self.assertEqual(optedin_addrs, ['+27760000000'])
def setUp(self): super(TestOptOutResource, self).setUp() self.vumi_helper = yield self.add_helper(VumiApiHelper()) self.msg_helper = self.add_helper(GoMessageHelper()) self.user_helper = yield self.vumi_helper.make_user(u'user') user_account = yield self.user_helper.get_user_account() user_account.can_manage_optouts = True yield user_account.save() self.app_worker.user_api = self.user_helper.user_api self.contact_store = self.user_helper.user_api.contact_store self.optout_store = OptOutStore.from_user_account(user_account) yield self.create_resource({}) self.contact1 = yield self.new_contact( name=u'A', surname=u'Person', msisdn=u'+27123456789') self.contact2 = yield self.new_contact( name=u'B', surname=u'Person', msisdn=u'+27000000000')
def setUp(self): self.eh_helper = self.add_helper(EventHandlerHelper()) yield self.eh_helper.setup_event_dispatcher( 'sisi_ni_amani', USSDOptOutHandler, { 'poll_manager_prefix': 'vumigo.', }) vumi_api = self.eh_helper.vumi_helper.get_vumi_api() user_helper = yield self.eh_helper.vumi_helper.get_or_create_user() self.contact_store = user_helper.user_api.contact_store self.oo_store = OptOutStore(vumi_api.manager, user_helper.account_key) self.pm = PollManager(vumi_api.redis, 'vumigo.') self.add_cleanup(self.pm.stop) self.eh_helper.track_event('survey_completed', 'sisi_ni_amani')
def test_optout_filtering(self): group = yield self.user_api.contact_store.new_group(u'test-group') user_account = yield self.user_helper.get_user_account() optout_store = OptOutStore.from_user_account(user_account) contact_store = ContactStore.from_user_account(user_account) # Create two random contacts yield self.user_api.contact_store.new_contact( msisdn=u'+27761234567', groups=[group.key]) yield self.user_api.contact_store.new_contact( msisdn=u'+27760000000', groups=[group.key]) conv = yield self.user_helper.create_conversation( u'dummy', delivery_class=u'sms', groups=[group]) # Opt out the first contact yield optout_store.new_opt_out(u'msisdn', u'+27761234567', { 'message_id': u'the-message-id' }) contact_keys = yield contact_store.get_contacts_for_conversation(conv) all_addrs = [] for contacts in contact_store.contacts.load_all_bunches(contact_keys): for contact in (yield contacts): all_addrs.append(contact.addr_for(conv.delivery_class)) self.assertEqual(set(all_addrs), set(['+27760000000', '+27761234567'])) optedin_addrs = [] for contacts in (yield conv.get_opted_in_contact_bunches( conv.delivery_class)): for contact in (yield contacts): optedin_addrs.append(contact.addr_for(conv.delivery_class)) self.assertEqual(optedin_addrs, ['+27760000000'])
def _filter_opted_out_contacts(self, contacts, delivery_class): # TODO: Less hacky address type handling. address_type = 'gtalk' if delivery_class == 'gtalk' else 'msisdn' contacts = yield contacts opt_out_store = OptOutStore( self.api.manager, self.user_api.user_account_key) filtered_contacts = [] for contact in contacts: contact_addr = contact.addr_for(delivery_class) if contact_addr: opt_out = yield opt_out_store.get_opt_out( address_type, contact_addr) if not opt_out: filtered_contacts.append(contact) returnValue(filtered_contacts)
def setUp(self): self.vumi_helper = yield self.add_helper( VumiApiHelper(is_sync=self.is_sync)) self.user_helper = yield self.vumi_helper.make_user(u'user') user_account = yield self.user_helper.get_user_account() self.optout_store = OptOutStore.from_user_account(user_account) self.conv_store = ConversationStore.from_user_account(user_account) self.contact_store = ContactStore.from_user_account(user_account)
def get_opt_out_collection(self, owner_id): """ Return the opt out collection for the specified owner. :param str owner_id: The id of the owner of the opt out store. """ opt_out_store = OptOutStore(self.riak_manager, owner_id) return RiakOptOutCollection(opt_out_store)
class TestOptOutApplication(VumiTestCase): @inlineCallbacks def setUp(self): self.app_helper = self.add_helper(AppWorkerHelper(OptOutApplication)) self.app = yield self.app_helper.get_app_worker({}) conv = yield self.app_helper.create_conversation() yield self.app_helper.start_conversation(conv) self.conversation = yield self.app_helper.get_conversation(conv.key) vumi_api = self.app_helper.vumi_helper.get_vumi_api() self.opt_out_store = OptOutStore( vumi_api.manager, self.conversation.user_account.key) @inlineCallbacks def test_sms_opt_out(self): yield self.app_helper.make_dispatch_inbound( "STOP", from_addr="12345", to_addr="666", conv=self.conversation) [msg] = self.app_helper.get_dispatched_outbound() self.assertEqual(msg.get('content'), "You have opted out") opt_out = yield self.opt_out_store.get_opt_out("msisdn", "12345") self.assertNotEqual(opt_out, None) @inlineCallbacks def test_sms_opt_out_no_account(self): yield self.app_helper.make_dispatch_inbound( "STOP", from_addr="12345", to_addr="666") [msg] = self.app_helper.get_dispatched_outbound() self.assertEqual(msg.get('content'), "Your opt-out was received but we failed to link it " "to a specific service, please try again later.") @inlineCallbacks def test_http_opt_out(self): yield self.app_helper.make_dispatch_inbound( "STOP", from_addr="12345", to_addr="666", conv=self.conversation, transport_type="http_api") [msg] = self.app_helper.get_dispatched_outbound() self.assertEqual(json.loads(msg['content']), { "msisdn": "12345", "opted_in": False, }) opt_out = yield self.opt_out_store.get_opt_out("msisdn", "12345") self.assertNotEqual(opt_out, None)
def contact_has_opted_out(self, contact): # FIXME: opt-outs are currently had coded to only work for msisdns if not contact.msisdn: return user_account = yield self.get_user_account() opt_out_store = OptOutStore.from_user_account(user_account) opt_out = yield opt_out_store.get_opt_out('msisdn', contact.msisdn) returnValue(opt_out)
def setUp(self): self.app_helper = self.add_helper(AppWorkerHelper(OptOutApplication)) self.app = yield self.app_helper.get_app_worker({}) conv = yield self.app_helper.create_conversation() yield self.app_helper.start_conversation(conv) self.conversation = yield self.app_helper.get_conversation(conv.key) vumi_api = self.app_helper.vumi_helper.get_vumi_api() self.opt_out_store = OptOutStore( vumi_api.manager, self.conversation.user_account.key)
def handle_event(self, event, handler_config): """ Expects the event 'content' to be a dict with the following keys and values: NOTE: perhaps all we need here is the message_id and lookup the rest of the required data from the message in the message store :param from_addr: the from_addr of the user interaction that triggered the event :param message_id: the id of the message that triggered the event, used to keep an audit trail of opt-outs and which messages they were triggered by. :param transport_type: the transport_type that the message was received on. """ account_key = event.payload['account_key'] oo_store = OptOutStore(self.vumi_api.manager, account_key) event_data = event.payload['content'] from_addr = event_data['from_addr'] message_id = event_data['message_id'] transport_type = event_data.get('transport_type') if transport_type != 'ussd': log.info("SNAUSSDOptOutHandler skipping non-ussd" " message for %r" % (from_addr,)) return contact = yield self.find_contact(account_key, from_addr) if contact: opted_out = contact.extra['opted_out'] if opted_out is not None and opted_out.isdigit(): if int(opted_out) > 1: yield oo_store.new_opt_out('msisdn', from_addr, { 'message_id': message_id, }) else: yield oo_store.delete_opt_out('msisdn', from_addr)
def consume_user_message(self, message): msg_mdh = self.get_metadata_helper(message) if not msg_mdh.has_user_account(): # We don't have an account to opt out of. # Since this can only happen for redirected messages, assume we # aren't dealing with an API. yield self.reply_to( message, "Your opt-out was received but we failed to link it " "to a specific service, please try again later.") return account_key = yield msg_mdh.get_account_key() opt_out_store = OptOutStore(self.manager, account_key) from_addr = message.get("from_addr") # Note: for now we are hardcoding addr_type as 'msisdn' # as only msisdn's are opting out currently yield opt_out_store.new_opt_out("msisdn", from_addr, message) if message.get('transport_type') == 'http_api': yield self.reply_to( message, '{"msisdn":"%s","opted_in": false}' % (from_addr, )) else: yield self.reply_to(message, "You have opted out")
def test_check_for_opted_out_contact(self): contact1 = yield self.store.new_contact( name=u'J Random', surname=u'Person', msisdn=u'27831234567') contact2 = yield self.store.new_contact( name=u'J Random', surname=u'Person', msisdn=u'27830000000') # Opt out the first contact user_account = yield self.user_helper.get_user_account() optout_store = OptOutStore.from_user_account(user_account) yield optout_store.new_opt_out(u'msisdn', contact1.msisdn, { 'message_id': u'the-message-id' }) self.assertTrue((yield self.store.contact_has_opted_out(contact1))) self.assertFalse((yield self.store.contact_has_opted_out(contact2)))
def consume_user_message(self, message): msg_mdh = self.get_metadata_helper(message) if not msg_mdh.has_user_account(): # We don't have an account to opt out of. # Since this can only happen for redirected messages, assume we # aren't dealing with an API. yield self.reply_to( message, "Your opt-out was received but we failed to link it " "to a specific service, please try again later.") return account_key = yield msg_mdh.get_account_key() opt_out_store = OptOutStore(self.manager, account_key) from_addr = message.get("from_addr") # Note: for now we are hardcoding addr_type as 'msisdn' # as only msisdn's are opting out currently yield opt_out_store.new_opt_out("msisdn", from_addr, message) if message.get('transport_type') == 'http_api': yield self.reply_to( message, '{"msisdn":"%s","opted_in": false}' % (from_addr,)) else: yield self.reply_to(message, "You have opted out")
def __init__(self, api, user_account_key): # We could get either bytes or unicode here. Decode if necessary. if not isinstance(user_account_key, unicode): user_account_key = user_account_key.decode('utf8') self.api = api self.manager = self.api.manager self.user_account_key = user_account_key self.conversation_store = ConversationStore(self.api.manager, self.user_account_key) self.contact_store = ContactStore(self.api.manager, self.user_account_key) self.router_store = RouterStore(self.api.manager, self.user_account_key) self.channel_store = ChannelStore(self.api.manager, self.user_account_key) self.optout_store = OptOutStore(self.api.manager, self.user_account_key)
def test_get_opted_in_contact_bunches(self): contact_store = self.user_helper.user_api.contact_store user_account = yield self.user_helper.get_user_account() opt_out_store = OptOutStore.from_user_account(user_account) @inlineCallbacks def get_contacts(): bunches = yield self.conv.get_opted_in_contact_bunches( self.conv.delivery_class) contacts = [] for bunch in bunches: contacts.extend((yield bunch)) returnValue([c.msisdn for c in contacts]) self.assertEqual( [], (yield get_contacts())) group = yield contact_store.new_group(u'a group') self.conv.add_group(group) yield self.conv.save() contact1 = yield contact_store.new_contact(msisdn=u'+27000000001') contact1.add_to_group(group) yield contact1.save() contact2 = yield contact_store.new_contact(msisdn=u'+27000000002') contact2.add_to_group(group) yield contact2.save() yield group.save() self.assertEqual( set(['+27000000001', '+27000000002']), set((yield get_contacts()))) yield opt_out_store.new_opt_out(u'msisdn', contact2.msisdn, { 'message_id': u'some-message-id', }) self.assertEqual( ['+27000000001'], (yield get_contacts()))
def test_get_opted_in_contact_bunches(self): contact_store = self.user_helper.user_api.contact_store user_account = yield self.user_helper.get_user_account() opt_out_store = OptOutStore.from_user_account(user_account) @inlineCallbacks def get_contacts(): bunches = yield self.conv.get_opted_in_contact_bunches( self.conv.delivery_class) contacts = [] for bunch in bunches: contacts.extend((yield bunch)) returnValue([c.msisdn for c in contacts]) self.assertEqual([], (yield get_contacts())) group = yield contact_store.new_group(u'a group') self.conv.add_group(group) yield self.conv.save() contact1 = yield contact_store.new_contact(msisdn=u'+27000000001') contact1.add_to_group(group) yield contact1.save() contact2 = yield contact_store.new_contact(msisdn=u'+27000000002') contact2.add_to_group(group) yield contact2.save() yield group.save() self.assertEqual(set(['+27000000001', '+27000000002']), set((yield get_contacts()))) yield opt_out_store.new_opt_out(u'msisdn', contact2.msisdn, { 'message_id': u'some-message-id', }) self.assertEqual(['+27000000001'], (yield get_contacts()))
def setUp(self): super(TestOptOutResource, self).setUp() self.vumi_helper = yield self.add_helper(VumiApiHelper()) self.msg_helper = self.add_helper(GoMessageHelper()) self.user_helper = yield self.vumi_helper.make_user(u'user') user_account = yield self.user_helper.get_user_account() user_account.can_manage_optouts = True yield user_account.save() self.app_worker.user_api = self.user_helper.user_api self.contact_store = self.user_helper.user_api.contact_store self.optout_store = OptOutStore.from_user_account(user_account) yield self.create_resource({}) self.contact1 = yield self.new_contact(name=u'A', surname=u'Person', msisdn=u'+27123456789') self.contact2 = yield self.new_contact(name=u'B', surname=u'Person', msisdn=u'+27000000000')
class TestUSSDOptOutHandler(VumiTestCase): @inlineCallbacks def setUp(self): self.eh_helper = self.add_helper(EventHandlerHelper()) yield self.eh_helper.setup_event_dispatcher( 'sisi_ni_amani', USSDOptOutHandler, { 'poll_manager_prefix': 'vumigo.', }) vumi_api = self.eh_helper.vumi_helper.get_vumi_api() user_helper = yield self.eh_helper.vumi_helper.get_or_create_user() self.contact_store = user_helper.user_api.contact_store self.oo_store = OptOutStore(vumi_api.manager, user_helper.account_key) self.pm = PollManager(vumi_api.redis, 'vumigo.') self.add_cleanup(self.pm.stop) self.eh_helper.track_event('survey_completed', 'sisi_ni_amani') @inlineCallbacks def test_opt_in(self): msisdn = u'+2345' message_id = u'message-id' event = self.eh_helper.make_event('survey_completed', { 'from_addr': msisdn, 'message_id': message_id, 'transport_type': 'ussd', }) yield self.oo_store.new_opt_out('msisdn', msisdn, { 'message_id': message_id}) contact = yield self.contact_store.new_contact(msisdn=msisdn) contact.extra['opted_out'] = u'1' yield contact.save() [opt_out] = yield self.oo_store.list_opt_outs() self.assertTrue(opt_out) yield self.eh_helper.dispatch_event(event) opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, []) @inlineCallbacks def test_opt_out(self): msisdn = u'+2345' message_id = u'message-id' event = self.eh_helper.make_event('survey_completed', { 'from_addr': msisdn, 'message_id': message_id, 'transport_type': 'ussd', }) contact = yield self.contact_store.new_contact(msisdn=msisdn) contact.extra['opted_out'] = u'2' yield contact.save() opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, []) yield self.eh_helper.dispatch_event(event) [opt_out] = yield self.oo_store.list_opt_outs() self.assertTrue(opt_out) @inlineCallbacks def test_opt_out_for_empty_outed_out_value(self): msisdn = u'+2345' message_id = u'message-id' event = self.eh_helper.make_event('survey_completed', { 'from_addr': msisdn, 'message_id': message_id, 'transport_type': 'ussd', }) contact = yield self.contact_store.new_contact(msisdn=msisdn) contact.extra['opted_out'] = u'' yield contact.save() opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, []) yield self.eh_helper.dispatch_event(event) opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, [])
class TestUSSDOptOutHandler(VumiTestCase): @inlineCallbacks def setUp(self): self.eh_helper = self.add_helper(EventHandlerHelper()) yield self.eh_helper.setup_event_dispatcher( 'sisi_ni_amani', USSDOptOutHandler, { 'poll_manager_prefix': 'vumigo.', }) vumi_api = self.eh_helper.vumi_helper.get_vumi_api() user_helper = yield self.eh_helper.vumi_helper.get_or_create_user() self.contact_store = user_helper.user_api.contact_store self.oo_store = OptOutStore(vumi_api.manager, user_helper.account_key) self.pm = PollManager(vumi_api.redis, 'vumigo.') self.add_cleanup(self.pm.stop) self.eh_helper.track_event('survey_completed', 'sisi_ni_amani') @inlineCallbacks def test_opt_in(self): msisdn = u'+2345' message_id = u'message-id' event = self.eh_helper.make_event( 'survey_completed', { 'from_addr': msisdn, 'message_id': message_id, 'transport_type': 'ussd', }) yield self.oo_store.new_opt_out('msisdn', msisdn, {'message_id': message_id}) contact = yield self.contact_store.new_contact(msisdn=msisdn) contact.extra['opted_out'] = u'1' yield contact.save() [opt_out] = yield self.oo_store.list_opt_outs() self.assertTrue(opt_out) yield self.eh_helper.dispatch_event(event) opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, []) @inlineCallbacks def test_opt_out(self): msisdn = u'+2345' message_id = u'message-id' event = self.eh_helper.make_event( 'survey_completed', { 'from_addr': msisdn, 'message_id': message_id, 'transport_type': 'ussd', }) contact = yield self.contact_store.new_contact(msisdn=msisdn) contact.extra['opted_out'] = u'2' yield contact.save() opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, []) yield self.eh_helper.dispatch_event(event) [opt_out] = yield self.oo_store.list_opt_outs() self.assertTrue(opt_out) @inlineCallbacks def test_opt_out_for_empty_outed_out_value(self): msisdn = u'+2345' message_id = u'message-id' event = self.eh_helper.make_event( 'survey_completed', { 'from_addr': msisdn, 'message_id': message_id, 'transport_type': 'ussd', }) contact = yield self.contact_store.new_contact(msisdn=msisdn) contact.extra['opted_out'] = u'' yield contact.save() opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, []) yield self.eh_helper.dispatch_event(event) opt_outs = yield self.oo_store.list_opt_outs() self.assertEqual(opt_outs, [])