2021-11-18 11:06:21 +13:00
import csv
2023-02-21 16:43:46 +13:00
from io import StringIO
from os . path import splitext
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
from . filters import is_in_christchurch , is_in_auckland
from . models import EcologicalDistrictLayer , SoilOrder , Questionnaire , ActivationKey
from . wms_utils import get_address_from_coordinates
2021-11-18 11:06:21 +13:00
import pdfkit
import pandas as pd
from PyPDF2 import PdfFileMerger
2023-02-21 16:43:46 +13:00
from django . core . files . storage import get_storage_class
Storage = get_storage_class ( )
storage = Storage ( )
2021-11-18 11:06:21 +13:00
CSV_FILENAME = ' plants.csv '
PLANTING_GUIDE_PDF_FILENAME = ' planting_guide.pdf '
HEADER_FIELDS = [ ' Names ' , ' Growth Form / Max Height (m) / Spacing (m) / Forest Position ' , ' Moisture Preferences ' ,
' Tolerances (Water / Drought / Frost / Salinity) ' , ' Ecosystem Services ' , ' Carbon Sequestration Rate ' , ' Planting Stage ' ]
2023-04-20 14:59:00 +12:00
def get_location_filters ( questionnaire ) :
2021-11-18 11:06:21 +13:00
""" Retrives the selected location data from the request.
"""
2021-11-23 14:16:52 +13:00
filter_rows = [ [ ' LOCATION FILTERS: ' , ' ' ] ]
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
eco_district_layer = EcologicalDistrictLayer . objects . filter ( geom__intersects = questionnaire . location ) . first ( )
address = get_address_from_coordinates ( questionnaire . location )
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
filter_rows . append ( [ ' Point coordinates: ' , questionnaire . location ] )
2023-04-20 15:12:22 +12:00
filter_rows . append ( [ ' Ecological region: ' , eco_district_layer . ecologic_1 or ' ' ] )
2023-04-20 14:59:00 +12:00
filter_rows . append ( [ ' Ecological district: ' , eco_district_layer . ecologic_2 or ' ' ] )
filter_rows . append ( [ ' Property address: ' , address [ ' full_address ' ] if address is not None else ' ' ] )
2021-11-18 11:06:21 +13:00
return filter_rows
2023-04-20 14:59:00 +12:00
def get_soil_filters ( questionnaire ) :
2023-02-21 16:43:46 +13:00
""" Retrives the selected soil type data from the request params.
2021-11-18 11:06:21 +13:00
"""
2021-11-23 14:16:52 +13:00
filter_rows = [ [ ' SOIL FILTERS: ' , ' ' ] ]
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
soil_order = SoilOrder . objects . filter ( soillayer__geom__intersects = questionnaire . location ) . first ( )
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
filter_rows . append ( [ ' Soil Order: ' , f " { soil_order . name or ' ' } ( { soil_order . code or ' ' } ) " ] )
filter_rows . append ( [ ' Soil Variant: ' , questionnaire . soil_variant ] )
2021-11-18 11:06:21 +13:00
return filter_rows
2023-04-20 14:59:00 +12:00
def get_site_filters ( questionnaire ) :
2023-02-21 16:43:46 +13:00
""" Retrives the selected site data from the request params
2021-11-18 11:06:21 +13:00
"""
2021-11-23 14:16:52 +13:00
filter_rows = [ [ ' SITE FILTERS: ' , ' ' ] ]
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
zone = questionnaire . zone
habitat = zone . habitat
filter_rows . append ( [ ' Habitat: ' , habitat . name ] )
filter_rows . append ( [ ' Zone Name: ' , zone . name ] )
filter_rows . append ( [ ' Zone Variant: ' , zone . variant ] )
filter_rows . append ( [ ' Zone Refined Variant: ' , zone . refined_variant ] )
2021-11-18 11:06:21 +13:00
return filter_rows
2023-04-20 14:59:00 +12:00
def get_additional_region_info ( questionnaire ) :
2021-12-01 10:06:30 +13:00
""" If the location coordinates fall within the CHCH or Auckland regions then return a description of where to find more information.
"""
2023-04-20 14:59:00 +12:00
if is_in_christchurch ( questionnaire . location ) :
return [ [ " Your location falls within the ecosystem type covered by the Christchurch Council ecosystem maps - further information can be obtained from Ōtautahi/Christchurch ecosystems map link to: https://ccc.govt.nz/environment/land/ecosystem-map " , " " ] , [ ' ' , ' ' ] ]
elif is_in_auckland ( questionnaire . location ) :
return [ [ " Your location falls within the ecosystem type covered by the Auckland Council Tiaki Tāmaki Makaurau Conservation map - further information can be obtained from tiaki Tāmaki Makaurau conservation Auckland - link to https://www.tiakitamakimakaurau.nz/conservation-map/ " , " " ] , [ ' ' , ' ' ] ]
2023-02-21 16:43:46 +13:00
2021-12-01 10:06:30 +13:00
return [ ]
2023-04-20 15:12:22 +12:00
2023-02-21 16:43:46 +13:00
def get_filter_values ( params ) :
""" Retrives all selected values/filters from the request parameters
2021-11-18 11:06:21 +13:00
"""
filter_rows = [ ]
2023-04-20 14:59:00 +12:00
try :
ak = ActivationKey . objects . get ( key = params . get ( " key " , " " ) )
q = Questionnaire . objects . get ( key = ak )
except ( ActivationKey . DoesNotExist , Questionnaire . DoesNotExist ) :
return filter_rows
2021-11-18 11:06:21 +13:00
# Add all the location filters
2023-04-20 14:59:00 +12:00
filter_rows + = get_location_filters ( q )
2021-11-23 14:16:52 +13:00
filter_rows . append ( [ ' ' , ' ' ] )
2021-11-18 11:06:21 +13:00
# Add the soil filters
2023-04-20 14:59:00 +12:00
filter_rows + = get_soil_filters ( q )
2021-11-23 14:16:52 +13:00
filter_rows . append ( [ ' ' , ' ' ] )
2021-11-18 11:06:21 +13:00
# Add the project site filters
2023-04-20 14:59:00 +12:00
filter_rows + = get_site_filters ( q )
2021-11-23 14:16:52 +13:00
filter_rows . append ( [ ' ' , ' ' ] )
2021-11-18 11:06:21 +13:00
2023-04-20 14:59:00 +12:00
filter_rows + = get_additional_region_info ( q )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
return filter_rows
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
def generate_csv ( data : list [ list [ str ] ] , output_filename : str ) - > str :
with storage . open ( output_filename , ' w ' ) as f :
csv . writer ( f ) . writerows ( data )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
return storage . path ( output_filename )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
def generate_pdf ( data : list [ list [ str ] ] , output_filename : str ) :
""" Generates a pdf from a csv given data and a csv generation method.
Requires an html file to be generated as an intermediate step .
2021-11-18 11:06:21 +13:00
"""
2023-02-21 16:43:46 +13:00
name , _ = splitext ( output_filename )
csv_filepath = generate_csv ( data , f " { name } .csv " )
pdf_filepath = storage . path ( output_filename )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
with StringIO ( ) as html_buf :
# Convert csv to html
pd . read_csv ( csv_filepath ) . to_html ( html_buf ) # reading from buffer causes segfault :/
html_buf . seek ( 0 )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
# Convert html to pdf
pdfkit . from_file ( html_buf , pdf_filepath )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
return pdf_filepath
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
def merge_pdfs ( pdfs : list [ str ] , output_filename ) :
""" Merge a list of PDF filenames """
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
output_filepath = storage . path ( output_filename )
merger = PdfFileMerger ( )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
for pdf in pdfs :
merger . append ( pdf )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
merger . write ( output_filepath )
merger . close ( )
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
return output_filepath
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
def serialize_plants_queryset ( plants_queryset ) :
return [ HEADER_FIELDS ] + [
[
plant . display_name ,
plant . display_growth_form ,
plant . moisture_preferences ,
plant . plant_tolerances ,
plant . ecosystem_services ,
plant . carbon_sequestration ,
plant . stage
] for plant in plants_queryset
]
2021-11-18 11:06:21 +13:00
2023-02-21 16:43:46 +13:00
def create_planting_guide_pdf ( filter_data , plant_data , output_filename ) :
""" Creates a planting guide pdf document with a pre-generated planting guide with
filter and plant list tabular informtation appended .
"""
# TODO: space values appear as NaN... this should be fixed
return merge_pdfs (
[
storage . path ( PLANTING_GUIDE_PDF_FILENAME ) ,
generate_pdf ( filter_data , f " { output_filename } .filters " ) ,
generate_pdf ( plant_data , f " { output_filename } .plants " ) ,
] ,
output_filename ,
)