def history(charge_id): llc_service = LocalLandChargeService(current_app.config) validate_charge_id(charge_id) history_response = llc_service.get_history_for_charge(charge_id) search_response = llc_service.get_by_charge_number(charge_id) if history_response.status_code == 404 or search_response.status_code == 404: current_app.logger.warning("Charge not found for charge_id='{}' - Returning not found".format(charge_id)) raise ApplicationError(404) if history_response.status_code == 500 or search_response.status_code == 500: current_app.logger.error("Server error occurred when getting details for charge_id''{}".format(charge_id)) raise ApplicationError(500) history_response.raise_for_status() search_response.raise_for_status() history_items = list(reversed(LocalLandChargeHistoryItem.from_json(history_response.json()))) charge_data = search_response.json()[0]['item'] land_charge = LocalLandChargeItem.from_json(charge_data) return render_template('view_charge_history.html', charge_id=charge_id, history=history_items, local_land_charge=land_charge, format_date_bst=DateFormatter.format_date_bst)
def test_modify_confirm_charge_inside_authority(self, mock_maintain_api_service, mock_audit): self.client.set_cookie('localhost', Session.session_cookie_name, 'cookie_value') self.mock_session.return_value.user.permissions = [ Permissions.vary_llc ] self.mock_session.return_value.charge_added_outside_users_authority = False self.mock_session.return_value.other_authority_update_permission = False state = LocalLandChargeItem.from_json(local_land_charge_1) self.mock_session.return_value.add_charge_state = state response = self.client.post( url_for('modify_land_charge.modify_land_charge_confirm')) self.assert_status(response, 200) self.assert_template_used('modify_confirmation.html') self.assert_context( 'charge_id', 'LLC-{}'.format(local_land_charge_1['local-land-charge'])) for calls in mock_audit.mock_calls: self.assertNotEqual( calls[1], "Charge location varied, extent(s) modified to be outside users authority." )
def test_modify_redirect_when_different_id_in_session( self, mock_llc_service, mock_features, mock_la_service): self.client.set_cookie('localhost', Session.session_cookie_name, 'cookie_value') self.mock_session.return_value.user.permissions = [ Permissions.vary_llc ] mock_la_service.return_value.get_authorities_by_extent.return_value = [ 'test' ] state = LocalLandChargeItem.from_json(local_land_charge_1) self.mock_session.return_value.add_charge_state = state charge_id_from_url = 'LLC-98765' mock_response = MagicMock() mock_llc_service.return_value.get_by_charge_number.return_value = mock_response mock_response.status_code = 200 mock_llc_service.return_value.get_history_for_charge.return_value = mock_response mock_response.status_code = 200 mock_response.json.return_value = [{ "item": local_land_charge_2, "display_id": charge_id_from_url, "cancelled": False }] response = self.client.get( url_for('modify_land_charge.modify_land_charge', local_land_charge=charge_id_from_url)) self.assert_status(response, 200) mock_llc_service.return_value.get_by_charge_number.assert_called_with( charge_id_from_url)
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))
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_modify_confirm_charge_outside_authority(self, mock_maintain_api_service, mock_audit): self.client.set_cookie('localhost', Session.session_cookie_name, 'cookie_value') self.mock_session.return_value.user.permissions = [ Permissions.vary_llc ] self.mock_session.return_value.user.organisation = 'test org' self.mock_session.return_value.charge_added_outside_users_authority = True self.mock_session.return_value.other_authority_update_permission = False state = LocalLandChargeItem.from_json(local_land_charge_1) self.mock_session.return_value.add_charge_state = state response = self.client.post( url_for('modify_land_charge.modify_land_charge_confirm')) self.assert_status(response, 200) self.assert_template_used('modify_confirmation.html') self.assert_context( 'charge_id', 'LLC-{}'.format(local_land_charge_1['local-land-charge'])) expected_call = [ call("Vary request submitted.", supporting_info={ 'id': calc_display_id(local_land_charge_1['local-land-charge']) }), call( "Charge location varied, extent(s) modified to be outside users authority.", supporting_info={ 'originating-authority': self.mock_session.return_value.user.organisation, 'id': calc_display_id(local_land_charge_1['local-land-charge']) }) ] mock_audit.audit_event.assert_has_calls(expected_call)
def test_put_update_land_charge_validation_error(self, mock_app, mock_audit): with main.app.test_request_context(): g.requests = MagicMock() g.trace_id = '123' g.session = self.mock_session response = MagicMock() response.status_code = 500 response.text = "response" g.requests.put.return_value = response try: MaintainApiService.update_charge(LocalLandChargeItem.from_json(s8)) except Exception as ex: self.assertEqual(ex.http_code, 500) mock_app.logger.exception.assert_called() mock_app.logger.exception.assert_called_with( 'Failed to send land charge to maintain-api. TraceID : 123 - Status: 500, Message: response') mock_audit.audit_event.assert_called_with('Failed to send land charge to maintain-api', supporting_info={ 'id': calc_display_id(s8['local-land-charge']) }) return self.fail()
def test_put_update_land_charge_success(self, mock_app): with main.app.test_request_context(): g.requests = MagicMock() g.trace_id = '123' g.session = self.mock_session user = User() user.username = "******" self.mock_session = user response = MagicMock() response.status_code = 202 response.json.return_value = { "entry_number": "1", "land_charge_id": "4", "registration_date": "2012-12-12" } response.text = 'Success' g.requests.put.return_value = response MaintainApiService.update_charge(LocalLandChargeItem.from_json(s8)) self.assertIsNotNone(g.session.last_created_charge) self.assertEqual(g.session.last_created_charge.charge_id, "4") self.assertEqual(g.session.last_created_charge.registration_date, "12/12/2012") self.assertEqual(g.session.last_created_charge.entry_number, "1") self.assertEqual(g.requests.put.call_count, 1)
def populate_state(self): """Populates the add charge from session state.""" current_app.logger.info( "Method called, getting session state from session api") response = SessionAPIService.get_session_state( self.session_key, Session.session_state_key) if response is not None: current_app.logger.info("Non-empty session state contents") if 'add_charge_state' in response: current_app.logger.info("add_charge_state in session state") self.add_charge_state = LocalLandChargeItem.from_json( response['add_charge_state']) if 'add_lon_charge_state' in response: current_app.logger.info( "add_lon_charge_state in session state") self.add_lon_charge_state = LightObstructionNoticeItem.from_json( response['add_lon_charge_state']) if 'last_created_charge' in response: current_app.logger.info("last_created_charge in session state") self.last_created_charge = LastCreatedCharge.from_dict( response['last_created_charge']) if 'statutory_provision_list' in response: current_app.logger.info( "statutory_provision_list in session state") self.statutory_provision_list = response[ 'statutory_provision_list'] if 'edited_fields' in response: current_app.logger.info("edited_fields in session state") self.edited_fields = response['edited_fields'] if 'llc1_state' in response: current_app.logger.info("llc1_state in session state") self.llc1_state = LLC1Search.from_json(response['llc1_state']) if 'redirect_route' in response: current_app.logger.info('redirect_route in session state') self.redirect_route = response['redirect_route'] if 'search_extent' in response: current_app.logger.info('search_extent in session state') self.search_extent = response['search_extent'] if 'filenames' in response: current_app.logger.info('filenames in session state') self.filenames = response['filenames'] if 'previously_selected_address' in response: current_app.logger.info( 'previously_selected_address in session state') self.previously_selected_address = response[ 'previously_selected_address'] if 'adding_charge_for_other_authority' in response: current_app.logger.info( 'adding_charge_for_other_authority in session state') self.adding_charge_for_other_authority = response[ 'adding_charge_for_other_authority'] if 'submit_token' in response: current_app.logger.info('submit token in session state') self.submit_token = response['submit_token'] if 'upload_shapefile_processed' in response: current_app.logger.info( 'upload_shapefile_processed in session state') self.upload_shapefile_processed = response[ 'upload_shapefile_processed'] if 'category_details' in response: self.category_details = Category.from_dict( response['category_details']) if 'category_confirmation' in response: self.category_confirmation = response['category_confirmation'] if 'charge_added_outside_users_authority' in response: self.charge_added_outside_users_authority = response[ 'charge_added_outside_users_authority'] if 'other_authority_update_permission' in response: self.other_authority_update_permission = response[ 'other_authority_update_permission'] if 'other_authority_cancel_permission' in response: self.other_authority_cancel_permission = response[ 'other_authority_cancel_permission'] if 'source_information' in response: self.source_information = response['source_information'] if 'source_information_id' in response: self.source_information_id = response['source_information_id'] if 'send_payment_link_info' in response: current_app.logger.info( "send_payment_link_info in session state") self.send_payment_link_info = PaymentLink.from_json( response['send_payment_link_info']) if 'payment_info' in response: current_app.logger.info("payment_info in session state") self.payment_info = PaymentInfo.from_json( response['payment_info']) if 'search_details' in response: self.search_details = SearchDetails.from_json( response['search_details'])
def modify_land_charge(local_land_charge): current_app.logger.info( "Endpoint called with local_land_charge='{}'".format( local_land_charge)) validate_charge_id(local_land_charge) local_land_charge_service = LocalLandChargeService(current_app.config) response = local_land_charge_service.get_by_charge_number( local_land_charge) if response.status_code == 404: current_app.logger.warning( "Charge not found for local_land_charge='{}' - Returning not found" .format(local_land_charge)) raise ApplicationError(404) response.raise_for_status() updated, updated_date = get_history_update_info_by_charge_id( local_land_charge, local_land_charge_service) if not g.session.add_charge_state: current_app.logger.info( "Retrieving charge with local_land_charge='{}'".format( local_land_charge)) # If the charge does not exist in the session, load it from the database, otherwise we are in the # process of updating it and as such it should be loaded from the session data charge_data = response.json()[0]['item'] charge_item = LocalLandChargeItem.from_json(charge_data) current_app.logger.info( "Charge information retrieved for local_land_charge='{}' - Updating session charge" .format(local_land_charge)) g.session.add_charge_state = charge_item g.session.edited_fields = [] g.session.commit() current_app.logger.info("Session charge updated - Rendering Template") else: charge_id = calc_display_id( g.session.add_charge_state.local_land_charge) current_app.logger.info('charge_id: {}'.format(charge_id)) current_app.logger.info( 'local_land_charge: {}'.format(local_land_charge)) # Check that charge ID in session and URL match. # If they don't, redirect user to the charge ID they entered and clear session if charge_id != local_land_charge: g.session.add_charge_state = None g.session.edited_fields = None g.session.commit() return modify_land_charge(local_land_charge) charge_item = g.session.add_charge_state current_app.logger.info("Session charge updated - Rendering Template") # Check that charge hasn't been cancelled in case user attempts to navigate to update URL manually if charge_item.end_date: current_app.logger.error( 'Attempted to update a cancelled charge. Charge ID: {}'.format( local_land_charge)) raise ApplicationError(500) # Check if the charge is outside of the user's authority, if user hasn't already updated the map if not g.session.charge_added_outside_users_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 update permission without asking g.session.other_authority_update_permission = True g.session.commit() if not g.session.other_authority_update_permission: # if the user has not confirmed that they can edit charges outside of their authority, make them return redirect( url_for( 'modify_land_charge.get_update_location_confirmation')) return render_template('modify_charge.html', charge_item=charge_item, updated=updated, updated_date=updated_date, charge_id=response.json()[0]['display_id'], geometry=json.dumps(charge_item.geometry), edited_fields=get_ordered_edited_fields( g.session.edited_fields, ReviewMap), map=ReviewMap)