def handle_member_answer( event_number: str, member_number: str, origin_conversation_uuid: str, origin_call_uuid: str, client: nexmo.Client, ): """Connects an organizer to a call-in-progress when they answer.""" # Members can actually be part of multiple events, so look up the event # separately. member = db.get_member_by_number(member_number) event = db.get_event_by_number(event_number) if member is None or event is None: error_ncco = [{ "action": "talk", "text": common_text.voice_answer_error }] return error_ncco client.send_speech( origin_call_uuid, text=common_text.voice_answer_announce.format(member=member)) ncco = [ { "action": "talk", "text": common_text.voice_answer_greeting.format(member=member, event=event), }, { "action": "conversation", "name": origin_conversation_uuid, "startOnEnter": True, "endOnExit": True, }, ] audit_log.log( audit_log.Kind.VOICE_CONVERSATION_ANSWERED, description=f"{member.name} answered {origin_conversation_uuid[-12:]}.", user="******", event=event, ) return ncco
def handle_member_answer( event_number: str, member_number: str, origin_conversation_uuid: str, origin_call_uuid: str, client: nexmo.Client, ): """Connects an organizer to a call-in-progress when they answer.""" # Members can actually be part of multiple events, so look up the event # separately. member = db.get_member_by_number(member_number) event = db.get_event_by_number(event_number) if member is None or event is None: error_ncco = [{ "action": "talk", "text": ("Oh no, an error occurred and we couldn't find the event or " "member entry for this call."), }] return error_ncco client.send_speech(origin_call_uuid, text=f"{member.name} is joining this call.") ncco = [ { "action": "talk", "text": f"Hello {member.name}, connecting you to {event.name}.", }, { "action": "conversation", "name": origin_conversation_uuid, "startOnEnter": True, "endOnExit": True, }, ] return ncco
def _create_room(event_number: str, reporter_number: str) -> hotline.chatroom.Chatroom: """Creates a room for the event with the given primary number. The alogrithm is a little tricky here. The event organizers can not use the primary number as the chat relay for this chat, so a new number must be used. """ # Find the event. event = db.get_event_by_number(event_number) if not event: raise EventDoesNotExist(f"No event for number {event_number}.") # Create a chatroom chatroom = hotline.chatroom.Chatroom() chatroom.add_user(name="Reporter", number=reporter_number, relay=event_number) # Find all organizers. organizers = list(db.get_verified_event_members(event)) if not organizers: raise NoOrganizersAvailable(f"No organizers found for {event.name}. :/") # Find an unused number to use for the organizers' relay. # Use the first organizer's number here, as all organizers should be # assigned the same relay anyway. organizer_number = organizers[0].number relay_number = db.find_unused_relay_number(event.primary_number, organizer_number) if not relay_number: raise NoRelaysAvailable() # Now add the organizers and their relay. for organizer in organizers: chatroom.add_user( name=organizer.name, number=organizer.number, relay=relay_number ) # Save the chatroom. db.save_room(chatroom, event=event) audit_log.log( audit_log.Kind.SMS_CONVERSATION_STARTED, description=f"A new sms conversation was started last 4 digits of number is {reporter_number[-4:]}", event=event, ) # Send welcome messages. lowlevel.send_sms( sender=event_number, to=reporter_number, message=f"You have started a new chat with the organizers of {event.name}.", ) for organizer in organizers: lowlevel.send_sms( sender=relay_number, to=organizer.number, message=f"This is the beginning of a new chat for {event.name}, the last 4 digits of the reporters number are {reporter_number[-4:]}.", ) return chatroom
def handle_inbound_call( reporter_number: str, event_number: str, conversation_uuid: str, call_uuid: str, host: str, client: nexmo.Client, ) -> List[dict]: # Get the event. If there's no event, tell the user that something went # wrong. event = db.get_event_by_number(event_number) if event is None: error_ncco = [{"action": "talk", "text": common_text.voice_no_event}] return error_ncco # Make sure the number isn't blocked. if db.check_if_blocked(event=event, number=reporter_number): error_ncco = [{"action": "talk", "text": common_text.voice_blocked}] return error_ncco # Get the members for the event. If there are no members, tell the user. :( event_members = list(db.get_verified_event_members(event)) if not event_members: error_ncco = [{"action": "talk", "text": common_text.voice_no_members}] return error_ncco # Make sure that the user is a verified member of this hotline. # If not, bounce them. if not db.get_verified_member_for_event_by_number(event, reporter_number): error_ncco = [{"action": "talk", "text": common_text.voice_non_member}] return error_ncco # Great, we have an event. Greet the user. if event.voice_greeting is not None and event.voice_greeting.strip(): greeting = event.voice_greeting else: greeting = common_text.voice_default_greeting.format(event=event) # NCCOs to be given to the caller. reporter_nccos: List[dict] = [] # Greet the reporter. reporter_nccos.append({"action": "talk", "text": greeting}) # Start a "conversation" (conference call) reporter_nccos.append({ "action": "conversation", "name": conversation_uuid, "eventMethod": "POST", "musicOnHoldUrl": [HOLD_MUSIC], "endOnExit": False, "startOnEnter": False, }) # Add all of the event members to the conference call. for member in event_members: client.create_call({ "to": [{ "type": "phone", "number": member.number }], "from": { "type": "phone", "number": event.primary_number }, "answer_url": [ f"https://{host}/telephony/connect-to-conference/{conversation_uuid}/{call_uuid}" ], "answer_method": "POST", }) # TODO NZ: log name instead of number. # Last four digits of number is {reporter_number[-4:]} audit_log.log( audit_log.Kind.VOICE_CONVERSATION_STARTED, description= f"A new voice conversation was started. UUID is {conversation_uuid[-12:]}.", event=event, reporter_number=reporter_number, ) return reporter_nccos
def handle_inbound_call( event_number: str, conversation_uuid: str, call_uuid: str, host: str, client: nexmo.Client, ) -> List[dict]: # Get the event. If there's no event, tell the user that something went # wrong. event = db.get_event_by_number(event_number) if event is None: error_ncco = [{ "action": "talk", "text": "No event was found for this number. Please reach out to the event staff directly for assistance.", }] return error_ncco # Get the members for the event. If there are no members, tell the user. :( event_members = list(db.get_verified_event_members(event)) if not event_members: error_ncco = [{ "action": "talk", "text": ("Unfortunately, there are no verified members for this event's hotline. " "Please reach out to the event staff directly for assistance."), }] return error_ncco # Great, we have an event. Greet the user. greeting = ( f"Thank you for calling the Code of Conduct hotline for {event.name}. This will dial all " f"of the hotline members and put you on hold until one is able to answer." ) # NCCOs to be given to the caller. reporter_nccos: List[dict] = [] # Greet the reporter. reporter_nccos.append({"action": "talk", "text": greeting}) # Start a "conversation" (conference call) reporter_nccos.append({ "action": "conversation", "name": conversation_uuid, "eventMethod": "POST", "musicOnHoldUrl": [HOLD_MUSIC], "endOnExit": False, "startOnEnter": False, }) # Add all of the event members to the conference call. for member in event_members: client.create_call({ "to": [{ "type": "phone", "number": member.number }], "from": { "type": "phone", "number": event.primary_number }, "answer_url": [ f"https://{host}/telephony/connect-to-conference/{conversation_uuid}/{call_uuid}" ], "answer_method": "POST", }) audit_log.log( audit_log.Kind.VOICE_CONVERSATION_STARTED, description= f"A new voice conversation was started, uuid is {conversation_uuid}", event=event, ) return reporter_nccos
def _create_room(event_number: str, reporter_number: str) -> hotline.chatroom.Chatroom: """Creates a room for the event with the given primary number. The alogrithm is a little tricky here. The event organizers can not use the primary number as the chat relay for this chat, so a new number must be used. """ # Find the event. event = db.get_event_by_number(event_number) if not event: raise EventDoesNotExist() # Make sure the number isn't blocked. if db.check_if_blocked(event=event, number=reporter_number): raise NumberBlocked() # Create a chatroom chatroom = hotline.chatroom.Chatroom() chatroom.add_user(name="Reporter", number=reporter_number, relay=event_number) # Find all organizers. organizers = list(db.get_verified_event_members(event)) if not organizers: raise NoOrganizersAvailable() # Find an unused number to use for the organizers' relay. relay_number = db.find_unused_relay_number(event) if not relay_number: raise NoRelaysAvailable() # Now add the organizers and their relay. for organizer in organizers: chatroom.add_user(name=organizer.name, number=organizer.number, relay=relay_number) # Save the chatroom. db.save_room(chatroom, relay_number=relay_number, event=event) audit_log.log( audit_log.Kind.SMS_CONVERSATION_STARTED, description= f"A new sms conversation was started. Last 4 digits of number is {reporter_number[-4:]}", event=event, reporter_number=reporter_number, ) # Determine the greeting. if event.sms_greeting is not None and event.sms_greeting.strip(): greeting = event.sms_greeting else: greeting = common_text.sms_default_greeting.format(event=event) # Send welcome messages. lowlevel.send_sms(sender=event_number, to=reporter_number, message=greeting) for organizer in organizers: lowlevel.send_sms( sender=relay_number, to=organizer.number, message=common_text.sms_introduction.format( event=event, reporter_number=reporter_number[-4:]), ) return chatroom