示例#1
0
 def test_get_voting_location_without_supplied_address(
         self, mock_get_address):
     mycity_request = MyCityRequestDataModel()
     mock_get_address.return_value = (MyCityRequestDataModel(), False)
     response = get_voting_location(mycity_request)
     self.assertTrue(
         "read::alexa:device:all:address" in response.card_permissions)
示例#2
0
 def test_returns_session_attributes(self):
     mycity_request = MyCityRequestDataModel()
     mycity_request.session_attributes["test_key"] = "test_value"
     mycity_response = coronavirus_update_intent.get_coronovirus_update(
         mycity_request)
     self.assertEqual("test_value",
                      mycity_response.session_attributes["test_key"])
    def test_does_not_require_boston_address_if_desired_address_provided(self, mock_get_days, mock_get_address):
        device_address_request = MyCityRequestDataModel()
        device_address_request.session_attributes[
            intent_constants.CURRENT_ADDRESS_KEY] \
            = "10 Main Street New York NY"
        mock_get_address.return_value = device_address_request, True

        mock_get_days.return_value = ["Monday"]
        request = MyCityRequestDataModel()
        request.session_attributes[intent_constants.CURRENT_ADDRESS_KEY] = "10 Main Street Boston MA"
        result = get_trash_day_info(request)
        self.assertTrue("Monday" in result.output_speech)
def get_alerts_intent(
    mycity_request: MyCityRequestDataModel,
    get_alerts_function_for_test: typing.Callable[[], typing.Dict] = None,
    prune_normal_responses_function_for_test: typing.Callable[
        [], typing.Dict] = None,
    alerts_to_speech_output_function_for_test: typing.Callable[
        [], typing.AnyStr] = None
) -> MyCityResponseDataModel:
    """
    Generate response object with information about citywide alerts

    :param mycity_request:                            MyCityRequestDataModel object
    :param get_alerts_function_for_test:              Injectable function for unit tests
    :param prune_normal_responses_function_for_test:  Injectable function for unit tests
    :param alerts_to_speech_output_function_for_test: Injectable function for unit tests
    :return:                                          MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    alerts = get_alerts(
    ) if get_alerts_function_for_test is None else get_alerts_function_for_test(
    )
    logger.debug("[dictionary with alerts scraped from boston.gov]:\n" +
                 str(alerts))

    pruned_alerts = prune_normal_responses(alerts) \
        if prune_normal_responses_function_for_test is None else prune_normal_responses_function_for_test(alerts)
    logger.debug("[dictionary after pruning]:\n" + str(alerts))

    mycity_response = _create_response_object()
    mycity_response.output_speech = alerts_to_speech_output(pruned_alerts) \
        if alerts_to_speech_output_function_for_test is None else alerts_to_speech_output_function_for_test(pruned_alerts)
    return mycity_response
 def test_requests_device_address_if_supported(self, mock_get_address):
     mock_get_address.return_value = (MyCityRequestDataModel(), False)
     self.request._session_attributes.pop(
         intent_constants.CURRENT_ADDRESS_KEY, None)
     self.request.device_has_geolocation = False
     response = snow_parking.get_snow_emergency_parking_intent(self.request)
     self.assertEqual(response.card_type, "AskForPermissionsConsent")
def get_inclement_weather_alert(
    mycity_request: MyCityRequestDataModel,
    get_alerts_function_for_test: typing.Callable[[], typing.Dict] = None,
) -> MyCityResponseDataModel:
    """
    Generates a response with information about any inclement weather alerts.

    :param mycity_request:                            MyCityRequestDataModel object
    :param get_alerts_function_for_test:              Injectable function for unit tests
    :return:                                          MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    alerts = get_alerts(
    ) if get_alerts_function_for_test is None else get_alerts_function_for_test(
    )
    logger.debug("[dictionary with alerts scraped from boston.gov]:\n" +
                 str(alerts))

    logger.debug("filtering for inclement weather alerts")
    output_speech = constants.NO_INCLEMENT_WEATHER_ALERTS
    if Services.ALERT_HEADER.value in alerts:
        if any(query in alerts[Services.ALERT_HEADER.value].lower()
               for query in SNOW_ALERT_QUERY):
            logger.debug("inclement weather alert found")
            output_speech = alerts[Services.ALERT_HEADER.value]

    mycity_response = _create_response_object()
    mycity_response.session_attributes = mycity_request.session_attributes
    mycity_response.output_speech = output_speech
    return mycity_response
示例#7
0
 def test_does_not_get_device_address_if_desired_address_provided(
         self, mock_get_days, mock_get_address):
     mock_get_days.return_value = ["Monday"]
     request = MyCityRequestDataModel()
     request.session_attributes[
         intent_constants.CURRENT_ADDRESS_KEY] = "10 Main Street Boston MA"
     get_trash_day_info(request)
     mock_get_address.assert_not_called()
 def test_fallback_to_manual_request_if_no_device_address(
         self, mock_get_address):
     mock_get_address.return_value = (MyCityRequestDataModel(), True)
     self.request._session_attributes.pop(
         intent_constants.CURRENT_ADDRESS_KEY, None)
     self.request.device_has_geolocation = False
     response = snow_parking.get_snow_emergency_parking_intent(self.request)
     self.assertEqual("Address", response.card_title)
示例#9
0
 def test_no_ward_voting_response(self, mock_ward, mock_geocode):
     mycity_request = MyCityRequestDataModel()
     mycity_request.session_attributes[
         intent_constants.CURRENT_ADDRESS_KEY] = "866 Huntington Avenue"
     mock_geocode.return_value = test_constants.GEOCODE_ADDRESS_CANDIDATES
     mock_ward.side_effect = ParseError()
     expected_text = "There doesn't seem to be information for that address in Boston"
     response = get_voting_location(mycity_request)
     self.assertTrue(expected_text, response.output_speech)
示例#10
0
    def test_delegates_if_address_not_provided_no_geolocation_support(
            self, mock_get_address):
        self.request.device_has_geolocation = False
        device_address_request = MyCityRequestDataModel()
        mock_get_address.return_value = device_address_request, True

        self.request._session_attributes.pop(
            intent_constants.CURRENT_ADDRESS_KEY, None)
        response = self.controller.on_intent(self.request)
        self.assertEqual(response.dialog_directive['type'], "Dialog.Delegate")
    def test_device_address_finds_closest_parking(self, mock_get_address):
        request_with_address = MyCityRequestDataModel()
        request_with_address._session_attributes[
            intent_constants.CURRENT_ADDRESS_KEY] = "1000 Dorchester Ave"
        mock_get_address.return_value = (request_with_address, True)

        self.request._session_attributes.pop(
            intent_constants.CURRENT_ADDRESS_KEY, None)
        self.request.device_has_geolocation = False
        response = snow_parking.get_snow_emergency_parking_intent(self.request)
        self.assertEqual(self.expected_card_title, response.card_title)
示例#12
0
 def test_correct_voting_response(self, mock_poll_location, mock_ward,
                                  mock_geocode):
     mycity_request = MyCityRequestDataModel()
     mycity_request.session_attributes[
         intent_constants.CURRENT_ADDRESS_KEY] = "866 Huntington Avenue"
     mock_geocode.return_value = test_constants.GEOCODE_ADDRESS_CANDIDATES
     mock_ward.return_value = test_constants.WARD_PRECINCT
     mock_poll_location.return_value = test_constants.POLL_DATA
     expected_text = "Your polling location is BACK OF THE HILL APARTMENTS , 100 SOUTH HUNTINGTON AVENUE."
     response = get_voting_location(mycity_request)
     self.assertTrue(expected_text, response.output_speech)
示例#13
0
 def test_requests_user_supplied_address_when_no_device_address_set(
         self, mock_get_address):
     mock_get_address.return_value = (MyCityRequestDataModel(), True)
     request = MyCityRequestDataModel()
     response = get_trash_day_info(request)
     self.assertEqual("Address", response.card_title)
示例#14
0
 def test_requests_device_address_permission(self, mock_get_address):
     mock_get_address.return_value = (MyCityRequestDataModel(), False)
     request = MyCityRequestDataModel()
     response = get_trash_day_info(request)
     self.assertTrue(
         "read::alexa:device:all:address" in response.card_permissions)
示例#15
0
 def test_provided_address_must_be_in_city(self, mock_get_days):
     mock_get_days.return_value = ["Monday"]
     request = MyCityRequestDataModel()
     request.session_attributes[intent_constants.CURRENT_ADDRESS_KEY] = "10 Main Street New York, NY"
     result = get_trash_day_info(request)
     self.assertFalse("Monday" in result.output_speech)
示例#16
0
 def test_provided_address_misunderstood(self):
     expected_text = speech_constants.ADDRESS_NOT_UNDERSTOOD
     request = MyCityRequestDataModel()
     request.session_attributes[intent_constants.CURRENT_ADDRESS_KEY] = "wayne street"
     result = get_trash_day_info(request)
     self.assertTrue(expected_text in result.output_speech)
示例#17
0
def platform_to_mycity_request(event):
    """
    Translates from Amazon platform request to MyCityRequestDataModel

    :param event:
    :return:
    """
    print("\n\n[module: lambda_function]",
          "[function: platform_to_mycity_request]",
          "Amazon request received:\n", str(event))
    mycity_request = MyCityRequestDataModel()
    mycity_request.request_type = event['request']['type']
    mycity_request.request_id = event['request']['requestId']
    mycity_request.is_new_session = event['session']['new']
    mycity_request.session_id = event['session']['sessionId']
    if 'attributes' in event['session']:
        mycity_request.session_attributes = event['session']['attributes']
    else:
        mycity_request.session_attributes = {}
    mycity_request.application_id = event['session']['application'][
        'applicationId']
    if 'intent' in event['request']:
        mycity_request.intent_name = event['request']['intent']['name']
        if 'slots' in event['request']['intent']:
            mycity_request.intent_variables = event['request']['intent'][
                'slots']
    else:
        mycity_request.intent_name = None
    mycity_request.output_speech = None
    mycity_request.reprompt_text = None
    mycity_request.should_end_session = False

    return mycity_request
示例#18
0
def get_voting_location(mycity_request: MyCityRequestDataModel) -> \
        MyCityResponseDataModel:
    """
    Generates response object for a polling location inquiry which includes
    a user's location to vote.

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseDataModel object
    """

    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())
    mycity_response = MyCityResponseDataModel()
    mycity_response.card_title = CARD_TITLE

    # check for address for locating voting location
    if intent_constants.CURRENT_ADDRESS_KEY not in \
        mycity_request.session_attributes:
        mycity_request, location_permissions = \
            get_address_from_user_device(mycity_request)
        if not location_permissions:
            return request_device_address_permission_response()
        elif intent_constants.CURRENT_ADDRESS_KEY not in \
                mycity_request.session_attributes:
            return request_user_address_response(mycity_request)

    current_address = \
        mycity_request.session_attributes[intent_constants.CURRENT_ADDRESS_KEY]

    # If we have more specific info then just the street
    # address, make sure we are in Boston
    if not is_address_in_city(current_address):
        mycity_response.output_speech = NOT_IN_BOSTON_SPEECH
        mycity_response.should_end_session = True
        mycity_response.card_title = CARD_TITLE
        return mycity_response

    # grab relevant information from session address
    parsed_address, _ = usaddress.tag(current_address)

    if not is_address_valid(parsed_address):
        mycity_response.output_speech = ADDRESS_NOT_UNDERSTOOD
        mycity_response.dialog_directive = "ElicitSlotVotingIntent"
        mycity_response.reprompt_text = None
        mycity_response.session_attributes = mycity_request.session_attributes
        mycity_response.card_title = CARD_TITLE
        mycity_response.should_end_session = True
        return clear_address_from_mycity_object(mycity_response)

    zipcode = None
    if "Zipcode" in mycity_request.intent_variables and \
        "value" in mycity_request.intent_variables["Zipcode"]:
        zipcode = \
                mycity_request.intent_variables["Zipcode"]["value"].zfill(5)

    mycity_response.reprompt_text = None
    mycity_response.should_end_session = True

    try:
        top_candidate = gis_utils.geocode_address(current_address, zipcode)
        ward_precinct = vote_utils.get_ward_precinct_info(top_candidate)
        poll_location = vote_utils.get_polling_location(ward_precinct)
        output_speech = LOCATION_SPEECH. \
            format(poll_location[LOCATION_NAME], poll_location[LOCATION_ADDRESS])
        mycity_response.output_speech = output_speech
    except ParseError:
        mycity_response.output_speech = NO_WARD_OR_PRECINCT
    except BadAPIResponse:
        mycity_response.output_speech = BAD_API_RESPONSE
    except MultipleAddressError as error:
        address_list = ', '.join(error.addresses)
        mycity_response.output_speech = MULTIPLE_ADDRESS_ERROR
        mycity_response.dialog_directive = "ElicitSlotZipCode"
        mycity_response.should_end_session = False

    return mycity_response
示例#19
0
 def test_returns_valid_text(self):
     mycity_request = MyCityRequestDataModel()
     mycity_reponse = coronavirus_update_intent.get_coronovirus_update(
         mycity_request)
     self.assertFalse(coronavirus_update_intent.NO_UPDATE_ERROR in
                      mycity_reponse.output_speech)
示例#20
0
def platform_to_mycity_request(event):
    """
    Translates from Amazon platform request to MyCityRequestDataModel

    :param event: JSON object containing the raw request information received
        from the Alexa service platform
    :return: MyCityRequestDataModel object (formatted to be understood and
        acted on by mycity_controller)
    """
    print("\n\n[module: lambda_function]",
          "[function: platform_to_mycity_request]",
          "Amazon request received:\n", str(event))
    mycity_request = MyCityRequestDataModel()
    mycity_request.request_type = event['request']['type']
    mycity_request.request_id = event['request']['requestId']
    mycity_request.is_new_session = event['session']['new']
    mycity_request.session_id = event['session']['sessionId']
    if 'attributes' in event['session']:
        mycity_request.session_attributes = event['session']['attributes']
    else:
        mycity_request.session_attributes = {}
    mycity_request.application_id = event['session']['application'][
        'applicationId']
    if 'intent' in event['request']:
        mycity_request.intent_name = event['request']['intent']['name']
        if 'slots' in event['request']['intent']:
            mycity_request.intent_variables = event['request']['intent'][
                'slots']
    else:
        mycity_request.intent_name = None
    mycity_request.output_speech = None
    mycity_request.reprompt_text = None
    mycity_request.should_end_session = False

    return mycity_request
示例#21
0
def platform_to_mycity_request(event):
    """
    Translates from Amazon platform request to MyCityRequestDataModel

    :param event: JSON object containing the raw request information received
        from the Alexa service platform
    :return: MyCityRequestDataModel object (formatted to be understood and
        acted on by mycity_controller)
    """
    logger.debug('Amazon request received: ' + str(event))
    mycity_request = MyCityRequestDataModel()

    # Get base request information
    mycity_request.request_type = event['request']['type']
    mycity_request.request_id = event['request']['requestId']

    # Get session information
    mycity_request.is_new_session = event['session']['new']
    mycity_request.session_id = event['session']['sessionId']
    mycity_request.application_id = \
        event['session']['application']['applicationId']

    # Get device information
    system_context = event['context']['System']
    device_context = system_context.get('device', {})
    mycity_request.device_id = device_context.get('deviceId', "unknown")
    mycity_request.api_access_token = \
        system_context.get('apiAccessToken', "none")

    # Get location services info
    mycity_request = _get_location_services_info(event, mycity_request)

    if 'attributes' in event['session']:
        mycity_request.session_attributes = event['session']['attributes']
    else:
        mycity_request.session_attributes = {}

    if 'intent' in event['request']:
        mycity_request.intent_name = event['request']['intent']['name']
        if 'slots' in event['request']['intent']:
            mycity_request.intent_variables = \
                event['request']['intent']['slots']
    else:
        mycity_request.intent_name = None
    mycity_request.output_speech = None
    mycity_request.reprompt_text = None
    mycity_request.should_end_session = False

    return mycity_request
示例#22
0
def get_alerts_intent(
        mycity_request: MyCityRequestDataModel,
        get_alerts_function_for_test: typing.Callable[[], typing.Dict] = None,
        prune_normal_responses_function_for_test:
        typing.Callable[[], typing.Dict] = None,
        alerts_to_speech_output_function_for_test:
        typing.Callable[[], typing.AnyStr] = None
) -> MyCityResponseDataModel:
    """
    Generate response object with information about citywide alerts

    :param mycity_request: MyCityRequestDataModel object
    :param get_alerts_function_for_test: Injectable function for unit tests
    :param prune_normal_responses_function_for_test: Injectable function
     for unit tests
    :param alerts_to_speech_output_function_for_test: Injectable function
    for unit tests
    :return: MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    # get the intent_variables and sessions_attribute object from the request
    intent_variables = mycity_request.intent_variables
    session_attributes = mycity_request.session_attributes
    
    service_name = intent_variables['ServiceName'].get('value') \
        if 'ServiceName' in intent_variables else None
    if service_name:
        service_name = service_name.lower()

    session_alerts = session_attributes.get('alerts', None)
    if not session_alerts:
        session_alerts = get_pruned_alerts(
            get_alerts_function_for_test, prune_normal_responses_function_for_test)

    # Build the response.
    mycity_response = _create_response_object()
    mycity_response.session_attributes = session_attributes.copy()
    mycity_response.should_end_session = True

    if session_alerts is None:
        logger.debug(
            "Could not get alerts from session attributes or Boston webpage")
        mycity_response.should_end_session = False
        mycity_response.output_speech = constants.LAUNCH_REPROMPT_SPEECH
        return mycity_response

    if service_name is None:
        # If the user hasn't give us a service name, check if we should
        # list alerts if there are only a few, or ask the user to select one
        if len(session_alerts) > 1:
            mycity_response.session_attributes['alerts'] = session_alerts
            mycity_response.dialog_directive = "ElicitSlotServiceName"
            mycity_response.should_end_session = False
            mycity_response.output_speech = list_alerts_output(session_alerts)
        else:
            mycity_response.output_speech = \
                alerts_to_speech_output(session_alerts) \
                if alerts_to_speech_output_function_for_test is None \
                else alerts_to_speech_output_function_for_test(session_alerts)
    elif service_name == 'all':
        # Respond with all alert text
        mycity_response.output_speech = \
            alerts_to_speech_output(session_alerts) \
            if alerts_to_speech_output_function_for_test is None \
            else alerts_to_speech_output_function_for_test(session_alerts)
    elif service_name in session_alerts:
        # Grab the requested service alert
        alert = {service_name: session_alerts[service_name]}
        mycity_response.output_speech = alerts_to_speech_output(alert) \
            if alerts_to_speech_output_function_for_test is None \
            else alerts_to_speech_output_function_for_test(alert)
    else:
        # Service not found. Re-ask for the desired service.
        mycity_response.session_attributes['alerts'] = session_alerts
        mycity_response.should_end_session = False
        mycity_response.output_speech = constants.INVALID_SERVICE_NAME_SCRIPT
        mycity_response.output_speech += list_alerts_output(session_alerts)
        mycity_response.dialog_directive = "ElicitSlotServiceName"

    return mycity_response