示例#1
0
def post_enter_email():
    email = request.form.get('email')
    current_app.logger.info(
        "Endpoint called with customer email as '{}'".format(email))

    validator = CustomerEmailValidator.validate(email)
    if validator.errors:
        current_app.logger.warning("Validation errors found")
        return render_template(
            'enter_email.html',
            validation_errors=validator.errors,
            validation_summary_heading=validator.summary_heading_text,
            error_heading_message=validator.summary_heading_text,
            request_body=request.form,
            submit_url=url_for("send_payment_link.post_enter_email")), 400

    # Send email
    NotificationAPIService.send_message_notify(
        email, config.NOTIFY_PAYMENT_LINK_TEMPLATE_ID, {})

    # Clear down the session information for payment
    g.session.send_payment_link_info = None
    g.session.commit()

    AuditAPIService.audit_event(
        "LON payment link sent to user {}".format(email))

    return render_template('email_confirmation.html')
示例#2
0
def view_lon(charge_id):
    current_app.logger.info("Endpoint called - Clearing session charge")

    local_land_charge_service = LocalLandChargeService(current_app.config)

    # Clear these session values if someone quit an edit back to the view page
    g.session.add_lon_charge_state = None
    g.session.edited_fields = None
    g.session.commit()
    current_app.logger.info("Charge cleared from session")

    display_id, charge_item = get_lon_by_charge_id(charge_id,
                                                   local_land_charge_service)
    # Let the LLC blueprint handle LLC's
    if charge_item.charge_type != LonDefaults.charge_type:
        return redirect(
            url_for('view_land_charge.view_land_charge',
                    local_land_charge=charge_id))

    updated, updated_date = get_history_update_info_by_charge_id(
        charge_id, local_land_charge_service)

    AuditAPIService.audit_event("User viewing LON: {}".format(charge_id))

    return render_template(
        'view_lon.html',
        charge_id=display_id,
        charge_item=charge_item,
        updated=updated,
        updated_date=updated_date,
        geometry=json.dumps(charge_item.geometry),
        document_urls=get_external_url_for_docs(charge_item))
 def test_audit_event_success(self, mock_socket):
     with main.app.test_request_context():
         mock_socket.gethostbyname.return_value = "1.1.1.1"
         self.mock_request()
         g.requests.post.return_value = self.mock_response(status_code=201)
         AuditAPIService.audit_event("A thing")
         g.requests.post.assert_called()
示例#4
0
def view_land_charge(local_land_charge):
    current_app.logger.info("Endpoint called - Clearing session charge")

    local_land_charge_service = LocalLandChargeService(current_app.config)

    # Clear these session values if someone quit an edit back to the view page
    g.session.add_charge_state = None
    g.session.edited_fields = None
    g.session.charge_added_outside_users_authority = None
    g.session.other_authority_update_permission = None
    g.session.other_authority_cancel_permission = None
    g.session.commit()
    current_app.logger.info("Charge cleared from session")

    validate_charge_id(local_land_charge)

    current_app.logger.info(
        "Retrieving charge for local_land_charge='{}'".format(
            local_land_charge))
    response = local_land_charge_service.get_by_charge_number(
        local_land_charge)

    if response.status_code == 404:
        current_app.logger.info(
            "Search service reports '{}' not found - Returning error".format(
                local_land_charge))
        raise ApplicationError(404)

    response.raise_for_status()
    current_app.logger.info(
        "Retrieved charge for local_land_charge='{}'".format(
            local_land_charge))

    charge_data = response.json()[0]['item']
    charge_item = LocalLandChargeItem.from_json(charge_data)

    # Let the LON blueprint handle LONS
    if charge_item.charge_type == LonDefaults.charge_type:
        return redirect(
            url_for('view_lon.view_lon', charge_id=local_land_charge))

    current_app.logger.info(
        "Retrieving charge history for local_land_charge='{}'".format(
            local_land_charge))
    updated, updated_date = get_history_update_info_by_charge_id(
        local_land_charge, local_land_charge_service)

    current_app.logger.info(
        "Rendering template for local_land_charge='{}'".format(
            local_land_charge))
    AuditAPIService.audit_event(
        "User viewing charge: {}".format(local_land_charge))

    return render_template('view_charge.html',
                           charge_item=charge_item,
                           charge_id=response.json()[0]['display_id'],
                           updated_date=updated_date,
                           updated=updated,
                           geometry=json.dumps(charge_item.geometry))
示例#5
0
    def update_charge(land_charge):
        current_app.logger.info("Attempting to update a charge")
        try:
            # Update Author Information
            land_charge.author = g.session.user.get_author_info()
            charge_json = land_charge.to_json()
            headers = {
                'Content-Type': 'application/json',
                'X-Trace-ID': g.trace_id
            }

            current_app.logger.info(
                "Putting to maintain-api/local-land-charge/{}".format(
                    charge_json['local-land-charge']))
            response = g.requests.put('{}/local-land-charge/{}'.format(
                MAINTAIN_API_URL, charge_json['local-land-charge']),
                                      json=charge_json,
                                      headers=headers)
        except Exception as ex:
            error_message = 'Failed to send land charge to maintain-api. ' \
                            'TraceID : {} - Exception - {}' \
                .format(g.trace_id, ex)
            current_app.logger.exception(error_message)
            AuditAPIService.audit_event(
                "Failed to send land charge to maintain-api",
                supporting_info={
                    'id': calc_display_id(land_charge.local_land_charge)
                })
            raise ApplicationError(500)

        if response.status_code != 202:
            current_app.logger.exception(
                'Failed to send land charge to maintain-api. '
                'TraceID : {} - Status: {}, Message: {}'.format(
                    g.trace_id, response.status_code, response.text))
            AuditAPIService.audit_event(
                "Failed to send land charge to maintain-api",
                supporting_info={
                    'id': calc_display_id(land_charge.local_land_charge)
                })
            raise ApplicationError(500)

        result = response.json()

        current_app.logger.info(
            "User ID '{}' updated charge {}. Entry number: {}, registration date: {}.  TraceID={}"
            .format(g.session.user.id, result['land_charge_id'],
                    result['entry_number'], result['registration_date'],
                    g.trace_id))

        last_charge = LastCreatedCharge()
        last_charge.charge_id = result['land_charge_id']
        last_charge.entry_number = result['entry_number']
        last_charge.registration_date = datetime.strptime(
            result['registration_date'], "%Y-%m-%d").strftime("%d/%m/%Y")
        g.session.last_created_charge = last_charge
        g.session.commit()
 def test_audit_event_machine_ip_without_supporting_info(self, mock_socket):
     with main.app.test_request_context():
         mock_socket.gethostbyname.return_value = "1.1.1.1"
         self.mock_request()
         g.requests.post.return_value = self.mock_response(status_code=201)
         AuditAPIService.audit_event("A thing")
         g.requests.post.assert_called()
         message = json.loads(g.requests.post.call_args[1]['data'])
         self.assertIn('machine_ip', message['supporting_info'])
         self.assertEqual("1.1.1.1",
                          message['supporting_info']['machine_ip'])
         self.assertNotIn('another', message['supporting_info'])
    def test_audit_event_exception(self, mock_app, mock_socket):
        with main.app.test_request_context():
            mock_socket.gethostbyname.return_value = "1.1.1.1"
            self.mock_request()
            g.trace_id = '123'
            g.requests.post.side_effect = Exception('Test exception')

            try:
                AuditAPIService.audit_event("A thing")
            except ApplicationError as e:
                self.assertEqual(e.http_code, 500)
                return
            self.fail()
def cancel_charge(charge_id):
    current_app.logger.info("Endpoint called with charge_id='{}'".format(charge_id))
    local_land_charge_service = LocalLandChargeService(current_app.config)
    current_app.logger.info("Retrieving charge information from charge_id='{}'".format(charge_id))
    response = local_land_charge_service.get_by_charge_number(charge_id)
    if response.status_code == 404:
        current_app.logger.warning("Charge not found for charge_id='{}' - Returning not found".format(charge_id))
        raise ApplicationError(404)
    response.raise_for_status()

    charge_data = response.json()[0]['item']
    charge_item = LocalLandChargeItem.from_json(charge_data)

    # add the charge to the session for checking the geometry is within the user's authority
    g.session.add_charge_state = charge_item
    g.session.commit()

    current_app.logger.info("Charge information retrieved for charge_id='{}'".format(charge_id))
    if request.method == 'GET':
        # Check if the charge is outside of the user's authority
        extent = build_extents_from_features(charge_item.geometry)
        result = LocalAuthorityService(current_app.config).get_authorities_by_extent(extent)

        if should_show_confirmation_warning(result):
            # In this case the charge is outside of the user's authority
            if Permissions.add_extent_anywhere in g.session.user.permissions:
                # If the user has permission to add a charge anywhere, give them cancel permission without asking
                g.session.other_authority_cancel_permission = True
                g.session.commit()

            if not g.session.other_authority_cancel_permission:
                # if the user has not confirmed that they can edit charges outside of their authority, make them
                return redirect(url_for('cancel_land_charge.get_cancel_location_confirmation'))

        current_app.logger.info("Rendering response for charge_id='{}'".format(charge_id))
        return render_template('cancel.html', charge_id=charge_id, charge_item=charge_item,
                               geometry=json.dumps(charge_item.geometry))
    else:
        charge_item.end_date = date.today()
        current_app.logger.info("Updating charge with cancellation date for charge_id='{}'".format(charge_id))
        AuditAPIService.audit_event("Cancelling charge", supporting_info={'id': charge_id})
        if g.session.other_authority_cancel_permission:
            AuditAPIService.audit_event(
                "Charge cancelled outside users authority.",
                supporting_info={'originating-authority': g.session.user.organisation})
        MaintainApiService.update_charge(charge_item)
        current_app.logger.info("Rendering response for charge_id='{}'".format(charge_id))
        # This is required because if the render_template is called from this post method then the flow won't be able
        # to return to the confirmation page if the user goes to the feedback form from the confirmation page
        return redirect(url_for('cancel_land_charge.cancel_confirmation', charge_id=charge_id))
    def test_audit_event_non201(self, mock_app, mock_socket):
        with main.app.test_request_context():
            mock_socket.gethostbyname.return_value = "1.1.1.1"
            self.mock_request()
            g.trace_id = '123'
            g.requests.post.return_value = self.mock_response(
                status_code=500, text="Something went wrong")

            try:
                AuditAPIService.audit_event("A thing")
            except ApplicationError as e:
                self.assertEqual(e.http_code, 500)
                return
            self.fail()
def get_check_your_email():
    if g.session.two_factor_authentication_code is None and config.ENABLE_TWO_FACTOR_AUTHENTICATION:
        g.session.two_factor_authentication_code = two_factor_authentication_code_generator.generate_code(
        )
        g.session.two_factor_authentication_generation_time = get_current_timestamp_minutes(
        )
        g.session.two_factor_authentication_invalid_attempts = 0
        g.session.commit_2fa_state()

        NotificationAPIService.send_message_notify(
            g.session.user.email, config.NOTIFY_TWO_FACTOR_AUTH_TEMPLATE_ID,
            {'code': g.session.two_factor_authentication_code})

        AuditAPIService.audit_event("2FA code sent to user")

    return render_template('check_your_email.html')
示例#11
0
def modify_land_charge_confirm(charge_id):
    current_app.logger.info("Endpoint called - Updating charge")

    AuditAPIService.audit_event("Vary request submitted",
                                supporting_info={'id': charge_id})
    MaintainApiService.update_charge(g.session.add_lon_charge_state)

    g.session.add_lon_charge_state = None
    g.session.edited_fields = None
    g.session.commit()

    current_app.logger.info("Charge removed from session - Rendering Template")
    # This is required because if the render_template is called from this post method then the flow won't be able to
    # return to the confirmation page if the user goes to the feedback form from the confirmation page
    return redirect(
        url_for('modify_lon.modify_confirmation', charge_id=charge_id))
    def test_audit_event_timestamps(self, mock_socket):
        with main.app.test_request_context():
            mock_socket.gethostbyname.return_value = "1.1.1.1"
            self.mock_request()
            g.requests.post.return_value = self.mock_response(status_code=201)
            AuditAPIService.audit_event("A thing")
            call1 = g.requests.post.call_args
            args, kwargs = call1
            call1_timestamp = json.loads(kwargs['data'])['activity_timestamp']

            time.sleep(0.1)

            AuditAPIService.audit_event("A thing")
            call2 = g.requests.post.call_args
            args, kwargs = call2
            call2_timestamp = json.loads(kwargs['data'])['activity_timestamp']

            self.assertNotEqual(call1_timestamp, call2_timestamp)
示例#13
0
def confirm(charge_id):
    local_land_charge_service = LocalLandChargeService(current_app.config)
    display_id, charge_item = get_lon_by_charge_id(charge_id,
                                                   local_land_charge_service)

    if request.method == 'GET':
        return render_template('cancel_lon_confirm.html',
                               charge_id=display_id,
                               charge_item=charge_item,
                               geometry=json.dumps(charge_item.geometry))
    if request.method == 'POST':
        current_app.logger.info("Cancelling Charge - {}".format(display_id))
        AuditAPIService.audit_event("Cancelling charge",
                                    supporting_info={'id': display_id})
        MaintainApiService.update_charge(g.session.add_lon_charge_state)
        # This is required because if the render_template is called from this post method then the flow won't be able
        # to return to the confirmation page if the user goes to the feedback form from the confirmation page
        return redirect(
            url_for('cancel_lon.charge_cancelled', charge_id=display_id))
示例#14
0
def modify_land_charge_confirm():
    current_app.logger.info("Endpoint called - Updating charge")
    AuditAPIService.audit_event(
        "Vary request submitted.",
        supporting_info={
            'id': calc_display_id(g.session.add_charge_state.local_land_charge)
        })
    if g.session.charge_added_outside_users_authority:
        AuditAPIService.audit_event(
            "Charge location varied, extent(s) modified to be outside users authority.",
            supporting_info={
                'originating-authority': g.session.user.organisation,
                'id':
                calc_display_id(g.session.add_charge_state.local_land_charge)
            })
    if g.session.other_authority_update_permission:
        AuditAPIService.audit_event(
            "Charge location varied, extent(s) modified on a charge outside users authority.",
            supporting_info={
                'originating-authority': g.session.user.organisation,
                'id':
                calc_display_id(g.session.add_charge_state.local_land_charge)
            })
    MaintainApiService.update_charge(g.session.add_charge_state)
    charge_id = calc_display_id(g.session.add_charge_state.local_land_charge)
    g.session.add_charge_state = None
    g.session.edited_fields = None
    g.session.charge_added_outside_users_authority = None
    g.session.other_authority_update_permission = None
    g.session.other_authority_cancel_permission = None
    g.session.commit()
    current_app.logger.info("Charge removed from session - Rendering Template")
    return render_template('modify_confirmation.html', charge_id=charge_id)
示例#15
0
def post_review():
    current_app.logger.info('Endpoint called')

    g.session.redirect_route = None
    g.session.edited_fields = {}
    g.session.commit()

    if g.session.add_lon_charge_state is None:
        current_app.logger.info('Redirecting to: {}'.format(url_for('add_lon.new')))
        return redirect(url_for('add_lon.new'))

    redirect_url = url_for('add_lon.get_confirmation')
    current_app.logger.info('Redirecting to next step: {}'.format(redirect_url))

    submit_token = request.form.get('csrf_token')

    if submit_token != g.session.submit_token:
        g.session.submit_token = submit_token
        g.session.commit()
        AuditAPIService.audit_event("Submitting the charge", supporting_info=g.session.add_lon_charge_state.to_json())
        MaintainApiService.add_charge(g.session.add_lon_charge_state)
        AuditAPIService.audit_event("Charge created", supporting_info={'id': g.session.last_created_charge.charge_id})

    # Audit the LON payment method
    '''if g.session.payment_info.payment_method == 'govuk':
        AuditAPIService.audit_event("Payment made via GOV.UK Pay",
                                    supporting_info={'reference': g.session.payment_info.payment_ref,
                                                     'charge_id': g.session.last_created_charge.charge_id})
    elif g.session.payment_info.payment_method == 'cheque':
        AuditAPIService.audit_event("Payment made by cheque",
                                    supporting_info={'charge_id': g.session.last_created_charge.charge_id}
                                    )
    else:
        AuditAPIService.audit_event("No payment needed",
                                    supporting_info={'explanation': g.session.payment_info.no_payment_notes,
                                                     'charge_id': g.session.last_created_charge.charge_id})'''

    return redirect(redirect_url)
def llc1_get_result():
    current_app.logger.info('Endpoint called')
    if g.session.llc1_state is None:
        current_app.logger.info('Redirecting to: %s',
                                url_for("create_llc1.create_llc1"))
        return redirect(url_for("create_llc1.create_llc1"))

    current_app.logger.info("Calling LLC1 Document API")
    AuditAPIService.audit_event(
        "User submitted an LLC Official Search request")
    document_service = LLC1DocumentService(current_app.config)
    response = document_service.generate(g.session.llc1_state.description,
                                         g.session.llc1_state.extent)

    ReportAPIService.send_number_of_charges_per_search_data({
        'date':
        datetime.now(timezone.utc).isoformat(),
        'channel':
        'MAINTAIN',
        'number_of_charges':
        response['number_of_charges'],
        # TODO(): Update once repeat searches are added to the Maintain service to check if
        # this is a repeat search
        'repeat':
        False
    })

    current_app.logger.info("Adding LLC1 URL to session state")
    g.session.llc1_state.llc1_url = response['document_url']
    g.session.llc1_state.external_llc1_url = response['external_url']
    g.session.commit()

    current_app.logger.info("Render template 'search_result.html'")
    return render_template(
        'search_result.html',
        url=g.session.llc1_state.external_llc1_url,
        supporting_documents=response.get('supporting_documents'))
def post_review():
    current_app.logger.info('Endpoint called')

    g.session.redirect_route = None
    g.session.edited_fields = []
    g.session.commit()

    if g.session.add_charge_state is None:
        current_app.logger.info('Redirecting to: {}'.format(
            url_for('add_land_charge.new')))
        return redirect(url_for('add_land_charge.new'))

    redirect_url = url_for('add_land_charge.get_confirmation')
    current_app.logger.info(
        'Redirecting to next step: {}'.format(redirect_url))

    submit_token = request.form.get('csrf_token')

    if submit_token != g.session.submit_token:
        g.session.submit_token = submit_token
        g.session.commit()

        added_outside_users_authority = g.session.charge_added_outside_users_authority

        if added_outside_users_authority:
            g.session.charge_added_outside_users_authority = None
            g.session.commit()

        AuditAPIService.audit_event(
            "Submitting the charge",
            supporting_info=g.session.add_charge_state.to_json())
        MaintainApiService.add_charge(g.session.add_charge_state)

        if added_outside_users_authority:
            AuditAPIService.audit_event(
                "Charge added outside users authority.",
                supporting_info={
                    'originating-authority': g.session.user.organisation,
                    'id': g.session.last_created_charge.charge_id
                })

        AuditAPIService.audit_event(
            "Charge created",
            supporting_info={'id': g.session.last_created_charge.charge_id})

    return redirect(redirect_url)
def post_check_your_email():
    # Make sure a code and generation time has actually been set
    if g.session.two_factor_authentication_code is None or \
            g.session.two_factor_authentication_generation_time is None:
        return redirect(
            url_for('two_factor_authentication.get_check_your_email'))

    code = request.form.get('code')
    validation_errors = TwoFactorAuthenticationValidator.validate(code)
    if 'code' in validation_errors.errors:
        # Log user out after 3 incorrect attempts
        AuditAPIService.audit_event('Invalid entry of 2FA code')

        if g.session.two_factor_authentication_invalid_attempts and \
                g.session.two_factor_authentication_invalid_attempts >= 2:
            AuditAPIService.audit_event('2FA code attempt limits exceeded')
            return redirect('/logout')

        if g.session.two_factor_authentication_invalid_attempts:
            g.session.two_factor_authentication_invalid_attempts = \
                g.session.two_factor_authentication_invalid_attempts + 1
        else:
            g.session.two_factor_authentication_invalid_attempts = 1

        g.session.commit_2fa_state()

        return render_template(
            'check_your_email.html',
            validation_errors=validation_errors.errors,
            validation_summary_heading=validation_errors.summary_heading_text,
        ), 400

    # Check code hasn't expired and that it matches
    if (get_current_timestamp_minutes() - g.session.two_factor_authentication_generation_time) < 10 and \
            str(code) == str(g.session.two_factor_authentication_code):
        g.session.two_factor_authentication_passed = True
        g.session.commit_2fa_state()
        AuditAPIService.audit_event('User successfully passed 2FA')
        return redirect(g.session.two_factor_authentication_redirect_url)

    AuditAPIService.audit_event('Invalid entry of 2FA code')

    # Log user out after 3 incorrect attempts
    if g.session.two_factor_authentication_invalid_attempts and \
            g.session.two_factor_authentication_invalid_attempts >= 2:
        AuditAPIService.audit_event('2FA code attempt limits exceeded')
        return redirect('/logout')

    if g.session.two_factor_authentication_invalid_attempts:
        g.session.two_factor_authentication_invalid_attempts = g.session.two_factor_authentication_invalid_attempts + 1
    else:
        g.session.two_factor_authentication_invalid_attempts = 1

    g.session.commit_2fa_state()

    # Generate error for incorrect / expired code
    validation_errors = TwoFactorAuthenticationValidator.generate_invalid_code_error_message(
    )

    return render_template(
        'check_your_email.html',
        validation_errors=validation_errors.errors,
        validation_summary_heading=validation_errors.summary_heading_text,
    ), 400