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 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 process(self, search_query): local_land_charge_service = LocalLandChargeService(self.config) if self.search_valid(search_query, CHARGE_NUMBER_REGEX): self.logger.info("Searching by charge ID: %s", search_query) response = local_land_charge_service.get_by_charge_number(search_query) else: self.logger.info("Searching by reference number: %s", search_query) response = local_land_charge_service.get_by_reference_number(search_query) return self.process_search_response(response)
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 modify_lon_details_get(charge_id): current_app.logger.info( "Endpoint called with charge_id='{}'".format(charge_id)) # If the charge not in session, redirect to initial upload screen if not g.session.add_lon_charge_state: return redirect( url_for("modify_lon.modify_lon_upload_get", charge_id=charge_id)) session_charge_id = calc_display_id( g.session.add_lon_charge_state.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 session_charge_id != charge_id: g.session.add_lon_charge_state = None g.session.commit() return redirect( url_for("modify_lon.modify_lon_upload_get", charge_id=charge_id)) # Retrieve Light Obstruction Notice Item local_land_charge_service = LocalLandChargeService(current_app.config) charge_item = g.session.add_lon_charge_state updated, updated_date = get_history_update_info_by_charge_id( charge_id, local_land_charge_service) return render_template("modify_lon_details.html", charge_id=charge_id, charge_item=charge_item, updated=updated, updated_date=updated_date, geometry=json.dumps(charge_item.geometry))
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_get_with_bounding_box(self, mock_current_app): with main.app.test_request_context(): g.requests = MagicMock() response = MagicMock() response.status_code = 200 response.json.return_value = {'results': [{"abc": "def"}]} g.requests.post.return_value = response search_api = 'abc' mock_current_app.config = {'SEARCH_API_URL': search_api} local_land_charge_service = LocalLandChargeService(mock_current_app.config) response = local_land_charge_service.get(BASE64_BOUNDING_BOX) self.assertEqual(response.status_code, 200) g.requests.post.assert_called_with( "http://{}/v2.0/search/local_land_charges".format(search_api), data=BASE64_BOUNDING_BOX, headers={'Content-Type': 'application/json'} )
def test_get_history_for_charge(self, mock_current_app): with main.app.test_request_context(): g.requests = MagicMock() response = MagicMock() response.status_code = 200 response.json.return_value = {'results': [{"abc": "def"}]} g.requests.get.return_value = response search_api = 'abc' mock_current_app.config = {'SEARCH_API_URL': search_api} charge_number = 'LLC-1' local_land_charge_service = LocalLandChargeService(mock_current_app.config) response = local_land_charge_service.get_history_for_charge(charge_number) self.assertEqual(response.status_code, 200) g.requests.get.assert_called_with( "http://{}/v2.0/search/local_land_charges/{}/history".format( search_api, charge_number), params=None )
def modify_lon_upload_get(charge_id): current_app.logger.info( "Endpoint called with charge_id='{}'".format(charge_id)) local_land_charge_service = LocalLandChargeService(current_app.config) # Retrieve Light Obstruction Notice Item display_id, charge_item = get_lon_by_charge_id(charge_id, local_land_charge_service) g.session.edited_fields = {} g.session.commit() # 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( charge_id)) raise ApplicationError(500) # If the charge is in session we are in the process of updating it if not g.session.add_lon_charge_state: g.session.add_lon_charge_state = charge_item g.session.commit() current_app.logger.info("Session charge updated - Rendering Template") return render_template('modify_lon_upload.html', charge_id=display_id, charge_item=charge_item) else: session_charge_id = calc_display_id( g.session.add_lon_charge_state.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 session_charge_id != display_id: g.session.add_lon_charge_state = None g.session.commit() return redirect( url_for("modify_lon.modify_lon_upload_get", charge_id=charge_id)) return render_template('modify_lon_upload.html', charge_id=display_id, charge_item=charge_item)
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))
def cancel_post(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) cancel_options = request.form.getlist('cancel-options') form_b = request.files.get('form-b-cancel-lon-file-input') court_order = request.files.get('court-order-cancel-lon-file-input') current_app.logger.info("Running validation") validation_error_builder = CancelLonValidator.validate( request.form, request.files) if validation_error_builder.errors: current_app.logger.warning("Validation errors occurred") return render_template( 'cancel_lon.html', charge_id=display_id, validation_errors=validation_error_builder.errors, validation_summary_heading=validation_error_builder. summary_heading_text, request_body=request.form), 400 files_to_upload = {} if "Form B" in cancel_options and form_b: files_to_upload['form-b'] = ('form_b.pdf', form_b, form_b.content_type) if "Court Order" in cancel_options and court_order: files_to_upload['court-order'] = ("court_order.pdf", court_order, court_order.content_type) if files_to_upload: upload_files(files_to_upload, charge_item, charge_id) charge_item.end_date = date.today() g.session.add_lon_charge_state = charge_item g.session.commit() return redirect(url_for('cancel_lon.confirm', charge_id=charge_id))
class SearchByArea(object): def __init__(self, logger, config): self.logger = logger self.local_land_charge_service = LocalLandChargeService(config) def process(self, bounding_box): response = dict() search_response = self.process_request(bounding_box) response['status'] = search_response.status_code if search_response.status_code == 200: response['data'] = search_response.json() return response def process_request(self, bounding_box): if bounding_box: return self.get_results_for_boundary(bounding_box) def get_results_for_boundary(self, bounding_box): self.logger.info("Searching area by bounding box") return self.local_land_charge_service.get( self.prepare_bounding_box(bounding_box)) @staticmethod def prepare_bounding_box(bounding_box): return SearchByArea.build_bounding_box_json(bounding_box) @staticmethod def build_bounding_box_json(bounding_box): geo_dict = { "type": "Polygon", "coordinates": json.loads(bounding_box), "crs": { "type": "name", "properties": { "name": "EPSG:27700" } } } return json.dumps(geo_dict)
def modify_lon_upload_post(charge_id): # Retrieve Charge local_land_charge_service = LocalLandChargeService(current_app.config) display_id, charge_item = get_lon_by_charge_id(charge_id, local_land_charge_service) validation_error_builder = VaryLonValidator.validate( request.form, request.files) if validation_error_builder.errors: current_app.logger.warning("Validation errors occurred") return render_template( 'modify_lon_upload.html', charge_id=display_id, charge_item=charge_item, validation_errors=validation_error_builder.errors, validation_summary_heading=validation_error_builder. summary_heading_text, request_body=request.form), 400 handle_vary_lon_options_choice(charge_id, charge_item) return redirect( url_for('modify_lon.modify_lon_details_get', charge_id=charge_id))
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)
def cancel_get(charge_id): # Retrieve Charge local_land_charge_service = LocalLandChargeService(current_app.config) display_id, charge_item = get_lon_by_charge_id(charge_id, local_land_charge_service) return render_template('cancel_lon.html', charge_id=display_id)
def __init__(self, logger, config): self.logger = logger self.local_land_charge_service = LocalLandChargeService(config)