diff --git a/api/app/__init__.py b/api/app/__init__.py
index fd4538b4..6a74460a 100644
--- a/api/app/__init__.py
+++ b/api/app/__init__.py
@@ -1,17 +1,21 @@
-from flask import Flask, g
import logging.config
-import sys
import os
-sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
-from flask_cors import CORS
-from flask_sqlalchemy import SQLAlchemy
-import pika
+import sys
import uuid
-from celery import Celery
+
+import pika
from app.decorators.restplus import api as api_rest_plus
+from celery import Celery
+from flask import Flask, g
+from flask_cors import CORS
from flask_login import LoginManager
from flask_mail import Mail
+from flask_sqlalchemy import SQLAlchemy
+
+from . import constants
+
+sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
"""__________________________________producer for COMPUTE_______________________________________________________"""
@@ -67,7 +71,6 @@ def is_calculation_module_alive(self,cm_id):
-from . import constants
dbGIS = SQLAlchemy()
diff --git a/api/app/api_v1/__init__.py b/api/app/api_v1/__init__.py
index 06835627..307a630d 100644
--- a/api/app/api_v1/__init__.py
+++ b/api/app/api_v1/__init__.py
@@ -1,12 +1,15 @@
from flask import Blueprint
-api = Blueprint('api', __name__, url_prefix='/api')
-from .stats import nsStats
-from .heat_load_profile import load_profile_namespace
+
from ..decorators import etag
+from . import computation_module
from .computation_module import nsCM
-from .users import nsUsers
-from .upload import nsUpload
+from .heat_load_profile import load_profile_namespace
from .snapshot import nsSnapshot
+from .stats import nsStats
+from .upload import nsUpload
+from .users import nsUsers
+
+api = Blueprint('api', __name__, url_prefix='/api')
@api.before_request
def before_request():
@@ -21,5 +24,4 @@ def after_request(rv):
return rv
-from . import computation_module
# from . import computation, errors
diff --git a/api/app/api_v1/computation_module.py b/api/app/api_v1/computation_module.py
index 2f0e47ce..113e1bd8 100644
--- a/api/app/api_v1/computation_module.py
+++ b/api/app/api_v1/computation_module.py
@@ -1,37 +1,33 @@
-from celery.task.control import revoke
-
+import json
+import os
import signal
-from flask import request, current_app,jsonify,redirect, \
- url_for,Response
+
+import requests
+from app import CalculationModuleRpcClient, celery, helper, model
+from app.constants import DATASET_DIRECTORY, UPLOAD_DIRECTORY
+from app.decorators.exceptions import ComputationalModuleError, ValidationError
from app.decorators.restplus import api
-from app.decorators.serializers import compution_module_class, \
- input_computation_module, test_communication_cm, \
- compution_module_list, uploadfile, cm_id_input
+from app.decorators.serializers import (cm_id_input, compution_module_class,
+ compution_module_list,
+ input_computation_module,
+ test_communication_cm, uploadfile)
+from app.model import getCMList, getUI, register_calulation_module
+from celery.task.control import revoke
+from flask import (Response, current_app, jsonify, redirect, request,
+ send_file, send_from_directory, url_for)
+from flask_restplus import Resource
-from app.model import register_calulation_module,getUI,getCMList
+from ..constants import DEFAULT_TIMEOUT
+from ..decorators.timeout import timeout_signal_handler
from ..helper import commands_in_array, run_command
-
from ..models.user import User
-from app import model
-from app import helper
nsCM = api.namespace('cm', description='Operations related to statistisdscs')
ns = nsCM
-from flask_restplus import Resource
-from app import celery
-import requests
-from app.decorators.exceptions import ValidationError, ComputationalModuleError
-import os
-import json
-from flask import send_from_directory, send_file
-from app.constants import UPLOAD_DIRECTORY, DATASET_DIRECTORY
-from app import CalculationModuleRpcClient
-from ..decorators.timeout import timeout_signal_handler
-from ..constants import DEFAULT_TIMEOUT
#TODO Add url to find right computation module
diff --git a/api/app/api_v1/errors.py b/api/app/api_v1/errors.py
index 59e5b4e4..a7463919 100644
--- a/api/app/api_v1/errors.py
+++ b/api/app/api_v1/errors.py
@@ -1,5 +1,6 @@
+from app.decorators.exceptions import ComputationalModuleError, ValidationError
from flask import jsonify
-from app.decorators.exceptions import ValidationError, ComputationalModuleError
+
from . import api
diff --git a/api/app/api_v1/heat_load_profile.py b/api/app/api_v1/heat_load_profile.py
index eea31d0c..3e44ecb4 100644
--- a/api/app/api_v1/heat_load_profile.py
+++ b/api/app/api_v1/heat_load_profile.py
@@ -1,21 +1,21 @@
-from app import celery
import logging
-from flask_restplus import Resource
-from app.decorators.serializers import load_profile_aggregation_day_input, \
- load_profile_aggregation_curve_output, load_profile_aggregation_curve, load_profile_aggregation_hectares, \
- load_profile_aggregation_curve_hectares
-from app.decorators.restplus import api
-from app.decorators.exceptions import IntersectionException, HugeRequestException, ParameterException, RequestException
-from app.models.heatloadQueries import HeatLoadProfile
-from .. import helper
-from ..decorators.timeout import return_on_timeout_endpoint
-
-
import shapely.geometry as shapely_geom
-
+from app import celery
+from app.decorators.exceptions import (HugeRequestException,
+ IntersectionException,
+ ParameterException, RequestException)
+from app.decorators.restplus import api
+from app.decorators.serializers import (
+ load_profile_aggregation_curve, load_profile_aggregation_curve_hectares,
+ load_profile_aggregation_curve_output, load_profile_aggregation_day_input,
+ load_profile_aggregation_hectares)
from app.models import generalData
+from app.models.heatloadQueries import HeatLoadProfile
+from flask_restplus import Resource
+from .. import helper
+from ..decorators.timeout import return_on_timeout_endpoint
log = logging.getLogger(__name__)
diff --git a/api/app/api_v1/snapshot.py b/api/app/api_v1/snapshot.py
index b31717f4..49f6a1b1 100644
--- a/api/app/api_v1/snapshot.py
+++ b/api/app/api_v1/snapshot.py
@@ -1,15 +1,23 @@
-from .. import dbGIS as db
-from ..decorators.restplus import api
-from ..decorators.exceptions import RequestException, ParameterException, UserUnidentifiedException, \
- SnapshotNotExistingException
-from ..models.user import User
-from ..models.snapshots import Snapshots
-from ..decorators.serializers import snapshot_load_input, snapshot_load_output, snapshot_add_input, \
- snapshot_add_output, snapshot_delete_input, snapshot_delete_output, snapshot_list_input, snapshot_list_output, \
- snapshot_update_input, snapshot_update_output
from app import celery
from flask_restplus import Resource
+
+from .. import dbGIS as db
+from ..decorators.exceptions import (ParameterException, RequestException,
+ SnapshotNotExistingException,
+ UserUnidentifiedException)
+from ..decorators.restplus import api
+from ..decorators.serializers import (snapshot_add_input, snapshot_add_output,
+ snapshot_delete_input,
+ snapshot_delete_output,
+ snapshot_list_input,
+ snapshot_list_output,
+ snapshot_load_input,
+ snapshot_load_output,
+ snapshot_update_input,
+ snapshot_update_output)
from ..decorators.timeout import return_on_timeout_endpoint
+from ..models.snapshots import Snapshots
+from ..models.user import User
nsSnapshot = api.namespace('snapshot', description='Operations related to snapshots')
ns = nsSnapshot
diff --git a/api/app/api_v1/stats.py b/api/app/api_v1/stats.py
index 1fe515cb..2fb77d69 100644
--- a/api/app/api_v1/stats.py
+++ b/api/app/api_v1/stats.py
@@ -1,41 +1,43 @@
-from app import celery
+import json
import logging
-import re
import os.path
-import pandas as pd
-import numpy as np
-from osgeo import gdal
-
-from flask_restplus import Resource
-from app.decorators.serializers import stats_layers_hectares_output,\
- stats_layers_nuts_input, stats_layers_nuts_output,\
- stats_layers_hectares_input, stats_list_nuts_input, stats_list_label_dataset,stats_layer_personnal_layer_input
-from app.decorators.restplus import api
-from app.decorators.exceptions import HugeRequestException, IntersectionException, NotEnoughPointsException, ParameterException, RequestException
-from ..models.user import User
+import re
-from app.models.statsQueries import ElectricityMix
-from app.models.statsQueries import LayersStats
-from app.api_v1.upload import Uploads
+import pandas as pd
-from app.models.indicators import layersData
+import app
+import numpy as np
import shapely.geometry as shapely_geom
+from app import celery, model
+from app.api_v1.upload import Uploads
+from app.decorators.exceptions import (HugeRequestException,
+ IntersectionException,
+ NotEnoughPointsException,
+ ParameterException, RequestException)
+from app.decorators.restplus import api
+from app.decorators.serializers import (stats_layer_personnal_layer_input,
+ stats_layers_hectares_input,
+ stats_layers_hectares_output,
+ stats_layers_nuts_input,
+ stats_layers_nuts_output,
+ stats_list_label_dataset,
+ stats_list_nuts_input)
+from app.helper import (adapt_layers_list, adapt_nuts_list, area_to_geom,
+ createAllLayers, find_key_in_dict, generate_csv_name,
+ generate_geotif_name, get_result_formatted,
+ getTypeScale, getValuesFromName, layers_filter,
+ projection_4326_to_3035, removeScaleLayers,
+ retrieveCrossIndicator, write_wkt_csv)
+from app.model import check_table_existe, prepare_clip_personal_layer
+from app.models import generalData, indicators
+from app.models.indicators import HEATDEMAND_FACTOR, layersData
+from app.models.statsQueries import ElectricityMix, LayersStats
+from flask_restplus import Resource
+from osgeo import gdal
from .. import constants
-
-from app.models import generalData, indicators
-from app.models.indicators import HEATDEMAND_FACTOR
-from app.helper import find_key_in_dict, getValuesFromName, retrieveCrossIndicator, createAllLayers,\
- getTypeScale, adapt_layers_list, adapt_nuts_list, removeScaleLayers, layers_filter, getTypeScale, get_result_formatted, generate_geotif_name, area_to_geom, \
- write_wkt_csv, generate_csv_name,projection_4326_to_3035
-import app
-import json
-from app.model import check_table_existe, prepare_clip_personal_layer
-from app import model
from ..decorators.timeout import return_on_timeout_endpoint
-
-
-
+from ..models.user import User
log = logging.getLogger(__name__)
@@ -48,52 +50,51 @@
@api.response(530, 'Request Error')
@api.response(531, 'Missing parameter.')
class StatsLayersNutsInArea(Resource):
- @return_on_timeout_endpoint()
- @api.marshal_with(stats_layers_nuts_output)
- @api.expect(stats_layers_nuts_input)
- def post(self):
- """
- Returns the statistics for specific layers, area and year
- :return:
- """
- #try:
- # Entries
- wrong_parameter = [];
- try:
- year = api.payload['year']
- except:
- wrong_parameter.append('year')
- try:
- layersPayload = api.payload['layers']
- except:
- wrong_parameter.append('layers')
- try:
- nuts = api.payload['nuts']
- except:
- wrong_parameter.append('nuts')
- # raise exception if parameters are false
- if len(wrong_parameter) > 0:
- exception_message = ''
- for i in range(len(wrong_parameter)):
- exception_message += wrong_parameter[i]
- if i != len(wrong_parameter) - 1:
- exception_message += ', '
- raise ParameterException(exception_message + '')
-
- # Stop execution if layers list or nuts list is empty
- if not layersPayload or not nuts:
- return
-
- # Get type
-
-
- output, noDataLayers = LayersStats.run_stat(api.payload)
- # output
- return {
- "layers": output,
- "no_data_layers": noDataLayers,
- "no_table_layers": noDataLayers
- }
+ @return_on_timeout_endpoint()
+ @api.marshal_with(stats_layers_nuts_output)
+ @api.expect(stats_layers_nuts_input)
+ def post(self):
+ """
+ Returns the statistics for specific layers, area and year
+ :return:
+ """
+ #try:
+ # Entries
+ wrong_parameter = [];
+ try:
+ year = api.payload['year']
+ except:
+ wrong_parameter.append('year')
+ try:
+ layersPayload = api.payload['layers']
+ except:
+ wrong_parameter.append('layers')
+ try:
+ nuts = api.payload['nuts']
+ except:
+ wrong_parameter.append('nuts')
+ # raise exception if parameters are false
+ if len(wrong_parameter) > 0:
+ exception_message = ''
+ for i in range(len(wrong_parameter)):
+ exception_message += wrong_parameter[i]
+ if i != len(wrong_parameter) - 1:
+ exception_message += ', '
+ raise ParameterException(exception_message + '')
+
+ # Stop execution if layers list or nuts list is empty
+ if not layersPayload or not nuts:
+ return
+
+ # Get type
+ output, noDataLayers = LayersStats.run_stat(api.payload)
+
+ # output
+ return {
+ "layers": output,
+ "no_data_layers": noDataLayers,
+ "no_table_layers": noDataLayers
+ }
@ns.route('/layers/hectares')
@@ -104,70 +105,65 @@ def post(self):
@api.response(533, 'SQL error.')
#@api.response(534, 'Not enough points error.')
class StatsLayersHectareMulti(Resource):
- @return_on_timeout_endpoint()
- @api.marshal_with(stats_layers_hectares_output)
- @api.expect(stats_layers_hectares_input)
- def post(self):
- """
- Returns the statistics for specific layers, hectares and year
- :return:
- """
- #try:
- # Entries
- wrong_parameter = [];
- layersPayload = api.payload['layers']
- try:
- year = api.payload['year']
- except:
- wrong_parameter.append('year')
- try:
- layersPayload = api.payload['layers']
- except:
- wrong_parameter.append('layers')
- try:
- areas = api.payload['areas']
- for test_area in areas:
- try:
- for test_point in test_area['points']:
- try:
- test_lng = test_point['lng']
- except:
- wrong_parameter.append('lng')
- try:
- test_lat = test_point['lat']
- except:
- wrong_parameter.append('lat')
- except:
- wrong_parameter.append('points')
- except:
- wrong_parameter.append('areas')
- # raise exception if parameters are false
- if len(wrong_parameter) > 0:
- exception_message = ''
- for i in range(len(wrong_parameter)):
- exception_message += wrong_parameter[i]
- if (i != len(wrong_parameter) - 1):
- exception_message += ', '
- raise ParameterException(str(exception_message))
-
-
-
-
-
- output, noDataLayers = LayersStats.run_stat(api.payload)
- #print ("output hectare ",output)
-
- #output
- return {
- "layers": output,
- "no_data_layers": noDataLayers,
- "no_table_layers": noDataLayers
- }
-
-
-
-
-
+ @return_on_timeout_endpoint()
+ @api.marshal_with(stats_layers_hectares_output)
+ @api.expect(stats_layers_hectares_input)
+ def post(self):
+ """
+ Returns the statistics for specific layers, hectares and year
+ :return:
+ """
+ #try:
+ # Entries
+ wrong_parameter = [];
+ layersPayload = api.payload['layers']
+ try:
+ year = api.payload['year']
+ except:
+ wrong_parameter.append('year')
+ try:
+ layersPayload = api.payload['layers']
+ except:
+ wrong_parameter.append('layers')
+ try:
+ areas = api.payload['areas']
+ for test_area in areas:
+ try:
+ for test_point in test_area['points']:
+ try:
+ test_lng = test_point['lng']
+ except:
+ wrong_parameter.append('lng')
+ try:
+ test_lat = test_point['lat']
+ except:
+ wrong_parameter.append('lat')
+ except:
+ wrong_parameter.append('points')
+ except:
+ wrong_parameter.append('areas')
+ # raise exception if parameters are false
+ if len(wrong_parameter) > 0:
+ exception_message = ''
+ for i in range(len(wrong_parameter)):
+ exception_message += wrong_parameter[i]
+ if (i != len(wrong_parameter) - 1):
+ exception_message += ', '
+ raise ParameterException(str(exception_message))
+
+
+
+
+
+ output, noDataLayers = LayersStats.run_stat(api.payload)
+ #print ("output hectare ",output)
+
+ #output
+ return {
+ "layers": output,
+ "no_data_layers": noDataLayers,
+ "no_table_layers": noDataLayers
+ }
@ns.route('/energy-mix/nuts-lau')
@@ -176,175 +172,175 @@ def post(self):
@api.response(530, 'Request error.')
@api.response(531, 'Missing parameter.')
class StatsLayersNutsInArea(Resource):
- @return_on_timeout_endpoint()
- @api.marshal_with(stats_list_label_dataset)
- @api.expect(stats_list_nuts_input)
- def post(self):
- """
- Returns the statistics for specific layers, area and year
- :return:
- """
- # Entries
- wrong_parameter = []
- try:
- nuts = api.payload['nuts']
- except:
- wrong_parameter.append('nuts')
-
- # raise exception if parameters are false
- if len(wrong_parameter) > 0:
- exception_message = ''
- for i in range(len(wrong_parameter)):
- exception_message += wrong_parameter[i]
- if (i != len(wrong_parameter) - 1):
- exception_message += ', '
- raise ParameterException(str(exception_message))
-
- res = ElectricityMix.getEnergyMixNutsLau(adapt_nuts_list(nuts))
- return res
-
-
- # Remove scale for each layer
+ @return_on_timeout_endpoint()
+ @api.marshal_with(stats_list_label_dataset)
+ @api.expect(stats_list_nuts_input)
+ def post(self):
+ """
+ Returns the statistics for specific layers, area and year
+ :return:
+ """
+ # Entries
+ wrong_parameter = []
+ try:
+ nuts = api.payload['nuts']
+ except:
+ wrong_parameter.append('nuts')
+
+ # raise exception if parameters are false
+ if len(wrong_parameter) > 0:
+ exception_message = ''
+ for i in range(len(wrong_parameter)):
+ exception_message += wrong_parameter[i]
+ if (i != len(wrong_parameter) - 1):
+ exception_message += ', '
+ raise ParameterException(str(exception_message))
+
+ res = ElectricityMix.getEnergyMixNutsLau(adapt_nuts_list(nuts))
+ return res
+
+
+ # Remove scale for each layer
@ns.route('/personnal-layers')
class StatsPersonalLayers(Resource):
- @return_on_timeout_endpoint()
- @api.marshal_with(stats_layers_nuts_output)
- @api.expect(stats_layer_personnal_layer_input)
- def post(self):
- noDataLayer=[]
- result=[]
- areas = api.payload['areas']
-
- # if api.payload['scale_level'] == 'hectare':
- # areas = area_to_geom(api.payload['areas'])
- # cutline_input = write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), areas) # TODO: Projection to 3035 if raster
- # else:
- # cutline_input = model.get_shapefile_from_selection(api.payload['scale_level'], areas, constants.UPLOAD_DIRECTORY, '4326')
- for pay in api.payload['layers']:
- values=[]
- data_file_name=""
- token = pay['user_token']
- layer_id = pay['id']
- layer_type = pay['layer_id']
- layer_name = pay['layer_name']
- user = User.verify_auth_token(token)
- upload = Uploads.query.filter_by(id=layer_id).first()
-
- upload_url = upload.url
- if layer_name.endswith('.tif'):
- cutline_input = model.get_cutline_input(areas, api.payload['scale_level'], 'raster')
- filename_tif = generate_geotif_name(constants.UPLOAD_DIRECTORY)
- args = app.helper.commands_in_array("gdalwarp -dstnodata 0 -cutline {} -crop_to_cutline -of GTiff {} {} -tr 100 100 -co COMPRESS=DEFLATE".format(cutline_input, upload_url, filename_tif))
- app.helper.run_command(args)
- if os.path.isfile(filename_tif):
- ds = gdal.Open(filename_tif)
- arr = ds.GetRasterBand(1).ReadAsArray()
- df = pd.DataFrame(arr)
- else:
- noDataLayer.append(layer_name)
- continue
- values = self.set_indicators_in_array(df, layer_type)
- elif layer_name.endswith('.csv'):
- cutline_input = model.get_cutline_input(areas, api.payload['scale_level'], 'vector')
-
- geojson = str(upload_url[:-3]) + "json"
- if os.path.isfile(geojson):
- # take geojson file instead (csv can not be clip), TODO: this on "prepare_clip_personal_layer" function?
- upload_url = geojson
-
- cmd_cutline, output_csv = prepare_clip_personal_layer(cutline_input, upload_url)
- app.helper.run_command(app.helper.commands_in_array(cmd_cutline))
- if os.path.isfile(output_csv):
- df = pd.read_csv(output_csv)
- if api.payload['scale_level'] != constants.hectare_name.lower() and "code" in df:
- # Cannot clip with multipoliygons, TODO: no need to cut the csv with a shapefile for this
- df = df[df["code"].isin(areas)]
-
- for ind in indicators.layersData[layer_type]['indicators']:
- try:
- value = df[ind['table_column']].sum()
- if "agg_method" in ind and ind["agg_method"] == "mean":
- value /= len(areas)
-
- if 'factor' in ind: # Decimal * float => rise error
- value = float(value) * float(ind['factor'])
-
- values.append(get_result_formatted(layer_type+"_"+ind['table_column'], str(value), ind['unit']))
- except:
- noDataLayer.append(layer_name)
- else:
- noDataLayer.append(layer_name)
- continue
- else:
- noDataLayer.append(layer_name)
- continue
-
- result.append({
- 'name': layer_name,
- 'values': values
- })
-
- return {
- "layers": result,
- "no_data_layers": noDataLayer,
- "no_table_layers": noDataLayer
- }
-
- @staticmethod
- def set_indicators_in_array(df, layer_name):
- values=[]
- # Set result in variables
- df=df[df!=0]
- counted_cells = df.count().sum()
- sum_tif = 0
- min_tif = 0
- max_tif = 0
- density_tif = 0
- if counted_cells != 0:
- sum_tif = df.sum().sum()
- min_tif = df.min().min()
- max_tif = df.max().max()
- density_tif = sum_tif/counted_cells
- #print(max_tif,counted_cells,min_tif,max_tif)
- # Assign indicator to results
- values.append(get_indicators_from_result('sum', layer_name, sum_tif))
- values.append(get_indicators_from_result('count', layer_name, counted_cells))
- values.append(get_indicators_from_result('min', layer_name, min_tif))
- values.append(get_indicators_from_result('max', layer_name, max_tif))
- values.append(get_indicators_from_result('mean', layer_name, density_tif))
- return values
+ @return_on_timeout_endpoint()
+ @api.marshal_with(stats_layers_nuts_output)
+ @api.expect(stats_layer_personnal_layer_input)
+ def post(self):
+ noDataLayer=[]
+ result=[]
+ areas = api.payload['areas']
+
+ # if api.payload['scale_level'] == 'hectare':
+ # areas = area_to_geom(api.payload['areas'])
+ # cutline_input = write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), areas) # TODO: Projection to 3035 if raster
+ # else:
+ # cutline_input = model.get_shapefile_from_selection(api.payload['scale_level'], areas, constants.UPLOAD_DIRECTORY, '4326')
+ for pay in api.payload['layers']:
+ values=[]
+ data_file_name=""
+ token = pay['user_token']
+ layer_id = pay['id']
+ layer_type = pay['layer_id']
+ layer_name = pay['layer_name']
+ user = User.verify_auth_token(token)
+ upload = Uploads.query.filter_by(id=layer_id).first()
+
+ upload_url = upload.url
+ if layer_name.endswith('.tif'):
+ cutline_input = model.get_cutline_input(areas, api.payload['scale_level'], 'raster')
+ filename_tif = generate_geotif_name(constants.UPLOAD_DIRECTORY)
+ args = app.helper.commands_in_array("gdalwarp -dstnodata 0 -cutline {} -crop_to_cutline -of GTiff {} {} -tr 100 100 -co COMPRESS=DEFLATE".format(cutline_input, upload_url, filename_tif))
+ app.helper.run_command(args)
+ if os.path.isfile(filename_tif):
+ ds = gdal.Open(filename_tif)
+ arr = ds.GetRasterBand(1).ReadAsArray()
+ df = pd.DataFrame(arr)
+ else:
+ noDataLayer.append(layer_name)
+ continue
+ values = self.set_indicators_in_array(df, layer_type)
+ elif layer_name.endswith('.csv'):
+ cutline_input = model.get_cutline_input(areas, api.payload['scale_level'], 'vector')
+
+ geojson = str(upload_url[:-3]) + "json"
+ if os.path.isfile(geojson):
+ # take geojson file instead (csv can not be clip), TODO: this on "prepare_clip_personal_layer" function?
+ upload_url = geojson
+
+ cmd_cutline, output_csv = prepare_clip_personal_layer(cutline_input, upload_url)
+ app.helper.run_command(app.helper.commands_in_array(cmd_cutline))
+ if os.path.isfile(output_csv):
+ df = pd.read_csv(output_csv)
+ if api.payload['scale_level'] != constants.hectare_name.lower() and "code" in df:
+ # Cannot clip with multipoliygons, TODO: no need to cut the csv with a shapefile for this
+ df = df[df["code"].isin(areas)]
+
+ for ind in indicators.layersData[layer_type]['indicators']:
+ try:
+ value = df[ind['table_column']].sum()
+ if "agg_method" in ind and ind["agg_method"] == "mean":
+ value /= len(areas)
+
+ if 'factor' in ind: # Decimal * float => rise error
+ value = float(value) * float(ind['factor'])
+
+ values.append(get_result_formatted(layer_type+"_"+ind['table_column'], str(value), ind['unit']))
+ except:
+ noDataLayer.append(layer_name)
+ else:
+ noDataLayer.append(layer_name)
+ continue
+ else:
+ noDataLayer.append(layer_name)
+ continue
+
+ result.append({
+ 'name': layer_name,
+ 'values': values
+ })
+
+ return {
+ "layers": result,
+ "no_data_layers": noDataLayer,
+ "no_table_layers": noDataLayer
+ }
+
+ @staticmethod
+ def set_indicators_in_array(df, layer_name):
+ values=[]
+ # Set result in variables
+ df=df[df!=0]
+ counted_cells = df.count().sum()
+ sum_tif = 0
+ min_tif = 0
+ max_tif = 0
+ density_tif = 0
+ if counted_cells != 0:
+ sum_tif = df.sum().sum()
+ min_tif = df.min().min()
+ max_tif = df.max().max()
+ density_tif = sum_tif/counted_cells
+ #print(max_tif,counted_cells,min_tif,max_tif)
+ # Assign indicator to results
+ values.append(get_indicators_from_result('sum', layer_name, sum_tif))
+ values.append(get_indicators_from_result('count', layer_name, counted_cells))
+ values.append(get_indicators_from_result('min', layer_name, min_tif))
+ values.append(get_indicators_from_result('max', layer_name, max_tif))
+ values.append(get_indicators_from_result('mean', layer_name, density_tif))
+ return values
def get_indicators_from_result(id,layer,result):
- filtered_indicators = list(filter(lambda x: 'table_column' in x and x['table_column'] == id, indicators.layersData[layer]['indicators']))
- unit = layer + '_unit_' + id
- value = result
- name = layer + '_' + id
- if len(filtered_indicators)>=1:
- name = layer + '_' + filtered_indicators[0]['indicator_id']
- if 'unit' in filtered_indicators[0]: unit = filtered_indicators[0]['unit']
- if 'factor' in filtered_indicators[0]: value = result*filtered_indicators[0]['factor']
- return get_result_formatted(name,str(value),unit)
-
+ filtered_indicators = list(filter(lambda x: 'table_column' in x and x['table_column'] == id, indicators.layersData[layer]['indicators']))
+ unit = layer + '_unit_' + id
+ value = result
+ name = layer + '_' + id
+ if len(filtered_indicators)>=1:
+ name = layer + '_' + filtered_indicators[0]['indicator_id']
+ if 'unit' in filtered_indicators[0]: unit = filtered_indicators[0]['unit']
+ if 'factor' in filtered_indicators[0]: value = result*filtered_indicators[0]['factor']
+ return get_result_formatted(name,str(value),unit)
+
def get_unit(id, layer):
- filtered_indicators = list(filter(lambda x: 'table_column' in x and x['table_column'] == id,indicators.layersData[layer]['indicators']))
- try:
- return list(filter(lambda x: 'table_column' in x and x['table_column'] == id,indicators.layersData[layer]['indicators']))[0]['unit']
- except IndexError:
- return layer + '_unit_' + id
+ filtered_indicators = list(filter(lambda x: 'table_column' in x and x['table_column'] == id,indicators.layersData[layer]['indicators']))
+ try:
+ return list(filter(lambda x: 'table_column' in x and x['table_column'] == id,indicators.layersData[layer]['indicators']))[0]['unit']
+ except IndexError:
+ return layer + '_unit_' + id
def get_businness_id(id, layer):
- filtered_indicators = list(filter(lambda x: 'table_column' in x and x['table_column'] == id,indicators.layersData[layer]['indicators']))
- try:
- return layer + '_' + filtered_indicators[0]['indicator_id']
- except IndexError:
- return layer + '_' + id
+ filtered_indicators = list(filter(lambda x: 'table_column' in x and x['table_column'] == id,indicators.layersData[layer]['indicators']))
+ try:
+ return layer + '_' + filtered_indicators[0]['indicator_id']
+ except IndexError:
+ return layer + '_' + id
@celery.task(name = 'energy_mix_nuts_lau')
def processGenerationMix(nuts):
- if not nuts:
- return
- res = ElectricityMix.getEnergyMixNutsLau(adapt_nuts_list(nuts))
+ if not nuts:
+ return
+ res = ElectricityMix.getEnergyMixNutsLau(adapt_nuts_list(nuts))
- return res
+ return res
diff --git a/api/app/api_v1/upload.py b/api/app/api_v1/upload.py
index f4231987..d7b7caee 100644
--- a/api/app/api_v1/upload.py
+++ b/api/app/api_v1/upload.py
@@ -6,24 +6,34 @@
import shapely.geometry as shapely_geom
from app import celery
-from app.constants import USER_UPLOAD_FOLDER, UPLOAD_BASE_NAME, UPLOAD_DIRECTORY, NUTS_YEAR, LAU_YEAR
+from app.constants import (LAU_YEAR, NUTS_YEAR, UPLOAD_BASE_NAME,
+ UPLOAD_DIRECTORY, USER_UPLOAD_FOLDER)
from flask import send_file
from flask_restplus import Resource
from .. import dbGIS as db
from ..decorators.parsers import file_upload
-from ..decorators.restplus import UserUnidentifiedException, ParameterException, RequestException, \
- UserDoesntOwnUploadsException, UploadNotExistingException, \
- HugeRequestException, NotEnoughPointsException, UploadFileNotExistingException
-from ..decorators.restplus import api
-from ..decorators.serializers import upload_add_output, upload_list_input, upload_list_output, upload_delete_input, \
- upload_delete_output, upload_export_csv_nuts_input, upload_export_csv_hectare_input, \
- upload_export_raster_nuts_input, upload_export_raster_hectare_input, upload_download_input, \
- upload_export_cm_layer_input
-from ..model import get_csv_from_nuts, get_csv_from_hectare
-from ..models.uploads import Uploads, generate_tiles, allowed_file, generate_geojson, calculate_total_space
-from ..models.user import User
+from ..decorators.restplus import (HugeRequestException,
+ NotEnoughPointsException,
+ ParameterException, RequestException,
+ UploadFileNotExistingException,
+ UploadNotExistingException,
+ UserDoesntOwnUploadsException,
+ UserUnidentifiedException, api)
+from ..decorators.serializers import (upload_add_output, upload_delete_input,
+ upload_delete_output,
+ upload_download_input,
+ upload_export_cm_layer_input,
+ upload_export_csv_hectare_input,
+ upload_export_csv_nuts_input,
+ upload_export_raster_hectare_input,
+ upload_export_raster_nuts_input,
+ upload_list_input, upload_list_output)
from ..decorators.timeout import return_on_timeout_endpoint
+from ..model import get_csv_from_hectare, get_csv_from_nuts
+from ..models.uploads import (Uploads, allowed_file, calculate_total_space,
+ generate_geojson, generate_tiles)
+from ..models.user import User
nsUpload = api.namespace('upload', description='Operations related to file upload')
ns = nsUpload
@@ -740,5 +750,3 @@ def post(self=None):
mimetype=mimetype,
attachment_filename=upload.name + extension,
as_attachment=True)
-
-
diff --git a/api/app/api_v1/users.py b/api/app/api_v1/users.py
index dba82b89..fc6f151a 100644
--- a/api/app/api_v1/users.py
+++ b/api/app/api_v1/users.py
@@ -2,31 +2,45 @@
import os
import uuid
+from app import celery
+from flask import current_app, request
from flask_mail import Message
from flask_restplus import Resource
from flask_security import SQLAlchemySessionUserDatastore
-from itsdangerous import (URLSafeTimedSerializer, BadSignature, SignatureExpired)
-from flask import request, current_app
+from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer
from passlib.hash import bcrypt
-from app import celery
-from .upload import calculate_total_space
-from .. import constants, mail, login_manager
-from ..decorators.exceptions import ParameterException, RequestException, ActivationException, \
- UserExistingException, WrongCredentialException, UserUnidentifiedException, \
- UserNotActivatedException
-from ..decorators.restplus import api
-from ..decorators.serializers import user_register_input, user_register_output, user_activate_input, \
- user_activate_output, user_deletion_input, user_deletion_output, user_ask_recovery_input, \
- user_ask_recovery_output, user_recovery_output, user_recovery_input, user_login_input, user_login_output, \
- user_logout_input, user_logout_output, user_profile_input, user_profile_output, user_get_information_output, \
- user_get_information_input, upload_space_used_output, upload_space_used_input, feedback_output
+from .. import constants
from .. import dbGIS as db
-from ..models.user import User
-from ..models.role import Role
+from .. import login_manager, mail
+from ..decorators.exceptions import (ActivationException, ParameterException,
+ RequestException, UserExistingException,
+ UserNotActivatedException,
+ UserUnidentifiedException,
+ WrongCredentialException)
from ..decorators.parsers import file_upload_feedback
+from ..decorators.restplus import api
+from ..decorators.serializers import (feedback_output, upload_space_used_input,
+ upload_space_used_output,
+ user_activate_input,
+ user_activate_output,
+ user_ask_recovery_input,
+ user_ask_recovery_output,
+ user_deletion_input,
+ user_deletion_output,
+ user_get_information_input,
+ user_get_information_output,
+ user_login_input, user_login_output,
+ user_logout_input, user_logout_output,
+ user_profile_input, user_profile_output,
+ user_recovery_input,
+ user_recovery_output,
+ user_register_input,
+ user_register_output)
from ..decorators.timeout import return_on_timeout_endpoint
-
+from ..models.role import Role
+from ..models.user import User
+from .upload import calculate_total_space
# Setup Flask-Security
user_datastore = SQLAlchemySessionUserDatastore(db.session, User, Role)
@@ -45,9 +59,9 @@ class AskingPasswordRecovery(Resource):
@celery.task(name='ask for password recovery')
def post(self):
"""
- Method to ask for a Password recovery
- :return:
- """
+ Method to ask for a Password recovery
+ :return:
+ """
# Entries
try:
email = api.payload['email']
@@ -90,9 +104,9 @@ class RecoverPassword(Resource):
@celery.task(name='method for recover of password')
def post(self):
"""
- Method to recover the password
- :return:
- """
+ Method to recover the password
+ :return:
+ """
# Entries
wrong_parameter = []
try:
@@ -145,9 +159,9 @@ class UserRegistering(Resource):
@celery.task(name='user registration')
def post(self):
"""
- Returns the statistics for specific layers, area and year
- :return:
- """
+ Returns the statistics for specific layers, area and year
+ :return:
+ """
# Entries
wrong_parameter = []
try:
@@ -222,9 +236,9 @@ class ActivateUser(Resource):
@celery.task(name='user activation')
def post(self):
'''
- The method called to activate a user with a token given by email
- :return:
- '''
+ The method called to activate a user with a token given by email
+ :return:
+ '''
# Entries
try:
token = api.payload['token']
@@ -260,9 +274,9 @@ class DeleteUser(Resource):
@celery.task(name='user deletion')
def delete(self):
'''
- The method called to delete a user with a token given by email
- :return:
- '''
+ The method called to delete a user with a token given by email
+ :return:
+ '''
# Entries
try:
token = api.payload['token']
@@ -299,9 +313,9 @@ class LoginUser(Resource):
@celery.task(name='user login')
def post(self):
'''
- The method called to login a user
- :return:
- '''
+ The method called to login a user
+ :return:
+ '''
# Entries
wrong_parameter = []
try:
@@ -354,9 +368,9 @@ class LogoutUser(Resource):
@celery.task(name='user logout')
def post(self):
'''
- The method called to logout a user
- :return:
- '''
+ The method called to logout a user
+ :return:
+ '''
try:
token = api.payload['token']
except:
@@ -509,9 +523,9 @@ def post(self):
def generate_confirmation_token(email):
"""
- this method will generate a confirmation token
- :return: the confirmation token
- """
+ this method will generate a confirmation token
+ :return: the confirmation token
+ """
s = URLSafeTimedSerializer(constants.FLASK_SECRET_KEY, salt=constants.FLASK_SALT)
token = s.dumps(
{
@@ -526,11 +540,11 @@ def generate_confirmation_token(email):
def confirm_token(token, expiration=3600):
'''
- This method will confirm that the given token is correct
- :param token:
- :param expiration:
- :return:
- '''
+ This method will confirm that the given token is correct
+ :param token:
+ :param expiration:
+ :return:
+ '''
s = URLSafeTimedSerializer(constants.FLASK_SECRET_KEY, salt=constants.FLASK_SALT)
try:
data = s.loads(token)
@@ -547,10 +561,10 @@ def confirm_token(token, expiration=3600):
@login_manager.user_loader
def load_user(user_id):
'''
- this method will return the current user
- :param user_id:
- :return:
- '''
+ this method will return the current user
+ :param user_id:
+ :return:
+ '''
return User.query.filter_by(id=user_id).first()
@@ -580,7 +594,7 @@ def post(self):
Feedback type : {}
\
Feedback priority : {}
\
Description :
{}
".format(title, datetime.date.today(), name,company,feedback_type,feedback_priority, description) - + if 'file' in args and args['file'] is not None: file=args['file'] @@ -594,7 +608,7 @@ def post(self): self.send_async_mail(msg) except Exception as e: raise RequestException(str(e)) - + return { 'message':'Your feedback has been sent successfully. It will be examined and processed as soon as possible' } @celery.task(name='send mail feedback') diff --git a/api/app/bll/csv_file.py b/api/app/bll/csv_file.py index 58bece46..e69de29b 100644 --- a/api/app/bll/csv_file.py +++ b/api/app/bll/csv_file.py @@ -1,3 +0,0 @@ - - - diff --git a/api/app/constants.py b/api/app/constants.py index f57beda5..4e31a74e 100644 --- a/api/app/constants.py +++ b/api/app/constants.py @@ -135,4 +135,4 @@ DATASET_DIRECTORY = '/var/hotmaps/repositories/' NUTS_YEAR = "2013" -LAU_YEAR = NUTS_YEAR \ No newline at end of file +LAU_YEAR = NUTS_YEAR diff --git a/api/app/decorators/__init__.py b/api/app/decorators/__init__.py index 57e1aca6..a610fd37 100644 --- a/api/app/decorators/__init__.py +++ b/api/app/decorators/__init__.py @@ -1,2 +1,2 @@ -from .caching import cache_control, no_cache, etag +from .caching import cache_control, etag, no_cache diff --git a/api/app/decorators/caching.py b/api/app/decorators/caching.py index 03a0f26c..58447c89 100644 --- a/api/app/decorators/caching.py +++ b/api/app/decorators/caching.py @@ -1,6 +1,7 @@ import functools import hashlib -from flask import request, make_response, jsonify + +from flask import jsonify, make_response, request def cache_control(*directives): diff --git a/api/app/decorators/exceptions.py b/api/app/decorators/exceptions.py index 09f1bccd..f260d5e4 100644 --- a/api/app/decorators/exceptions.py +++ b/api/app/decorators/exceptions.py @@ -121,4 +121,3 @@ class ValidationError(ValueError): class ComputationalModuleError(ValueError): pass - diff --git a/api/app/decorators/json.py b/api/app/decorators/json.py index b00de39d..db06bbae 100644 --- a/api/app/decorators/json.py +++ b/api/app/decorators/json.py @@ -1,4 +1,5 @@ import functools + from flask import jsonify diff --git a/api/app/decorators/paginate.py b/api/app/decorators/paginate.py index 1c2845b0..8f67384e 100644 --- a/api/app/decorators/paginate.py +++ b/api/app/decorators/paginate.py @@ -1,5 +1,6 @@ import functools -from flask import url_for, request + +from flask import request, url_for def paginate(collection, max_per_page=25): diff --git a/api/app/decorators/parsers.py b/api/app/decorators/parsers.py index a60df621..5230a4a6 100644 --- a/api/app/decorators/parsers.py +++ b/api/app/decorators/parsers.py @@ -1,5 +1,5 @@ -from flask_restplus import reqparse import werkzeug +from flask_restplus import reqparse pagination_arguments = reqparse.RequestParser() pagination_arguments.add_argument('page', type=int, required=False, default=1, help='Page number') diff --git a/api/app/decorators/restplus.py b/api/app/decorators/restplus.py index ed391143..431ce029 100644 --- a/api/app/decorators/restplus.py +++ b/api/app/decorators/restplus.py @@ -1,14 +1,24 @@ -import traceback import logging +import traceback from flask_restplus import Api -from .. import constants from sqlalchemy.orm.exc import NoResultFound -from ..decorators.exceptions import HugeRequestException, IntersectionException, NotEnoughPointsException, \ - ParameterException, RequestException, ActivationException, UserExistingException, \ - WrongCredentialException, UserUnidentifiedException, UserDoesntOwnUploadsException, NotEnoughSpaceException, \ - UploadNotExistingException, UserNotActivatedException, SnapshotNotExistingException, \ - UploadFileNotExistingException, TimeOutException + +from .. import constants +from ..decorators.exceptions import (ActivationException, HugeRequestException, + IntersectionException, + NotEnoughPointsException, + NotEnoughSpaceException, + ParameterException, RequestException, + SnapshotNotExistingException, + TimeOutException, + UploadFileNotExistingException, + UploadNotExistingException, + UserDoesntOwnUploadsException, + UserExistingException, + UserNotActivatedException, + UserUnidentifiedException, + WrongCredentialException) log = logging.getLogger(__name__) @@ -334,4 +344,3 @@ def default_error_handler(e): def database_not_found_error_handler(e): log.warning(traceback.format_exc()) return {'message': 'A models result was required but none was found.'}, 404 - diff --git a/api/app/decorators/serializers.py b/api/app/decorators/serializers.py index 8f8a88e6..300c4f8c 100644 --- a/api/app/decorators/serializers.py +++ b/api/app/decorators/serializers.py @@ -1,8 +1,9 @@ -from flask_restplus import fields from app.decorators.restplus import api +from flask_restplus import fields from geoalchemy2.shape import to_shape from geojson import Feature, FeatureCollection, dumps + class Geometry(fields.Raw): def format(self, value): shape = to_shape(value) diff --git a/api/app/decorators/timeout.py b/api/app/decorators/timeout.py index e724a813..d0cd7f85 100644 --- a/api/app/decorators/timeout.py +++ b/api/app/decorators/timeout.py @@ -1,7 +1,8 @@ -from .exceptions import TimeOutException -from .restplus import handle_timeout_reached import signal + from ..constants import DEFAULT_TIMEOUT +from .exceptions import TimeOutException +from .restplus import handle_timeout_reached def timeout_signal_handler(signum, frame): @@ -31,4 +32,4 @@ def applicator(*args, **kwargs): return applicator - return decorate \ No newline at end of file + return decorate diff --git a/api/app/helper.py b/api/app/helper.py index 4a7c1a06..0e0f0c82 100644 --- a/api/app/helper.py +++ b/api/app/helper.py @@ -1,528 +1,529 @@ -from app.constants import LAU_TABLE -from app import celery -from shlex import split -import subprocess -import json -import uuid -import shapely.geometry as shapely_geom -import ast -from osgeo import ogr -from osgeo import osr -from . import constants -import requests -from .decorators.exceptions import RequestException -import xml.etree.ElementTree as ET -import csv -import os - -from .models.indicators import MUNICIPAL_SOLID_WASTE - -class ColorMap: - ''' - This class is used to access all informations necessary to upload a .tif to the server separating it into tiles - ''' - def __init__(self, r, g, b, a, quantity): - self.r = r - self.g = g - self.b = b - self.a = a - self.quantity = quantity - - -@celery.task(name = 'Colorize') -def colorize(layer_type, grey_tif, rgb_tif): - ''' - This method is used to check the size of the file - :param layer_type: the name of the layer type chosen for the input - :param grey_tif: the url to the input file - :param rgb_tif: the path to the output file - :return: - ''' - print('colorize') - - # we want to use a unique id for the file to be sure that it will not be duplicated in case two - uuid_temp = str(uuid.uuid4()) - xml = get_style_from_geoserver(layer_type) - color_map_objects = extract_colormap(xml) - - grey2rgb_path = create_grey2rgb_txt(color_map_objects, uuid_temp) - - args_rgba = commands_in_array("gdaldem color-relief {} {} -alpha {} -co COMPRESS=LZW".format(grey_tif, grey2rgb_path, rgb_tif)) - run_command(args_rgba) - - # we delete all temp files - for fname in os.listdir('/tmp'): - if fname.startswith(uuid_temp): - os.remove(os.path.join('/tmp', fname)) - - -def get_style_from_geoserver(layer_type): - ''' - This method will get the style from the geoserver using GET method - :param layer_type: the layer type to select - :return xml: the sld style file - ''' - # TODO: change name on geoserver? - if layer_type == MUNICIPAL_SOLID_WASTE: - layer_type = "potential_municipal_solid_waste" - - url = constants.GEOSERVER_API_URL + 'styles/' + layer_type + '.sld' - result = requests.get(url) - xml = result.content - # This piece of code is temporary, this should be removed when the workspaces on geoserver are unified - if b'No such style' in xml: - # As some layer are inside workspaces, we need to specify the workspace in order to find the correct style - url = constants.GEOSERVER_API_URL + 'workspaces/hotmaps/styles/' + layer_type + '.sld' - result = requests.get(url) - xml = result.content - return xml - - -def create_grey2rgb_txt(color_map_objects, uuid_upload): - ''' - This method will create the grey2rgb.txt file in the /tmp folder in order to convert the .tif to the rgb format - :param color_map_objects: the list of ColorMap required - :param uuid_upload: the uuid in order to have a single file - :return: the file path - ''' - # create the path and the file - grey2rgb_path = '/tmp/' + uuid_upload + 'grey2rgb.txt' - grey2rgb = open(grey2rgb_path, 'w') - - # complete the file - for color_map_object in color_map_objects: - grey2rgb.write( - str(color_map_object.quantity) + " " + - str(color_map_object.r) + " " + - str(color_map_object.g) + " " + - str(color_map_object.b) + " " + - str(color_map_object.a) + "\r\n" - ) - - # close the file connection and return the path - grey2rgb.close() - return grey2rgb_path - - -def extract_colormap(xml): - ''' - This method will extract the colormap of a sld stylesheet - :param xml: the xml file - :return: an array of the different color map - ''' - # create the xml tree - try: - root = ET.fromstring(xml) - except Exception as e: - raise RequestException(str(xml)) - ns = {'sld': 'http://www.opengis.net/sld'} - # get the list of Color map - color_map_list = root.findall(".//sld:ColorMapEntry", ns) - color_map_objects = [] - # for each color map get the color, the opacity and the quantity - for color_map in color_map_list: - color_tuple = hex_to_rgb(color_map.get('color')) - opacity = int(float(color_map.get('opacity')) * 255) - quantity = color_map.get('quantity') - color_map_object = ColorMap(color_tuple[0], color_tuple[1], color_tuple[2], opacity, quantity) - - # add the color map object to the list - color_map_objects.append(color_map_object) - return color_map_objects - - -def hex_to_rgb(value): - ''' - This method is used to convert an hexadecimal into a tuple of rgb values - :param value: hexadecimal - :return: a tuple of rgb - ''' - value = value.lstrip('#') - lv = len(value) - return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) - - -def find_key_in_dict(key, dictionary): - for k, v in dictionary.items(): - if k == key: - yield v - elif isinstance(v, dict): - for result in find_key_in_dict(key, v): - yield result - elif isinstance(v, list): - for d in v: - for result in find_key_in_dict(key, d): - yield result - -def retrieveCrossIndicator(denominator_indicator_name, numerator_indicator_name, layers, payload_output): - if denominator_indicator_name in layers and numerator_indicator_name in layers: - numerator = getValuesFromName(numerator_indicator_name,payload_output) - denominator = getValuesFromName(denominator_indicator_name,payload_output) - generateCrossIndicator(numerator, denominator,numerator_indicator_name, payload_output) - -def generateCrossIndicator(numerator, denominator, value_to_append, output): - denominator_val = float(denominator.get('value', 1)) - denominator_val = denominator_val if denominator_val > 0 else 1 - numerator_val = float(numerator.get('value', 0)) - v = { - 'name': numerator['name'] + '_per_' + denominator['name'], - 'value': numerator_val / denominator_val, - 'unit': numerator.get('unit') + '/' + denominator.get('unit') - } - for x in output: - if x['name'] == value_to_append: - x['values'].append(v) - -def getValuesFromName(name, output): - values = None - for i in output: - if i['name'] == name: - values = i['values'][0] - break - return values -def unicode_array_to_string(unicode_string): - return ast.literal_eval(unicode_string) -def unicode_string_to_string(unicode_string): - return str(unicode_string).encode('ascii','ignore') - - -def test_display(value): - pass - #print ('value ', value) - #print ('type ', type(value)) -def getDictFromJson(output): - outputdumps = json.dumps(output) - outputloads = json.loads(outputdumps)[0] - return outputloads - -def roundValue(value): - return round(value, 1) - -def getGenerationMixColor(value): - switcher = { - "Nuklear": "#909090", - "Lignite": "#556B2F", - "Hard coal": "#000000", - "Natural gas": "#FFD700", - "Oil": "#8B0000", - "Other fossil fuels": "#A9A9A9", - "PV": "#FFFF00", - "Wind ": "#D8BFD8", - "Biomass": "#228B22", - "Hydro": "#1E90FF", - "No information on source": "#FFFAFA", - } - return switcher.get(value, "#D8BFD8") - - -def get_result_formatted(name='not_defined', value=0, unit='unit'): - return { - 'name': name, - 'value': value, - 'unit': unit - } - - - -def generate_geotif_name(directory): - filename = generate_file(directory, '.tif') - return filename - -def generate_shapefile_name(directory): - filename = generate_file(directory, '.shp') - return filename -def generate_csv_name(directory): - filename = generate_file(directory, '.csv') - return filename -def generate_archive(directory): - filename = generate_file(directory, '.zip') - return filename -def generate_file(directory,extension): - filename = directory+'/' + str(uuid.uuid4()) + extension - return filename - -def generate_directory_name(): - return str(uuid.uuid4()) - -def area_to_geom(areas): - polyArray = [] - # convert to polygon format for each polygon and store them in polyArray - for polygon in areas: - po = shapely_geom.Polygon([[p['lng'], p['lat']] for p in polygon['points']]) - polyArray.append(po) - # convert array of polygon into multipolygon - multipolygon = shapely_geom.MultiPolygon(polyArray) - #geom = "SRID=4326;{}".format(multipolygon.wkt) - - geom = multipolygon.wkt - return geom - -def adapt_nuts_list(nuts): - # Store nuts in new custom list - nutsPayload = [] - for n in nuts: - if n not in nutsPayload: - nutsPayload.append(str(n)) - - # Adapt format of list for the query - nutsListQuery = str(nutsPayload) - nutsListQuery = nutsListQuery[1:] # Remove the left hook - nutsListQuery = nutsListQuery[:-1] # Remove the right hook - - return nutsListQuery - -def generate_payload_for_compute(inputs_raster_selection,inputs_parameter_selection): - - data_output = {} - - data_output.update({ - - 'inputs_parameter_selection':inputs_parameter_selection - }) - data_output.update({ - - 'inputs_raster_selection':inputs_raster_selection - }) - ##print ('data_output',data_output) - data = json.dumps(data_output) - return data - -def remove_None_in_turple(tupleX): - tupleX = [x for x in tupleX if x is not None] - return tupleX - -def write_wkt_csv(output_file,content): - - with open(output_file, mode='w') as csv_file: - fieldnames = ['id', 'WKT'] - writer = csv.DictWriter(csv_file, fieldnames=fieldnames) - - writer.writeheader() - writer.writerow({'id': '1', 'WKT': content}) - return output_file - -def projection_4326_to_3035(wkt): - # use the database to transform the geometry from 3857 to 4326 - source = osr.SpatialReference() - source.ImportFromEPSG(4326) - - target = osr.SpatialReference() - target.ImportFromEPSG(3035) - - transform = osr.CoordinateTransformation(source, target) - - point = ogr.CreateGeometryFromWkt(wkt) - point.Transform(transform) - - return point.ExportToWkt() - - - -def zipdir(path, ziph): - # ziph is zipfile handle - for root, dirs, files in os.walk(path): - for file in files: - ziph.write(os.path.join(root, file)) - -def retrieve_list_from_sql_result(results): - response = [] - for value in results: - ##print ('value', value) - ze_value = {} - i = 0 - for key in results.description: - ze_value[key[0]]= str(value[i]) - if isinstance(unicode_string_to_string(value[i]), str): - val = unicode_string_to_string(value[i]) - if val.find('[') == 0: # and value.find(']')== - #print ('value ', val) - ze_value[key[0]]= unicode_array_to_string(value[i]) - elif isinstance(value[i], str): - val = value[i] - if val.find('[') == 0: # and value.find(']')== - #print ('value ', val) - ze_value[key[0]]= unicode_array_to_string(value[i]) - i = i + 1 - response.append(ze_value) - return response - -def force_decode(string, codecs=['utf8', 'cp1252']): - for i in codecs: - try: - return string.decode(i) - except UnicodeDecodeError: - pass -def from_dict_to_unique_array(results,key): - response = [] - for value in results: - ze_value = value[key] - response.append(ze_value) - return response - -def sampling_data(listValues): - # Get number of values - numberOfValues = len(listValues) - - # Create the points for the curve with the X and Y axis - listPoints = [] - for n, l in enumerate(listValues): - listPoints.append({ - 'X':n+1, - 'Y':listValues[n] - }) - - # Sampling of the values - cut1 = int(numberOfValues*constants.POINTS_FIRST_GROUP_PERCENTAGE) - cut2 = int(cut1+(numberOfValues*constants.POINTS_SECOND_GROUP_PERCENTAGE)) - cut3 = int(cut2+(numberOfValues*constants.POINTS_THIRD_GROUP_PERCENTAGE)) - - firstGroup = listPoints[0:cut1:constants.POINTS_FIRST_GROUP_STEP] - secondGroup = listPoints[cut1:cut2:constants.POINTS_SECOND_GROUP_STEP] - thirdGroup = listPoints[cut2:cut3:constants.POINTS_THIRD_GROUP_STEP] - fourthGroup = listPoints[cut3:numberOfValues:constants.POINTS_FOURTH_GROUP_STEP] - - # Get min and max values needed for the sampling list - maxValue = min(listPoints) - minValue = max(listPoints) - - # Concatenate the groups to a new list of points (sampling list) - finalListPoints = firstGroup+secondGroup+thirdGroup+fourthGroup - - # Add max value at the beginning if the list doesn't contain it - if maxValue not in finalListPoints: - finalListPoints.insert(0, maxValue) - - # Add min value at the end if the list doesn't contain it - if minValue not in finalListPoints: - finalListPoints.append(minValue) - - return finalListPoints -def nuts_array_to_string(nuts): - nuts_transformed = ''.join("'"+str(nu)+"'," for nu in nuts)[:-1] - return nuts_transformed - -def transform_nuts_list(nuts): - # Store nuts in new custom list - nutsPayload = [] - for n in nuts: - n = n[:4] - if n not in nutsPayload: - nutsPayload.append(str(n)) - - # Adapt format of list for the query - nutsListQuery = str(nutsPayload) - nutsListQuery = nutsListQuery[1:] # Remove the left hook - nutsListQuery = nutsListQuery[:-1] # Remove the right hook - - return nutsListQuery - - -def createAllLayers(layers): - allLayers = [] - for l in layers: - allLayers.append(l) - allLayers.append(l+'_ha') - allLayers.append(l+'_nuts3') - allLayers.append(l+'_nuts2') - allLayers.append(l+'_nuts1') - allLayers.append(l+'_nuts0') - allLayers.append(l+'_lau2') - - return allLayers - -def getTypeScale(layers): - if layers: - if layers[0].endswith('lau2'): - return 'lau' - else: - return 'nuts' - else: - return '' - -def areas_to_geom(areas): - polygon_array=[] - for polygon in areas: - po = shapely_geom.Polygon([[p['lng'], p['lat']] for p in polygon['points']]) - polygon_array.append(po) - # convert array of polygon into multipolygon - mp = shapely_geom.MultiPolygon(polygon_array) - return mp.wkt - -def adapt_layers_list(layersPayload, type, allLayers): - layers = [] - if type == 'lau': - for layer in layersPayload: - if layer in allLayers: - layer = layer[:-5] # Remove the type for each layer - layers.append(layer) - elif type == 'ha': - for layer in layersPayload: - if layer in allLayers: - layer = layer[:-3] # Remove the type for each layer - layers.append(layer) - else: - for layer in layersPayload: - if layer in allLayers: - layer = layer[:-6] # Remove the type for each layer - layers.append(layer) - - return layers -def removeScaleLayers(layersList, type): - layers = [] - if type == 'lau': - for layer in layersList: - layer = layer[:-5] # Remove the type for each layer - layers.append(layer) - elif type == 'ha': - for layer in layersList: - layer = layer[:-3] # Remove the type for each layer - layers.append(layer) - else: - for layer in layersList: - layer = layer[:-6] # Remove the type for each layer - layers.append(layer) - - return layers - -def layers_filter(layersPayload, list): - layers = [] - for l in layersPayload: - if l not in list: - layers.append(l) - - return layers -def get_nuts_query_selection(nuts, scale_level_table, scale_id): - - if scale_level_table == 'nuts': - scale_schema = 'geo' - return """nutsSelection as ( - SELECT nuts.nuts_id as nuts2_id, tbl2."""+scale_id+""" as scale_id - from geo.nuts nuts, """+scale_schema+"""."""+scale_level_table+""" tbl2 - where tbl2.year = date('2013-01-01') and tbl2."""+scale_id+""" in ("""+nuts+""") - and st_within(st_transform(tbl2.geom,"""+constants.CRS_NUTS+"""),nuts.geom) - and nuts.stat_levl_ = 2 - group by nuts.nuts_id, tbl2."""+scale_id+"""),""" - - else: - scale_schema = 'public' - return """nutsSelection as ( - SELECT nuts.nuts_id as nuts2_id, tbl2."""+scale_id+""" as scale_id - from geo.nuts nuts, """+scale_schema+"""."""+LAU_TABLE+""" tbl2 - where tbl2."""+scale_id+""" in ("""+nuts+""") - and st_within(st_centroid(tbl2.geom),nuts.geom) - and nuts.stat_levl_ = 2 - group by nuts.nuts_id, tbl2."""+scale_id+"""),""" - - -def commands_in_array(com_string): - return split(com_string) - - -def run_command(arr): - process = subprocess.Popen( - arr, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - if process.wait(): - print(f"Not able to execute: {arr}\n returncode: {process.returncode}") - stdout, stderr = process.communicate() - print(f"stdout:\n{stdout}\nstderr:\n{stderr}") \ No newline at end of file +import ast +import csv +import json +import os +import subprocess +import uuid +import xml.etree.ElementTree as ET +from shlex import split + +import requests +import shapely.geometry as shapely_geom +from app import celery +from app.constants import LAU_TABLE +from osgeo import ogr, osr + +from . import constants +from .decorators.exceptions import RequestException +from .models.indicators import MUNICIPAL_SOLID_WASTE + + +class ColorMap: + ''' + This class is used to access all informations necessary to upload a .tif to the server separating it into tiles + ''' + def __init__(self, r, g, b, a, quantity): + self.r = r + self.g = g + self.b = b + self.a = a + self.quantity = quantity + + +@celery.task(name = 'Colorize') +def colorize(layer_type, grey_tif, rgb_tif): + ''' + This method is used to check the size of the file + :param layer_type: the name of the layer type chosen for the input + :param grey_tif: the url to the input file + :param rgb_tif: the path to the output file + :return: + ''' + print('colorize') + + # we want to use a unique id for the file to be sure that it will not be duplicated in case two + uuid_temp = str(uuid.uuid4()) + xml = get_style_from_geoserver(layer_type) + color_map_objects = extract_colormap(xml) + + grey2rgb_path = create_grey2rgb_txt(color_map_objects, uuid_temp) + + args_rgba = commands_in_array("gdaldem color-relief {} {} -alpha {} -co COMPRESS=LZW".format(grey_tif, grey2rgb_path, rgb_tif)) + run_command(args_rgba) + + # we delete all temp files + for fname in os.listdir('/tmp'): + if fname.startswith(uuid_temp): + os.remove(os.path.join('/tmp', fname)) + + +def get_style_from_geoserver(layer_type): + ''' + This method will get the style from the geoserver using GET method + :param layer_type: the layer type to select + :return xml: the sld style file + ''' + # TODO: change name on geoserver? + if layer_type == MUNICIPAL_SOLID_WASTE: + layer_type = "potential_municipal_solid_waste" + + url = constants.GEOSERVER_API_URL + 'styles/' + layer_type + '.sld' + result = requests.get(url) + xml = result.content + # This piece of code is temporary, this should be removed when the workspaces on geoserver are unified + if b'No such style' in xml: + # As some layer are inside workspaces, we need to specify the workspace in order to find the correct style + url = constants.GEOSERVER_API_URL + 'workspaces/hotmaps/styles/' + layer_type + '.sld' + result = requests.get(url) + xml = result.content + return xml + + +def create_grey2rgb_txt(color_map_objects, uuid_upload): + ''' + This method will create the grey2rgb.txt file in the /tmp folder in order to convert the .tif to the rgb format + :param color_map_objects: the list of ColorMap required + :param uuid_upload: the uuid in order to have a single file + :return: the file path + ''' + # create the path and the file + grey2rgb_path = '/tmp/' + uuid_upload + 'grey2rgb.txt' + grey2rgb = open(grey2rgb_path, 'w') + + # complete the file + for color_map_object in color_map_objects: + grey2rgb.write( + str(color_map_object.quantity) + " " + + str(color_map_object.r) + " " + + str(color_map_object.g) + " " + + str(color_map_object.b) + " " + + str(color_map_object.a) + "\r\n" + ) + + # close the file connection and return the path + grey2rgb.close() + return grey2rgb_path + + +def extract_colormap(xml): + ''' + This method will extract the colormap of a sld stylesheet + :param xml: the xml file + :return: an array of the different color map + ''' + # create the xml tree + try: + root = ET.fromstring(xml) + except Exception as e: + raise RequestException(str(xml)) + ns = {'sld': 'http://www.opengis.net/sld'} + # get the list of Color map + color_map_list = root.findall(".//sld:ColorMapEntry", ns) + color_map_objects = [] + # for each color map get the color, the opacity and the quantity + for color_map in color_map_list: + color_tuple = hex_to_rgb(color_map.get('color')) + opacity = int(float(color_map.get('opacity')) * 255) + quantity = color_map.get('quantity') + color_map_object = ColorMap(color_tuple[0], color_tuple[1], color_tuple[2], opacity, quantity) + + # add the color map object to the list + color_map_objects.append(color_map_object) + return color_map_objects + + +def hex_to_rgb(value): + ''' + This method is used to convert an hexadecimal into a tuple of rgb values + :param value: hexadecimal + :return: a tuple of rgb + ''' + value = value.lstrip('#') + lv = len(value) + return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) + + +def find_key_in_dict(key, dictionary): + for k, v in dictionary.items(): + if k == key: + yield v + elif isinstance(v, dict): + for result in find_key_in_dict(key, v): + yield result + elif isinstance(v, list): + for d in v: + for result in find_key_in_dict(key, d): + yield result + +def retrieveCrossIndicator(denominator_indicator_name, numerator_indicator_name, layers, payload_output): + if denominator_indicator_name in layers and numerator_indicator_name in layers: + numerator = getValuesFromName(numerator_indicator_name,payload_output) + denominator = getValuesFromName(denominator_indicator_name,payload_output) + generateCrossIndicator(numerator, denominator,numerator_indicator_name, payload_output) + +def generateCrossIndicator(numerator, denominator, value_to_append, output): + denominator_val = float(denominator.get('value', 1)) + denominator_val = denominator_val if denominator_val > 0 else 1 + numerator_val = float(numerator.get('value', 0)) + v = { + 'name': numerator['name'] + '_per_' + denominator['name'], + 'value': numerator_val / denominator_val, + 'unit': numerator.get('unit') + '/' + denominator.get('unit') + } + for x in output: + if x['name'] == value_to_append: + x['values'].append(v) + +def getValuesFromName(name, output): + values = None + for i in output: + if i['name'] == name: + values = i['values'][0] + break + return values +def unicode_array_to_string(unicode_string): + return ast.literal_eval(unicode_string) +def unicode_string_to_string(unicode_string): + return str(unicode_string).encode('ascii','ignore') + + +def test_display(value): + pass + #print ('value ', value) + #print ('type ', type(value)) +def getDictFromJson(output): + outputdumps = json.dumps(output) + outputloads = json.loads(outputdumps)[0] + return outputloads + +def roundValue(value): + return round(value, 1) + +def getGenerationMixColor(value): + switcher = { + "Nuklear": "#909090", + "Lignite": "#556B2F", + "Hard coal": "#000000", + "Natural gas": "#FFD700", + "Oil": "#8B0000", + "Other fossil fuels": "#A9A9A9", + "PV": "#FFFF00", + "Wind ": "#D8BFD8", + "Biomass": "#228B22", + "Hydro": "#1E90FF", + "No information on source": "#FFFAFA", + } + return switcher.get(value, "#D8BFD8") + + +def get_result_formatted(name='not_defined', value=0, unit='unit'): + return { + 'name': name, + 'value': value, + 'unit': unit + } + + + +def generate_geotif_name(directory): + filename = generate_file(directory, '.tif') + return filename + +def generate_shapefile_name(directory): + filename = generate_file(directory, '.shp') + return filename +def generate_csv_name(directory): + filename = generate_file(directory, '.csv') + return filename +def generate_archive(directory): + filename = generate_file(directory, '.zip') + return filename +def generate_file(directory,extension): + filename = directory+'/' + str(uuid.uuid4()) + extension + return filename + +def generate_directory_name(): + return str(uuid.uuid4()) + +def area_to_geom(areas): + polyArray = [] + # convert to polygon format for each polygon and store them in polyArray + for polygon in areas: + po = shapely_geom.Polygon([[p['lng'], p['lat']] for p in polygon['points']]) + polyArray.append(po) + # convert array of polygon into multipolygon + multipolygon = shapely_geom.MultiPolygon(polyArray) + #geom = "SRID=4326;{}".format(multipolygon.wkt) + + geom = multipolygon.wkt + return geom + +def adapt_nuts_list(nuts): + # Store nuts in new custom list + nutsPayload = [] + for n in nuts: + if n not in nutsPayload: + nutsPayload.append(str(n)) + + # Adapt format of list for the query + nutsListQuery = str(nutsPayload) + nutsListQuery = nutsListQuery[1:] # Remove the left hook + nutsListQuery = nutsListQuery[:-1] # Remove the right hook + + return nutsListQuery + +def generate_payload_for_compute(inputs_raster_selection,inputs_parameter_selection): + + data_output = {} + + data_output.update({ + + 'inputs_parameter_selection':inputs_parameter_selection + }) + data_output.update({ + + 'inputs_raster_selection':inputs_raster_selection + }) + ##print ('data_output',data_output) + data = json.dumps(data_output) + return data + +def remove_None_in_turple(tupleX): + tupleX = [x for x in tupleX if x is not None] + return tupleX + +def write_wkt_csv(output_file,content): + + with open(output_file, mode='w') as csv_file: + fieldnames = ['id', 'WKT'] + writer = csv.DictWriter(csv_file, fieldnames=fieldnames) + + writer.writeheader() + writer.writerow({'id': '1', 'WKT': content}) + return output_file + +def projection_4326_to_3035(wkt): + # use the database to transform the geometry from 3857 to 4326 + source = osr.SpatialReference() + source.ImportFromEPSG(4326) + + target = osr.SpatialReference() + target.ImportFromEPSG(3035) + + transform = osr.CoordinateTransformation(source, target) + + point = ogr.CreateGeometryFromWkt(wkt) + point.Transform(transform) + + return point.ExportToWkt() + + + +def zipdir(path, ziph): + # ziph is zipfile handle + for root, dirs, files in os.walk(path): + for file in files: + ziph.write(os.path.join(root, file)) + +def retrieve_list_from_sql_result(results): + response = [] + for value in results: + ##print ('value', value) + ze_value = {} + i = 0 + for key in results.description: + ze_value[key[0]]= str(value[i]) + if isinstance(unicode_string_to_string(value[i]), str): + val = unicode_string_to_string(value[i]) + if val.find('[') == 0: # and value.find(']')== + #print ('value ', val) + ze_value[key[0]]= unicode_array_to_string(value[i]) + elif isinstance(value[i], str): + val = value[i] + if val.find('[') == 0: # and value.find(']')== + #print ('value ', val) + ze_value[key[0]]= unicode_array_to_string(value[i]) + i = i + 1 + response.append(ze_value) + return response + +def force_decode(string, codecs=['utf8', 'cp1252']): + for i in codecs: + try: + return string.decode(i) + except UnicodeDecodeError: + pass +def from_dict_to_unique_array(results,key): + response = [] + for value in results: + ze_value = value[key] + response.append(ze_value) + return response + +def sampling_data(listValues): + # Get number of values + numberOfValues = len(listValues) + + # Create the points for the curve with the X and Y axis + listPoints = [] + for n, l in enumerate(listValues): + listPoints.append({ + 'X':n+1, + 'Y':listValues[n] + }) + + # Sampling of the values + cut1 = int(numberOfValues*constants.POINTS_FIRST_GROUP_PERCENTAGE) + cut2 = int(cut1+(numberOfValues*constants.POINTS_SECOND_GROUP_PERCENTAGE)) + cut3 = int(cut2+(numberOfValues*constants.POINTS_THIRD_GROUP_PERCENTAGE)) + + firstGroup = listPoints[0:cut1:constants.POINTS_FIRST_GROUP_STEP] + secondGroup = listPoints[cut1:cut2:constants.POINTS_SECOND_GROUP_STEP] + thirdGroup = listPoints[cut2:cut3:constants.POINTS_THIRD_GROUP_STEP] + fourthGroup = listPoints[cut3:numberOfValues:constants.POINTS_FOURTH_GROUP_STEP] + + # Get min and max values needed for the sampling list + maxValue = min(listPoints) + minValue = max(listPoints) + + # Concatenate the groups to a new list of points (sampling list) + finalListPoints = firstGroup+secondGroup+thirdGroup+fourthGroup + + # Add max value at the beginning if the list doesn't contain it + if maxValue not in finalListPoints: + finalListPoints.insert(0, maxValue) + + # Add min value at the end if the list doesn't contain it + if minValue not in finalListPoints: + finalListPoints.append(minValue) + + return finalListPoints +def nuts_array_to_string(nuts): + nuts_transformed = ''.join("'"+str(nu)+"'," for nu in nuts)[:-1] + return nuts_transformed + +def transform_nuts_list(nuts): + # Store nuts in new custom list + nutsPayload = [] + for n in nuts: + n = n[:4] + if n not in nutsPayload: + nutsPayload.append(str(n)) + + # Adapt format of list for the query + nutsListQuery = str(nutsPayload) + nutsListQuery = nutsListQuery[1:] # Remove the left hook + nutsListQuery = nutsListQuery[:-1] # Remove the right hook + + return nutsListQuery + + +def createAllLayers(layers): + allLayers = [] + for l in layers: + allLayers.append(l) + allLayers.append(l+'_ha') + allLayers.append(l+'_nuts3') + allLayers.append(l+'_nuts2') + allLayers.append(l+'_nuts1') + allLayers.append(l+'_nuts0') + allLayers.append(l+'_lau2') + + return allLayers + +def getTypeScale(layers): + if layers: + if layers[0].endswith('lau2'): + return 'lau' + else: + return 'nuts' + else: + return '' + +def areas_to_geom(areas): + polygon_array=[] + for polygon in areas: + po = shapely_geom.Polygon([[p['lng'], p['lat']] for p in polygon['points']]) + polygon_array.append(po) + # convert array of polygon into multipolygon + mp = shapely_geom.MultiPolygon(polygon_array) + return mp.wkt + +def adapt_layers_list(layersPayload, type, allLayers): + layers = [] + if type == 'lau': + for layer in layersPayload: + if layer in allLayers: + layer = layer[:-5] # Remove the type for each layer + layers.append(layer) + elif type == 'ha': + for layer in layersPayload: + if layer in allLayers: + layer = layer[:-3] # Remove the type for each layer + layers.append(layer) + else: + for layer in layersPayload: + if layer in allLayers: + layer = layer[:-6] # Remove the type for each layer + layers.append(layer) + + return layers +def removeScaleLayers(layersList, type): + layers = [] + if type == 'lau': + for layer in layersList: + layer = layer[:-5] # Remove the type for each layer + layers.append(layer) + elif type == 'ha': + for layer in layersList: + layer = layer[:-3] # Remove the type for each layer + layers.append(layer) + else: + for layer in layersList: + layer = layer[:-6] # Remove the type for each layer + layers.append(layer) + + return layers + +def layers_filter(layersPayload, list): + layers = [] + for l in layersPayload: + if l not in list: + layers.append(l) + + return layers +def get_nuts_query_selection(nuts, scale_level_table, scale_id): + + if scale_level_table == 'nuts': + scale_schema = 'geo' + return """nutsSelection as ( + SELECT nuts.nuts_id as nuts2_id, tbl2."""+scale_id+""" as scale_id + from geo.nuts nuts, """+scale_schema+"""."""+scale_level_table+""" tbl2 + where tbl2.year = date('2013-01-01') and tbl2."""+scale_id+""" in ("""+nuts+""") + and st_within(st_transform(tbl2.geom,"""+constants.CRS_NUTS+"""),nuts.geom) + and nuts.stat_levl_ = 2 + group by nuts.nuts_id, tbl2."""+scale_id+"""),""" + + else: + scale_schema = 'public' + return """nutsSelection as ( + SELECT nuts.nuts_id as nuts2_id, tbl2."""+scale_id+""" as scale_id + from geo.nuts nuts, """+scale_schema+"""."""+LAU_TABLE+""" tbl2 + where tbl2."""+scale_id+""" in ("""+nuts+""") + and st_within(st_centroid(tbl2.geom),nuts.geom) + and nuts.stat_levl_ = 2 + group by nuts.nuts_id, tbl2."""+scale_id+"""),""" + + +def commands_in_array(com_string): + return split(com_string) + + +def run_command(arr): + process = subprocess.Popen( + arr, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + if process.wait(): + print(f"Not able to execute: {arr}\n returncode: {process.returncode}") + stdout, stderr = process.communicate() + print(f"stdout:\n{stdout}\nstderr:\n{stderr}") diff --git a/api/app/helper/gdal2tiles-multiprocess.py b/api/app/helper/gdal2tiles-multiprocess.py index 22df8a97..0552064a 100755 --- a/api/app/helper/gdal2tiles-multiprocess.py +++ b/api/app/helper/gdal2tiles-multiprocess.py @@ -40,7 +40,12 @@ # Hacked to make changes to the stacking order.. spruceboy@gmail.com +import math +import multiprocessing +import os import sys +import tempfile +from optparse import OptionGroup, OptionParser try: from osgeo import gdal @@ -50,8 +55,6 @@ print 'You are using "old gen" bindings. gdal2tiles needs "new gen" bindings.' sys.exit(1) -import os -import math try: from PIL import Image @@ -63,9 +66,6 @@ pass -import multiprocessing -import tempfile -from optparse import OptionParser, OptionGroup __version__ = '$Id: gdal2tiles.py 27349 2014-05-16 18:58:51Z rouault $' @@ -119,7 +119,6 @@ Class is available under the open-source GDAL license (www.gdal.org). """ -import math MAXZOOMLEVEL = 32 diff --git a/api/app/helper/gdal2tiles.py b/api/app/helper/gdal2tiles.py index b3cfcc43..0c77d9ee 100644 --- a/api/app/helper/gdal2tiles.py +++ b/api/app/helper/gdal2tiles.py @@ -37,20 +37,19 @@ # DEALINGS IN THE SOFTWARE. # ****************************************************************************** -from __future__ import print_function, division +from __future__ import division, print_function import math -from multiprocessing import Pipe, Pool, Process, Manager import os -import tempfile -import threading import shutil import sys +import tempfile +import threading +from multiprocessing import Manager, Pipe, Pool, Process from uuid import uuid4 from xml.etree import ElementTree -from osgeo import gdal -from osgeo import osr +from osgeo import gdal, osr try: from PIL import Image diff --git a/api/app/helper/gdal2tiles.py.orig b/api/app/helper/gdal2tiles.py.orig index b3cfcc43..0c77d9ee 100644 --- a/api/app/helper/gdal2tiles.py.orig +++ b/api/app/helper/gdal2tiles.py.orig @@ -37,20 +37,19 @@ # DEALINGS IN THE SOFTWARE. # ****************************************************************************** -from __future__ import print_function, division +from __future__ import division, print_function import math -from multiprocessing import Pipe, Pool, Process, Manager import os -import tempfile -import threading import shutil import sys +import tempfile +import threading +from multiprocessing import Manager, Pipe, Pool, Process from uuid import uuid4 from xml.etree import ElementTree -from osgeo import gdal -from osgeo import osr +from osgeo import gdal, osr try: from PIL import Image diff --git a/api/app/model.py b/api/app/model.py index b45f5e95..bf4729c4 100644 --- a/api/app/model.py +++ b/api/app/model.py @@ -1,746 +1,747 @@ -import uuid - -import app.helper -from app.decorators.exceptions import ValidationError, HugeRequestException, RequestException, NotEnoughPointsException - - -from .helper import area_to_geom, write_wkt_csv, generate_csv_name, projection_4326_to_3035, commands_in_array, \ - run_command - -try: - from shlex import quote -except ImportError: - from pipes import quote -import subprocess -from app.constants import DATASET_DIRECTORY, USER_DB,HOST_DB,PASSWORD_DB,PORT_DB,DATABASE_DB -from app.constants import DATASET_DIRECTORY, UPLOAD_DIRECTORY, NUTS_YEAR, LAU_YEAR -from datetime import datetime -import psycopg2 -import sqlalchemy.pool as pool -import sqlite3 -from app import celery, dbGIS as db, constants -from app.constants import CM_DB_NAME -from app import helper -from app import sql_queries -from .models.uploads import Uploads, generate_csv_string -import os -import shapely.geometry as shapely_geom -try: - import ogr -except ImportError: - from osgeo import ogr - -try: - import osr -except ImportError: - from osgeo import osr -basedir = os.path.abspath(os.path.dirname(__file__)) - -db_path = os.path.join(basedir, '../data.sqlite') - -DB_NAME = CM_DB_NAME - -def getConnection_db_CM(): - c = sqlite3.connect(DB_NAME) - return c - - -myCMpool = pool.QueuePool(getConnection_db_CM, max_overflow=10, pool_size=15) - - -def addRegisterCalulationModule(data): - """ - this request will get the signature of a CM and will insert it to the database - :param data: signature payload of the CM - :return: - """ - - cm_name = data['cm_name'] - - - - wiki_url = "" - try: - wiki_url = data['wiki_url'] - except: - pass - category = data['category'] - type_layer_needed = data['type_layer_needed'] - authorized_scale = "[]" - try: - authorized_scale = data['authorized_scale'] - except: - pass - description_link = "" - try: - description_link = data['description_link'] - except: - pass - vectors_needed = "[]" - try: - vectors_needed = data['vectors_needed'] - except: - pass - - try: - type_vectors_needed = data['type_vectors_needed'] - except: - pass - cm_description = data['cm_description'] - cm_url = data['cm_url'] - cm_Id = data['id'] - layers_needed = data['layers_needed'] - updatedAt = datetime.utcnow() - createdAt = datetime.utcnow() - conn = myCMpool.connect() - cursor = conn.cursor() - cursor.execute("INSERT INTO calculation_module (cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updateAt,type_layer_needed,authorized_scale,description_link,vectors_needed,wiki_url) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", ( cm_Id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt ,type_layer_needed,authorized_scale,description_link,vectors_needed,type_vectors_needed,wiki_url)) - cursor.close() - -def init_sqlite_caculation_module_database(dbname=DB_NAME): - """ - - :param dbname: this part will manually create the database for CM - :return: conn : this is the connection to the database - """ - conn = sqlite3.connect(dbname) - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS calculation_module") - cursor.execute("CREATE TABLE calculation_module (cm_id INTEGER NOT NULL, cm_name VARCHAR(255), wiki_url VARCHAR(255)," - "cm_description VARCHAR(255),cm_url VARCHAR(255),category VARCHAR(255),layers_needed VARCHAR(255),authorized_scale VARCHAR(255),description_link VARCHAR(255),createdAt REAL(255),updatedAt REAL(255),type_layer_needed REAL(255),vectors_needed REAL(255),type_vectors_needed REAL(255)," - " PRIMARY KEY(cm_id))") - conn.commit() - cursor.execute("DROP TABLE IF EXISTS inputs_calculation_module") - cursor.execute("CREATE TABLE inputs_calculation_module (input_id INTEGER NOT NULL, input_name VARCHAR(255), " - "input_type VARCHAR(255),input_parameter_name VARCHAR(255),input_value VARCHAR(255),input_priority INTEGER, input_unit VARCHAR(255)," - "input_min INTEGER,input_max INTEGER,createdAt REAL(255),updatedAt REAL(255),cm_id INTEGER NOT NULL," - " PRIMARY KEY(input_id),FOREIGN KEY(cm_id) REFERENCES calculation_module(cm_id))") - conn.commit() - return conn - -def register_calulation_module(data): - if data is not None: - conn = myCMpool.connect() - cursor = conn.cursor() - cm_name = data['cm_name'] - - - wiki_url = "" - try: - wiki_url = data['wiki_url'] - except: - pass - category = data['category'] - type_layer_needed = data['type_layer_needed'] - - cm_description = data['cm_description'] - cm_url = data['cm_url'] - cm_id = data['cm_id'] - layers_needed = data['layers_needed'] - authorized_scale = "[]" - try: - authorized_scale = data['authorized_scale'] - except: - pass - - description_link = "" - try: - description_link = data['description_link'] - except: - pass - vectors_needed = "[]" - try: - vectors_needed = data['vectors_needed'] - except: - pass - - type_vectors_needed = "[]" - try: - type_vectors_needed = data['type_vectors_needed'] - except: - pass - - updatedAt = datetime.utcnow() - createdAt = datetime.utcnow() - inputs_calculation_module = data['inputs_calculation_module'] - try: - - ln = str(layers_needed) - tn = str(type_layer_needed) - authorized_scale = str(authorized_scale) - description_link = str(description_link) - vectors_needed = str(vectors_needed) - type_vectors_needed = str(type_vectors_needed) - cursor.execute("INSERT INTO calculation_module (cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt, type_layer_needed,authorized_scale,description_link,vectors_needed,type_vectors_needed,wiki_url) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", ( cm_id, cm_name, cm_description, category, cm_url, ln, createdAt, updatedAt,tn,authorized_scale,description_link,vectors_needed,type_vectors_needed,wiki_url )) - conn.commit() - for value in inputs_calculation_module: - input_name = value['input_name'] - input_type = value['input_type'] - input_parameter_name = value['input_parameter_name'] - input_value = str(value['input_value']) - input_priority = 0 - try: - input_priority = value['input_priority'] - except: - pass - input_unit = value['input_unit'] - input_min = value['input_min'] - input_max = value['input_max'] - cm_id = value['cm_id'] - conn = myCMpool.connect() - cursor = conn.cursor() - cursor.execute("INSERT INTO inputs_calculation_module (input_name, input_type, input_parameter_name, input_value,input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (input_name, input_type, input_parameter_name, input_value,input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt)) - - conn.commit() - conn.close() - - except ValidationError: - pass - except sqlite3.IntegrityError as e: - update_calulation_module(cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt,type_layer_needed,authorized_scale,description_link,vectors_needed,inputs_calculation_module,cursor,conn,type_vectors_needed,wiki_url) - - -def update_calulation_module(cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt, type_layer_needed,authorized_scale,description_link,vectors_needed ,inputs_calculation_module,cursor,conn,type_vectors_needed,wiki_url): - try: - ln = str(layers_needed) - tn = str(type_layer_needed) - auth_s = str(authorized_scale) - description_link = str(description_link) - vn = str(vectors_needed) - - type_vectors_needed = str(type_vectors_needed) - - cursor.execute("UPDATE calculation_module SET cm_name = ?, cm_description = ?, category= ?, cm_url= ?, layers_needed= ?, createdAt= ?, updatedAt = ? , type_layer_needed = ?, authorized_scale = ?,description_link = ?, vectors_needed = ?, type_vectors_needed=?, wiki_url=? WHERE cm_id = ? ", ( cm_name, cm_description, category, cm_url,ln , createdAt, updatedAt, tn,auth_s,description_link, vn,type_vectors_needed, wiki_url, cm_id )) - conn.commit() - cursor.execute("DELETE FROM inputs_calculation_module WHERE cm_id = ? ", (str(cm_id))) - conn.commit() - for value in inputs_calculation_module: - input_name = value['input_name'] - input_type = value['input_type'] - input_parameter_name = value['input_parameter_name'] - input_value = str(value['input_value']) - input_priority = 0 - try: - input_priority = value['input_priority'] - except: - pass - input_unit = value['input_unit'] - input_min = value['input_min'] - input_max = value['input_max'] - cm_id = value['cm_id'] - - cursor.execute("INSERT INTO inputs_calculation_module (input_name, input_type, input_parameter_name, input_value, input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (input_name, input_type, input_parameter_name, input_value,input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt)) - conn.commit() - conn.close() - - except ValidationError: - pass - except sqlite3.IntegrityError as e: - pass - -def getUI(cm_id): - conn = myCMpool.connect() - cursor = conn.cursor() - - - results = cursor.execute('select * from inputs_calculation_module where cm_id = ?', - (cm_id,)) - conn.commit() - response = helper.retrieve_list_from_sql_result(results) - - """ valid_condition = assert((cmd_id) in (get_all_cm_ids())() - if valid_condition: - results = cursor.execute('select * from inputs_calculation_module where cm_id = ?', - (cm_id)) - else: - return False()""" - conn.close() - return response - -def delete_cm(cm_id): - delete_cm_with_id(cm_id) - delete_cm_ui_with_id(cm_id) - -def delete_cm_ui_with_id(cm_id): - try: - conn = myCMpool.connect() - cursor = conn.cursor() - - results = cursor.execute('DELETE FROM inputs_calculation_module WHERE cm_id = ?', - (cm_id)) - conn.commit() - conn.close() - return results - - except ValidationError: - pass - except sqlite3.IntegrityError as e: - pass - -def delete_cm_with_id(cm_id): - try: - conn = myCMpool.connect() - cursor = conn.cursor() - - results = cursor.execute('DELETE FROM calculation_module WHERE cm_id = ?', - (cm_id)) - conn.commit() - conn.close() - return results - - except ValidationError: - pass - except sqlite3.IntegrityError as e: - pass - -def getCMList(): - response = helper.retrieve_list_from_sql_result(query_calculation_module_database('select * from calculation_module ')) - return response - -@celery.task(name = 'task-getConnection_db_gis') -def getConnection_db_gis(): - c = psycopg2.connect(get_connection_string()) - return c - -def get_connection_string(): - con = "host=" + HOST_DB + " user=" + USER_DB + " dbname=" + DATABASE_DB + " port=" + PORT_DB + " password=" + PASSWORD_DB + "" - return con - -def get_shapefile_from_selection(scalevalue, id_selected_list, ouput_directory, EPSG=str(3035)): - id_selected_list = helper.adapt_nuts_list(id_selected_list) - - output_shapefile = quote(helper.generate_shapefile_name(ouput_directory)) - if scalevalue == 'nuts': - subprocess.call('ogr2ogr -overwrite -f "ESRI Shapefile" '+output_shapefile+' PG:"'+get_connection_string()+'" -sql "select ST_Union(ST_Transform(geom,'+EPSG+')) from geo.nuts where nuts_id IN ('+ id_selected_list +') AND year = date({})"'.format("'2013-01-01'"), shell=True) - - else: - subprocess.call('ogr2ogr -overwrite -f "ESRI Shapefile" '+output_shapefile+' PG:"'+get_connection_string()+'" -sql "select ST_Union(ST_Transform(geom,'+EPSG+')) from public.tbl_lau1_2 where comm_id IN ('+ id_selected_list +')"', shell=True) - - return output_shapefile - -def get_raster_from_csv(wkt_point, layer_needed, output_directory): - inputs_raster_selection = {} - wkt_point_3035 = helper.projection_4326_to_3035(wkt_point) - filename_csv = helper.write_wkt_csv(helper.generate_csv_name(output_directory),wkt_point_3035) - for layer in layer_needed: - if 'layer_type' in layer: - type = layer['layer_type'] - id = layer['id'] - else: - type = layer['name'] - id = 0 - if id == 0: - dataset_directory = DATASET_DIRECTORY - directory = layer['workspaceName'] - root_path = dataset_directory + directory + "/data/" - path_to_dataset = root_path + layer['workspaceName'] + ".tif" - if not os.path.abspath(path_to_dataset).startswith(root_path): - raise Exception("directory traversal denied") - else: - upload = Uploads.query.get(layer['id']) - path_to_dataset = upload.url - - # create a file name as output - filename_tif = helper.generate_geotif_name(output_directory) - args = commands_in_array("gdalwarp -dstnodata 0 -cutline {} -crop_to_cutline -of GTiff {} {} -tr 100 100 -co COMPRESS=DEFLATE".format(filename_csv, path_to_dataset, filename_tif)) - run_command(args) - #os.system(com_string) - inputs_raster_selection[type] = filename_tif - return inputs_raster_selection - -def clip_raster_from_shapefile(shapefile_path,layer_needed, output_directory): - """ - - :param datasets_directory: input dataset directory - :param shapefile_path: input shapefile path - :param layer_needed: list of layer need for the CM - :param output_directory: output directory where we c - :return: dictionnary - """ - inputs_raster_selection = {} - # retrieve all layer neeeded - for layer in layer_needed: - if 'layer_type' in layer: - type = layer['layer_type'] - id = layer['id'] - else: - type = layer['name'] - id = 0 - if id == 0: - dataset_directory = DATASET_DIRECTORY - directory = layer['workspaceName'] - root_path = dataset_directory + directory + "/data/" - path_to_dataset = root_path + layer['workspaceName'] + ".tif" - if not os.path.abspath(path_to_dataset).startswith(root_path): - raise Exception("directory traversal denied") - else: - upload = Uploads.query.filter_by(id=layer['id']).first() - path_to_dataset = upload.url - # create a file name as output - filename_tif = helper.generate_geotif_name(output_directory) - # The previous option "-tr 100 100" seems to shift the layer - args = commands_in_array("gdalwarp -dstnodata 0 -cutline {} -crop_to_cutline -of GTiff {} {} -co COMPRESS=DEFLATE".format(shapefile_path, path_to_dataset, filename_tif)) - run_command(args) - inputs_raster_selection[type] = filename_tif - - - return inputs_raster_selection - - -def nuts2_within_the_selection_nuts_lau(scalevalue, nuts): - toCRS = 4258 - sql_query = sql_queries.nuts2_within_the_selection_nuts_lau(scalevalue, nuts, toCRS) - result = query_geographic_database(sql_query) - result = helper.retrieve_list_from_sql_result(result) - result = helper.from_dict_to_unique_array(result,'nuts_id') - return result - -def nuts_within_the_selection(geom): - toCRS = 4258 - sql_query = sql_queries.nuts_within_the_selection(geom,toCRS) - result = query_geographic_database(sql_query) - result = helper.retrieve_list_from_sql_result(result) - result = helper.from_dict_to_unique_array(result,'nuts_id') - return result - -def retrieve_vector_data_for_calculation_module(vectors_needed, scalevalue, area_selected): - """ - this function will return an array of vectors from the database - :param vectors_needed: - :param scalevalue: - :param area_selected: list of nut or geometry - :return: - """ - inputs_vectors_selection = {} - - for vector_table_requested in vectors_needed: - layer_path = '' - layer_id = vector_table_requested['id'] - layer_type = vector_table_requested['layer_type'] - if layer_id == 0: - if scalevalue == 'hectare': - layer_path = ExportCut.cut_hectares(area_selected, layer_type + "_ha", 'public', '2012') - print(layer_type + "_ha") - else: - layer_path = ExportCut.cut_nuts(layer_type + "_" + scalevalue, area_selected, 'public', '2012') - else: - - upload = Uploads.query.filter_by(id=layer_id).first() - path_to_dataset = upload.url - layer_path = ExportCut.cut_personal_layer(scalevalue, path_to_dataset, area_selected)['path'] - inputs_vectors_selection[layer_type] = layer_path - print(layer_path, layer_id, layer_type) - return inputs_vectors_selection - -def get_vectors_needed(cm_id): - conn = myCMpool.connect() - cursor = conn.cursor() - vectors_needed = cursor.execute('select vectors_needed from calculation_module where cm_id = ?', - (cm_id)) - conn.commit() - vectors_needed = vectors_needed.fetchone()[0] - vectors_needed = helper.unicode_array_to_string(vectors_needed) - conn.close() - return vectors_needed - - -def query_geographic_database(sql_query): - mypool = pool.QueuePool(getConnection_db_gis, max_overflow=100, pool_size=5) - # get a connectioncommands_in_array - conn = mypool.connect() - # use it - cursor = query(sql_query,conn) - return cursor - -def query_geographic_database_first(sql_query): - cursor = query_geographic_database(sql_query) - result = cursor.fetchone() - return result - -def check_table_existe(sql_query): - return query_geographic_database_first(sql_query) - -def query_calculation_module_database(sql_query): - - # get a connection - conn = myCMpool.connect() - # use it - cursor = conn.cursor() - - cursor.execute(sql_query) - conn.commit() - conn.close() - - - return cursor - -def query(sql_query,conn): - - # use it - cursor = conn.cursor() - - cursor.execute(sql_query) - conn.commit() - conn.close() - - - return cursor - -def get_cutline_input(areas, scalelevel, data_type): - if scalelevel == 'hectare': - areas = area_to_geom(areas) - if data_type == 'raster': - areas = projection_4326_to_3035(areas) - - return write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), areas) - else: - return get_shapefile_from_selection(scalelevel, areas, - constants.UPLOAD_DIRECTORY, '4326') - # if data_type == 'raster': - # if scalelevel == 'hectare': - # areas = area_to_geom(areas) - # cutline_input = write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), projection_4326_to_3035(areas)) # TODO: Projection to 3035 if raster - # else: - # cutline_input = get_shapefile_from_selection(scalelevel, areas, - # constants.UPLOAD_DIRECTORY, '4326') - # elif data_type == 'vector': - # if scalelevel == 'hectare': - # areas = area_to_geom(areas) - # cutline_input = write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), - # areas) - # else: - # cutline_input = get_shapefile_from_selection(scalelevel, areas, - # constants.UPLOAD_DIRECTORY, '4326') - # return cutline_input - -class ExportCut: - @staticmethod - def cut_nuts(layers: str, nuts: list, schema: str, year: str): - """ - The method called to cut a given list of nuts into a csv - :param layers: the layer selected - :param nuts: the list of nuts to export - :param schema: the DB schema - :param year: the data year - :return: - """ - csv_result = get_csv_from_nuts(layers=layers, nuts=nuts, schema=schema, year=year) - return ExportCut.save_file_csv_random_name(content=csv_result) - - @staticmethod - def cut_personal_layer(scale_level, upload_url, areas): - """ - The method called to cut a given list of nuts or a selection into a csv for a presonal layer - :param scale_level: nuts, lau or hectare - :param upload_url: the URL of the selected personal layer - :param areas: the selection on the map - :return: - """ - if scale_level == 'hectare': - areas = area_to_geom(areas) - cutline_input = write_wkt_csv(generate_csv_name(UPLOAD_DIRECTORY), areas) - else: - cutline_input = get_shapefile_from_selection(scale_level[:-1], areas, UPLOAD_DIRECTORY, '4326') - print(cutline_input) - cmd_cutline, output_csv = prepare_clip_personal_layer(cutline_input, upload_url) - args = app.helper.commands_in_array(cmd_cutline) - app.helper.run_command(args) - if not os.path.isfile(output_csv): - return { - "message": "not a csv file" - } - return { - "path": output_csv - } - - @staticmethod - def cut_hectares(areas: list, layers: str, schema: str, year: str): - """ - The method called to cut a given selection of hectares into a csv - :param areas: the area to cut - :param layers: the layer to select - :param schema: the DB schema - :param year: the data_year - :return: - """ - csv_result = get_csv_from_hectare(areas=areas, layers=layers, schema=schema, year=year) - return ExportCut.save_file_csv_random_name(content=csv_result) - - @staticmethod - def save_file_csv_random_name(content): - """ - Save a file into a temp folder with a random name - :param content: the content of the file you want to write - :return random_name: the name randomly generated - """ - path = ExportCut.generate_random_file_name() - content_str = content.getvalue() - with open(path, 'w', encoding='utf8') as f: - f.write(content_str) - return path - - @staticmethod - def generate_random_file_name(extension: str = '.csv'): - """ - generate a random file name - :param extension: the extension of the file, default to .csv - :return: the path of the generated file name or None if extension doesn't start with a dot - """ - # the extension must be an extension - if not extension.startswith('.'): - return None - - random_name = uuid.uuid4().hex + '.csv' - path = UPLOAD_DIRECTORY + '/' + random_name - return path - - -def get_csv_from_nuts(layers, nuts, schema, year): - """ - This method will generate a CSV from a nuts or list of nuts - :param layers: the layer selected - :param nuts: the selection - :param schema: the schema of the layer in the DB - :param year: the year of the data - :return:the csv containing the results - """ - # We must determine if it is a nuts or a lau - dateCol = "year" - schema2 = "geo" - if str(layers).endswith('lau2'): - layer_type = 'lau' - layer_name = layers[: -5] - id_type = 'comm_id' - layer_date = LAU_YEAR - dateCol = "date" - schema2 = "public" - - else: - scale = str(layers)[-5:] - layer_type = 'nuts' - layer_name = str(layers)[: -6] - id_type = 'nuts_id' - layer_date = NUTS_YEAR - if scale not in ['nuts3', 'nuts2', 'nuts1', 'nuts0']: - # allow co2 emission factors layer - if 'yearly_co2_emission_factors_view' in str(layers): - layer_name = 'yearly_co2_emission_factors_view' - else: - raise HugeRequestException(message=scale) - # handle special case of wwtp where geom column has a different name (manual integration) - geom_col_name = 'geometry' if layer_name.startswith('wwtp') else 'geom' - # check if year exists otherwise get most recent or fallback to default (1970) - # timestamp to year if necessary: SELECT TO_CHAR(timestamp :: DATE, 'yyyy') - date_sql = """SELECT timestamp FROM {0}.{1} GROUP BY timestamp ORDER BY timestamp DESC;""".format(schema, - layer_name) - try: - results = db.engine.execute(date_sql) - except: - raise RequestException("Failed retrieving year in database") - layer_year = year + '-01-01' - dates = [] - for row in results: - dates.append(row[0]) - if len(dates) == 0: - layer_year = '1970-01-01' - elif layer_year not in dates: - layer_year = dates[0] - # build query - sql = """ - WITH _ as (SELECT geom as _ from {6}.{3} WHERE {4} IN ({5}) AND {7} = '{8}-01-01') - SELECT ST_ASTEXT({9}) as geometry_wkt, ST_SRID({9}) as srid, {0}.{1}.* - FROM {0}.{1}, _ - WHERE timestamp = '{2}' - AND ST_Within({0}.{1}.{9}, st_transform( - _._, ST_SRID({9}) - )) - ;""".format( - schema, # 0 - layer_name, # 1 - layer_year, # 2 - layer_type, # 3 - id_type, # 4 - ', '.join("'{0}'".format(n) for n in nuts), # 5 - schema2, # 6 - dateCol, # 7 - layer_date, # 8 - geom_col_name # 9 - ) - # execute query - try: - result = db.engine.execute(sql) - except: - raise RequestException("Problem with your SQL query") - - # build CSV - return generate_csv_string(result) - - -def get_csv_from_hectare(areas, layers, schema, year): - """ - this method will generate a csv from hectare selection - :param areas: the selection - :param layers: the layer selected - :param schema: the schema of the layer in the db - :param year: the year of the data - :return: the csv containing the results - """ - if not str(layers).endswith('_ha'): - raise RequestException("this is not a correct layer for an hectare selection !") - # format the layer_name to contain only the name - layer_name = layers[:-3] - # build request - polyArray = [] - # convert to polygon format for each polygon and store them in polyArray - try: - for polygon in areas: - po = shapely_geom.Polygon([[p['lng'], p['lat']] for p in polygon['points']]) - polyArray.append(po) - except: - raise NotEnoughPointsException - # convert array of polygon into multipolygon - multipolygon = shapely_geom.MultiPolygon(polyArray) - # handle special case of wwtp where geom column has a different name (manual integration) - geom_col_name = 'geometry' if layer_name.startswith('wwtp') else 'geom' - # check if year exists otherwise get most recent or fallback to default (1970) - date_sql = """SELECT timestamp FROM {0}.{1} GROUP BY timestamp ORDER BY timestamp DESC;""".format(schema, - layer_name) - try: - results = db.engine.execute(date_sql) - except: - raise RequestException("Failed retrieving year in database") - layer_year = year + '-01-01' - dates = [] - for row in results: - dates.append(row[0]) - if len(dates) == 0: - layer_year = '1970-01-01' - elif layer_year not in dates: - layer_year = dates[0] - # build query - sql = """SELECT ST_ASTEXT({3}) as geometry_wkt, ST_SRID({3}) as srid, * - FROM {0}.{1} WHERE timestamp = '{2}' - AND ST_Within({0}.{1}.{3}, st_transform(st_geomfromtext('{4}', 4258), ST_SRID({3}) - ));""".format(schema, layer_name, layer_year, geom_col_name, str(multipolygon)) - # execute query - try: - result = db.engine.execute(sql) - except: - raise RequestException("Problem with your SQL query") - - - return generate_csv_string(result) - - -def prepare_clip_personal_layer(cutline_input, upload_url): - """ - Helper method to clip a personal layer - :param cutline_input: - :param upload_url: the url of the upload - :return: a tuple containing the command to use later ant the output csv path - """ - #upload_url += "data.csv" - output_csv = generate_csv_name(constants.UPLOAD_DIRECTORY) - cmd_cutline = "ogr2ogr -f 'CSV' -clipsrc {} {} {} -oo GEOM_POSSIBLE_NAMES=geometry_wkt -oo KEEP_GEOM_COLUMNS=NO".format( - cutline_input, output_csv, upload_url) - return cmd_cutline, output_csv +import os +import sqlite3 +import subprocess +import uuid +from datetime import datetime + +import app.helper +import psycopg2 +import shapely.geometry as shapely_geom +import sqlalchemy.pool as pool +from app import celery, constants +from app import dbGIS as db +from app import helper, sql_queries +from app.constants import ( + CM_DB_NAME, DATABASE_DB, DATASET_DIRECTORY, HOST_DB, LAU_YEAR, NUTS_YEAR, + PASSWORD_DB, PORT_DB, UPLOAD_DIRECTORY, USER_DB) +from app.decorators.exceptions import (HugeRequestException, + NotEnoughPointsException, + RequestException, ValidationError) + +from .helper import (area_to_geom, commands_in_array, generate_csv_name, + projection_4326_to_3035, run_command, write_wkt_csv) +from .models.uploads import Uploads, generate_csv_string + +try: + from shlex import quote +except ImportError: + from pipes import quote +try: + import ogr +except ImportError: + from osgeo import ogr + +try: + import osr +except ImportError: + from osgeo import osr +basedir = os.path.abspath(os.path.dirname(__file__)) + +db_path = os.path.join(basedir, '../data.sqlite') + +DB_NAME = CM_DB_NAME + +def getConnection_db_CM(): + c = sqlite3.connect(DB_NAME) + return c + + +myCMpool = pool.QueuePool(getConnection_db_CM, max_overflow=10, pool_size=15) + + +def addRegisterCalulationModule(data): + """ + this request will get the signature of a CM and will insert it to the database + :param data: signature payload of the CM + :return: + """ + + cm_name = data['cm_name'] + + + + wiki_url = "" + try: + wiki_url = data['wiki_url'] + except: + pass + category = data['category'] + type_layer_needed = data['type_layer_needed'] + authorized_scale = "[]" + try: + authorized_scale = data['authorized_scale'] + except: + pass + description_link = "" + try: + description_link = data['description_link'] + except: + pass + vectors_needed = "[]" + try: + vectors_needed = data['vectors_needed'] + except: + pass + + try: + type_vectors_needed = data['type_vectors_needed'] + except: + pass + cm_description = data['cm_description'] + cm_url = data['cm_url'] + cm_Id = data['id'] + layers_needed = data['layers_needed'] + updatedAt = datetime.utcnow() + createdAt = datetime.utcnow() + conn = myCMpool.connect() + cursor = conn.cursor() + cursor.execute("INSERT INTO calculation_module (cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updateAt,type_layer_needed,authorized_scale,description_link,vectors_needed,wiki_url) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", ( cm_Id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt ,type_layer_needed,authorized_scale,description_link,vectors_needed,type_vectors_needed,wiki_url)) + cursor.close() + +def init_sqlite_caculation_module_database(dbname=DB_NAME): + """ + + :param dbname: this part will manually create the database for CM + :return: conn : this is the connection to the database + """ + conn = sqlite3.connect(dbname) + cursor = conn.cursor() + cursor.execute("DROP TABLE IF EXISTS calculation_module") + cursor.execute("CREATE TABLE calculation_module (cm_id INTEGER NOT NULL, cm_name VARCHAR(255), wiki_url VARCHAR(255)," + "cm_description VARCHAR(255),cm_url VARCHAR(255),category VARCHAR(255),layers_needed VARCHAR(255),authorized_scale VARCHAR(255),description_link VARCHAR(255),createdAt REAL(255),updatedAt REAL(255),type_layer_needed REAL(255),vectors_needed REAL(255),type_vectors_needed REAL(255)," + " PRIMARY KEY(cm_id))") + conn.commit() + cursor.execute("DROP TABLE IF EXISTS inputs_calculation_module") + cursor.execute("CREATE TABLE inputs_calculation_module (input_id INTEGER NOT NULL, input_name VARCHAR(255), " + "input_type VARCHAR(255),input_parameter_name VARCHAR(255),input_value VARCHAR(255),input_priority INTEGER, input_unit VARCHAR(255)," + "input_min INTEGER,input_max INTEGER,createdAt REAL(255),updatedAt REAL(255),cm_id INTEGER NOT NULL," + " PRIMARY KEY(input_id),FOREIGN KEY(cm_id) REFERENCES calculation_module(cm_id))") + conn.commit() + return conn + +def register_calulation_module(data): + if data is not None: + conn = myCMpool.connect() + cursor = conn.cursor() + cm_name = data['cm_name'] + + + wiki_url = "" + try: + wiki_url = data['wiki_url'] + except: + pass + category = data['category'] + type_layer_needed = data['type_layer_needed'] + + cm_description = data['cm_description'] + cm_url = data['cm_url'] + cm_id = data['cm_id'] + layers_needed = data['layers_needed'] + authorized_scale = "[]" + try: + authorized_scale = data['authorized_scale'] + except: + pass + + description_link = "" + try: + description_link = data['description_link'] + except: + pass + vectors_needed = "[]" + try: + vectors_needed = data['vectors_needed'] + except: + pass + + type_vectors_needed = "[]" + try: + type_vectors_needed = data['type_vectors_needed'] + except: + pass + + updatedAt = datetime.utcnow() + createdAt = datetime.utcnow() + inputs_calculation_module = data['inputs_calculation_module'] + try: + + ln = str(layers_needed) + tn = str(type_layer_needed) + authorized_scale = str(authorized_scale) + description_link = str(description_link) + vectors_needed = str(vectors_needed) + type_vectors_needed = str(type_vectors_needed) + cursor.execute("INSERT INTO calculation_module (cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt, type_layer_needed,authorized_scale,description_link,vectors_needed,type_vectors_needed,wiki_url) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", ( cm_id, cm_name, cm_description, category, cm_url, ln, createdAt, updatedAt,tn,authorized_scale,description_link,vectors_needed,type_vectors_needed,wiki_url )) + conn.commit() + for value in inputs_calculation_module: + input_name = value['input_name'] + input_type = value['input_type'] + input_parameter_name = value['input_parameter_name'] + input_value = str(value['input_value']) + input_priority = 0 + try: + input_priority = value['input_priority'] + except: + pass + input_unit = value['input_unit'] + input_min = value['input_min'] + input_max = value['input_max'] + cm_id = value['cm_id'] + conn = myCMpool.connect() + cursor = conn.cursor() + cursor.execute("INSERT INTO inputs_calculation_module (input_name, input_type, input_parameter_name, input_value,input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (input_name, input_type, input_parameter_name, input_value,input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt)) + + conn.commit() + conn.close() + + except ValidationError: + pass + except sqlite3.IntegrityError as e: + update_calulation_module(cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt,type_layer_needed,authorized_scale,description_link,vectors_needed,inputs_calculation_module,cursor,conn,type_vectors_needed,wiki_url) + + +def update_calulation_module(cm_id, cm_name, cm_description, category, cm_url, layers_needed, createdAt, updatedAt, type_layer_needed,authorized_scale,description_link,vectors_needed ,inputs_calculation_module,cursor,conn,type_vectors_needed,wiki_url): + try: + ln = str(layers_needed) + tn = str(type_layer_needed) + auth_s = str(authorized_scale) + description_link = str(description_link) + vn = str(vectors_needed) + + type_vectors_needed = str(type_vectors_needed) + + cursor.execute("UPDATE calculation_module SET cm_name = ?, cm_description = ?, category= ?, cm_url= ?, layers_needed= ?, createdAt= ?, updatedAt = ? , type_layer_needed = ?, authorized_scale = ?,description_link = ?, vectors_needed = ?, type_vectors_needed=?, wiki_url=? WHERE cm_id = ? ", ( cm_name, cm_description, category, cm_url,ln , createdAt, updatedAt, tn,auth_s,description_link, vn,type_vectors_needed, wiki_url, cm_id )) + conn.commit() + cursor.execute("DELETE FROM inputs_calculation_module WHERE cm_id = ? ", (str(cm_id))) + conn.commit() + for value in inputs_calculation_module: + input_name = value['input_name'] + input_type = value['input_type'] + input_parameter_name = value['input_parameter_name'] + input_value = str(value['input_value']) + input_priority = 0 + try: + input_priority = value['input_priority'] + except: + pass + input_unit = value['input_unit'] + input_min = value['input_min'] + input_max = value['input_max'] + cm_id = value['cm_id'] + + cursor.execute("INSERT INTO inputs_calculation_module (input_name, input_type, input_parameter_name, input_value, input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (input_name, input_type, input_parameter_name, input_value,input_priority, input_unit, input_min, input_max, cm_id, createdAt,updatedAt)) + conn.commit() + conn.close() + + except ValidationError: + pass + except sqlite3.IntegrityError as e: + pass + +def getUI(cm_id): + conn = myCMpool.connect() + cursor = conn.cursor() + + + results = cursor.execute('select * from inputs_calculation_module where cm_id = ?', + (cm_id,)) + conn.commit() + response = helper.retrieve_list_from_sql_result(results) + + """ valid_condition = assert((cmd_id) in (get_all_cm_ids())() + if valid_condition: + results = cursor.execute('select * from inputs_calculation_module where cm_id = ?', + (cm_id)) + else: + return False()""" + conn.close() + return response + +def delete_cm(cm_id): + delete_cm_with_id(cm_id) + delete_cm_ui_with_id(cm_id) + +def delete_cm_ui_with_id(cm_id): + try: + conn = myCMpool.connect() + cursor = conn.cursor() + + results = cursor.execute('DELETE FROM inputs_calculation_module WHERE cm_id = ?', + (cm_id)) + conn.commit() + conn.close() + return results + + except ValidationError: + pass + except sqlite3.IntegrityError as e: + pass + +def delete_cm_with_id(cm_id): + try: + conn = myCMpool.connect() + cursor = conn.cursor() + + results = cursor.execute('DELETE FROM calculation_module WHERE cm_id = ?', + (cm_id)) + conn.commit() + conn.close() + return results + + except ValidationError: + pass + except sqlite3.IntegrityError as e: + pass + +def getCMList(): + response = helper.retrieve_list_from_sql_result(query_calculation_module_database('select * from calculation_module ')) + return response + +@celery.task(name = 'task-getConnection_db_gis') +def getConnection_db_gis(): + c = psycopg2.connect(get_connection_string()) + return c + +def get_connection_string(): + con = "host=" + HOST_DB + " user=" + USER_DB + " dbname=" + DATABASE_DB + " port=" + PORT_DB + " password=" + PASSWORD_DB + "" + return con + +def get_shapefile_from_selection(scalevalue, id_selected_list, ouput_directory, EPSG=str(3035)): + id_selected_list = helper.adapt_nuts_list(id_selected_list) + + output_shapefile = quote(helper.generate_shapefile_name(ouput_directory)) + if scalevalue == 'nuts': + subprocess.call('ogr2ogr -overwrite -f "ESRI Shapefile" '+output_shapefile+' PG:"'+get_connection_string()+'" -sql "select ST_Union(ST_Transform(geom,'+EPSG+')) from geo.nuts where nuts_id IN ('+ id_selected_list +') AND year = date({})"'.format("'2013-01-01'"), shell=True) + + else: + subprocess.call('ogr2ogr -overwrite -f "ESRI Shapefile" '+output_shapefile+' PG:"'+get_connection_string()+'" -sql "select ST_Union(ST_Transform(geom,'+EPSG+')) from public.tbl_lau1_2 where comm_id IN ('+ id_selected_list +')"', shell=True) + + return output_shapefile + +def get_raster_from_csv(wkt_point, layer_needed, output_directory): + inputs_raster_selection = {} + wkt_point_3035 = helper.projection_4326_to_3035(wkt_point) + filename_csv = helper.write_wkt_csv(helper.generate_csv_name(output_directory),wkt_point_3035) + for layer in layer_needed: + if 'layer_type' in layer: + type = layer['layer_type'] + id = layer['id'] + else: + type = layer['name'] + id = 0 + if id == 0: + dataset_directory = DATASET_DIRECTORY + directory = layer['workspaceName'] + root_path = dataset_directory + directory + "/data/" + path_to_dataset = root_path + layer['workspaceName'] + ".tif" + if not os.path.abspath(path_to_dataset).startswith(root_path): + raise Exception("directory traversal denied") + else: + upload = Uploads.query.get(layer['id']) + path_to_dataset = upload.url + + # create a file name as output + filename_tif = helper.generate_geotif_name(output_directory) + args = commands_in_array("gdalwarp -dstnodata 0 -cutline {} -crop_to_cutline -of GTiff {} {} -tr 100 100 -co COMPRESS=DEFLATE".format(filename_csv, path_to_dataset, filename_tif)) + run_command(args) + #os.system(com_string) + inputs_raster_selection[type] = filename_tif + return inputs_raster_selection + +def clip_raster_from_shapefile(shapefile_path,layer_needed, output_directory): + """ + + :param datasets_directory: input dataset directory + :param shapefile_path: input shapefile path + :param layer_needed: list of layer need for the CM + :param output_directory: output directory where we c + :return: dictionnary + """ + inputs_raster_selection = {} + # retrieve all layer neeeded + for layer in layer_needed: + if 'layer_type' in layer: + type = layer['layer_type'] + id = layer['id'] + else: + type = layer['name'] + id = 0 + if id == 0: + dataset_directory = DATASET_DIRECTORY + directory = layer['workspaceName'] + root_path = dataset_directory + directory + "/data/" + path_to_dataset = root_path + layer['workspaceName'] + ".tif" + if not os.path.abspath(path_to_dataset).startswith(root_path): + raise Exception("directory traversal denied") + else: + upload = Uploads.query.filter_by(id=layer['id']).first() + path_to_dataset = upload.url + # create a file name as output + filename_tif = helper.generate_geotif_name(output_directory) + # The previous option "-tr 100 100" seems to shift the layer + args = commands_in_array("gdalwarp -dstnodata 0 -cutline {} -crop_to_cutline -of GTiff {} {} -co COMPRESS=DEFLATE".format(shapefile_path, path_to_dataset, filename_tif)) + run_command(args) + inputs_raster_selection[type] = filename_tif + + + return inputs_raster_selection + + +def nuts2_within_the_selection_nuts_lau(scalevalue, nuts): + toCRS = 4258 + sql_query = sql_queries.nuts2_within_the_selection_nuts_lau(scalevalue, nuts, toCRS) + result = query_geographic_database(sql_query) + result = helper.retrieve_list_from_sql_result(result) + result = helper.from_dict_to_unique_array(result,'nuts_id') + return result + +def nuts_within_the_selection(geom): + toCRS = 4258 + sql_query = sql_queries.nuts_within_the_selection(geom,toCRS) + result = query_geographic_database(sql_query) + result = helper.retrieve_list_from_sql_result(result) + result = helper.from_dict_to_unique_array(result,'nuts_id') + return result + +def retrieve_vector_data_for_calculation_module(vectors_needed, scalevalue, area_selected): + """ + this function will return an array of vectors from the database + :param vectors_needed: + :param scalevalue: + :param area_selected: list of nut or geometry + :return: + """ + inputs_vectors_selection = {} + + for vector_table_requested in vectors_needed: + layer_path = '' + layer_id = vector_table_requested['id'] + layer_type = vector_table_requested['layer_type'] + if layer_id == 0: + if scalevalue == 'hectare': + layer_path = ExportCut.cut_hectares(area_selected, layer_type + "_ha", 'public', '2012') + print(layer_type + "_ha") + else: + layer_path = ExportCut.cut_nuts(layer_type + "_" + scalevalue, area_selected, 'public', '2012') + else: + + upload = Uploads.query.filter_by(id=layer_id).first() + path_to_dataset = upload.url + layer_path = ExportCut.cut_personal_layer(scalevalue, path_to_dataset, area_selected)['path'] + inputs_vectors_selection[layer_type] = layer_path + print(layer_path, layer_id, layer_type) + return inputs_vectors_selection + +def get_vectors_needed(cm_id): + conn = myCMpool.connect() + cursor = conn.cursor() + vectors_needed = cursor.execute('select vectors_needed from calculation_module where cm_id = ?', + (cm_id)) + conn.commit() + vectors_needed = vectors_needed.fetchone()[0] + vectors_needed = helper.unicode_array_to_string(vectors_needed) + conn.close() + return vectors_needed + + +def query_geographic_database(sql_query): + mypool = pool.QueuePool(getConnection_db_gis, max_overflow=100, pool_size=5) + # get a connectioncommands_in_array + conn = mypool.connect() + # use it + cursor = query(sql_query,conn) + return cursor + +def query_geographic_database_first(sql_query): + cursor = query_geographic_database(sql_query) + result = cursor.fetchone() + return result + +def check_table_existe(sql_query): + return query_geographic_database_first(sql_query) + +def query_calculation_module_database(sql_query): + + # get a connection + conn = myCMpool.connect() + # use it + cursor = conn.cursor() + + cursor.execute(sql_query) + conn.commit() + conn.close() + + + return cursor + +def query(sql_query,conn): + + # use it + cursor = conn.cursor() + + cursor.execute(sql_query) + conn.commit() + conn.close() + + + return cursor + +def get_cutline_input(areas, scalelevel, data_type): + if scalelevel == 'hectare': + areas = area_to_geom(areas) + if data_type == 'raster': + areas = projection_4326_to_3035(areas) + + return write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), areas) + else: + return get_shapefile_from_selection(scalelevel, areas, + constants.UPLOAD_DIRECTORY, '4326') + # if data_type == 'raster': + # if scalelevel == 'hectare': + # areas = area_to_geom(areas) + # cutline_input = write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), projection_4326_to_3035(areas)) # TODO: Projection to 3035 if raster + # else: + # cutline_input = get_shapefile_from_selection(scalelevel, areas, + # constants.UPLOAD_DIRECTORY, '4326') + # elif data_type == 'vector': + # if scalelevel == 'hectare': + # areas = area_to_geom(areas) + # cutline_input = write_wkt_csv(generate_csv_name(constants.UPLOAD_DIRECTORY), + # areas) + # else: + # cutline_input = get_shapefile_from_selection(scalelevel, areas, + # constants.UPLOAD_DIRECTORY, '4326') + # return cutline_input + +class ExportCut: + @staticmethod + def cut_nuts(layers: str, nuts: list, schema: str, year: str): + """ + The method called to cut a given list of nuts into a csv + :param layers: the layer selected + :param nuts: the list of nuts to export + :param schema: the DB schema + :param year: the data year + :return: + """ + csv_result = get_csv_from_nuts(layers=layers, nuts=nuts, schema=schema, year=year) + return ExportCut.save_file_csv_random_name(content=csv_result) + + @staticmethod + def cut_personal_layer(scale_level, upload_url, areas): + """ + The method called to cut a given list of nuts or a selection into a csv for a presonal layer + :param scale_level: nuts, lau or hectare + :param upload_url: the URL of the selected personal layer + :param areas: the selection on the map + :return: + """ + if scale_level == 'hectare': + areas = area_to_geom(areas) + cutline_input = write_wkt_csv(generate_csv_name(UPLOAD_DIRECTORY), areas) + else: + cutline_input = get_shapefile_from_selection(scale_level[:-1], areas, UPLOAD_DIRECTORY, '4326') + print(cutline_input) + cmd_cutline, output_csv = prepare_clip_personal_layer(cutline_input, upload_url) + args = app.helper.commands_in_array(cmd_cutline) + app.helper.run_command(args) + if not os.path.isfile(output_csv): + return { + "message": "not a csv file" + } + return { + "path": output_csv + } + + @staticmethod + def cut_hectares(areas: list, layers: str, schema: str, year: str): + """ + The method called to cut a given selection of hectares into a csv + :param areas: the area to cut + :param layers: the layer to select + :param schema: the DB schema + :param year: the data_year + :return: + """ + csv_result = get_csv_from_hectare(areas=areas, layers=layers, schema=schema, year=year) + return ExportCut.save_file_csv_random_name(content=csv_result) + + @staticmethod + def save_file_csv_random_name(content): + """ + Save a file into a temp folder with a random name + :param content: the content of the file you want to write + :return random_name: the name randomly generated + """ + path = ExportCut.generate_random_file_name() + content_str = content.getvalue() + with open(path, 'w', encoding='utf8') as f: + f.write(content_str) + return path + + @staticmethod + def generate_random_file_name(extension: str = '.csv'): + """ + generate a random file name + :param extension: the extension of the file, default to .csv + :return: the path of the generated file name or None if extension doesn't start with a dot + """ + # the extension must be an extension + if not extension.startswith('.'): + return None + + random_name = uuid.uuid4().hex + '.csv' + path = UPLOAD_DIRECTORY + '/' + random_name + return path + + +def get_csv_from_nuts(layers, nuts, schema, year): + """ + This method will generate a CSV from a nuts or list of nuts + :param layers: the layer selected + :param nuts: the selection + :param schema: the schema of the layer in the DB + :param year: the year of the data + :return:the csv containing the results + """ + # We must determine if it is a nuts or a lau + dateCol = "year" + schema2 = "geo" + if str(layers).endswith('lau2'): + layer_type = 'lau' + layer_name = layers[: -5] + id_type = 'comm_id' + layer_date = LAU_YEAR + dateCol = "date" + schema2 = "public" + + else: + scale = str(layers)[-5:] + layer_type = 'nuts' + layer_name = str(layers)[: -6] + id_type = 'nuts_id' + layer_date = NUTS_YEAR + if scale not in ['nuts3', 'nuts2', 'nuts1', 'nuts0']: + # allow co2 emission factors layer + if 'yearly_co2_emission_factors_view' in str(layers): + layer_name = 'yearly_co2_emission_factors_view' + else: + raise HugeRequestException(message=scale) + # handle special case of wwtp where geom column has a different name (manual integration) + geom_col_name = 'geometry' if layer_name.startswith('wwtp') else 'geom' + # check if year exists otherwise get most recent or fallback to default (1970) + # timestamp to year if necessary: SELECT TO_CHAR(timestamp :: DATE, 'yyyy') + date_sql = """SELECT timestamp FROM {0}.{1} GROUP BY timestamp ORDER BY timestamp DESC;""".format(schema, + layer_name) + try: + results = db.engine.execute(date_sql) + except: + raise RequestException("Failed retrieving year in database") + layer_year = year + '-01-01' + dates = [] + for row in results: + dates.append(row[0]) + if len(dates) == 0: + layer_year = '1970-01-01' + elif layer_year not in dates: + layer_year = dates[0] + # build query + sql = """ + WITH _ as (SELECT geom as _ from {6}.{3} WHERE {4} IN ({5}) AND {7} = '{8}-01-01') + SELECT ST_ASTEXT({9}) as geometry_wkt, ST_SRID({9}) as srid, {0}.{1}.* + FROM {0}.{1}, _ + WHERE timestamp = '{2}' + AND ST_Within({0}.{1}.{9}, st_transform( + _._, ST_SRID({9}) + )) + ;""".format( + schema, # 0 + layer_name, # 1 + layer_year, # 2 + layer_type, # 3 + id_type, # 4 + ', '.join("'{0}'".format(n) for n in nuts), # 5 + schema2, # 6 + dateCol, # 7 + layer_date, # 8 + geom_col_name # 9 + ) + # execute query + try: + result = db.engine.execute(sql) + except: + raise RequestException("Problem with your SQL query") + + # build CSV + return generate_csv_string(result) + + +def get_csv_from_hectare(areas, layers, schema, year): + """ + this method will generate a csv from hectare selection + :param areas: the selection + :param layers: the layer selected + :param schema: the schema of the layer in the db + :param year: the year of the data + :return: the csv containing the results + """ + if not str(layers).endswith('_ha'): + raise RequestException("this is not a correct layer for an hectare selection !") + # format the layer_name to contain only the name + layer_name = layers[:-3] + # build request + polyArray = [] + # convert to polygon format for each polygon and store them in polyArray + try: + for polygon in areas: + po = shapely_geom.Polygon([[p['lng'], p['lat']] for p in polygon['points']]) + polyArray.append(po) + except: + raise NotEnoughPointsException + # convert array of polygon into multipolygon + multipolygon = shapely_geom.MultiPolygon(polyArray) + # handle special case of wwtp where geom column has a different name (manual integration) + geom_col_name = 'geometry' if layer_name.startswith('wwtp') else 'geom' + # check if year exists otherwise get most recent or fallback to default (1970) + date_sql = """SELECT timestamp FROM {0}.{1} GROUP BY timestamp ORDER BY timestamp DESC;""".format(schema, + layer_name) + try: + results = db.engine.execute(date_sql) + except: + raise RequestException("Failed retrieving year in database") + layer_year = year + '-01-01' + dates = [] + for row in results: + dates.append(row[0]) + if len(dates) == 0: + layer_year = '1970-01-01' + elif layer_year not in dates: + layer_year = dates[0] + # build query + sql = """SELECT ST_ASTEXT({3}) as geometry_wkt, ST_SRID({3}) as srid, * + FROM {0}.{1} WHERE timestamp = '{2}' + AND ST_Within({0}.{1}.{3}, st_transform(st_geomfromtext('{4}', 4258), ST_SRID({3}) + ));""".format(schema, layer_name, layer_year, geom_col_name, str(multipolygon)) + # execute query + try: + result = db.engine.execute(sql) + except: + raise RequestException("Problem with your SQL query") + + + return generate_csv_string(result) + + +def prepare_clip_personal_layer(cutline_input, upload_url): + """ + Helper method to clip a personal layer + :param cutline_input: + :param upload_url: the url of the upload + :return: a tuple containing the command to use later ant the output csv path + """ + #upload_url += "data.csv" + output_csv = generate_csv_name(constants.UPLOAD_DIRECTORY) + cmd_cutline = "ogr2ogr -f 'CSV' -clipsrc {} {} {} -oo GEOM_POSSIBLE_NAMES=geometry_wkt -oo KEEP_GEOM_COLUMNS=NO".format( + cutline_input, output_csv, upload_url) + return cmd_cutline, output_csv diff --git a/api/app/models/gdal2tiles.py b/api/app/models/gdal2tiles.py index fa59212a..9acb7599 100644 --- a/api/app/models/gdal2tiles.py +++ b/api/app/models/gdal2tiles.py @@ -38,6 +38,8 @@ # DEALINGS IN THE SOFTWARE. # ****************************************************************************** +import math +import os import sys try: @@ -48,8 +50,6 @@ print 'You are using "old gen" bindings. gdal2tiles needs "new gen" bindings.' sys.exit(1) -import os -import math try: from PIL import Image @@ -112,7 +112,6 @@ Class is available under the open-source GDAL license (www.gdal.org). """ -import math MAXZOOMLEVEL = 32 diff --git a/api/app/models/generalData.py b/api/app/models/generalData.py index 44ae90e9..4205f3d4 100644 --- a/api/app/models/generalData.py +++ b/api/app/models/generalData.py @@ -1,163 +1,164 @@ +from app.constants import (CRS_LAU, CRS_NUTS, CRS_USER_GEOMETRY, LAU_TABLE, + NUTS_LAU_LEVELS, NUTS_VAlUES) from app.models.indicators import * -from app.constants import CRS_USER_GEOMETRY, NUTS_VAlUES, NUTS_LAU_LEVELS, CRS_NUTS,CRS_LAU,LAU_TABLE def constructWithPartEachLayerHectare(geometry, year, layer, scale_level): - if len(layersData[layer]['indicators']) == 0 and scale_level not in layersData[layer]['data_lvl']: - return ' ' - query = '' - layer_table_name = layersData[layer]['schema_hectare']+"."+layersData[layer]['tablename'] - query_select = 'SELECT ' - from_part = 'stat_' + layer - scalelvl_column = '' - if 'scalelvl_column' in layersData[layer]: - scalelvl_column = layersData[layer]['scalelvl_column'] - if layersData[layer]['table_type'] == vector_type: - for indic in layersData[layer]['indicators']: - if 'table_column' in indic: - query_select+=get_indicator_as_query(indic,layer_table_name,layer,scalelvl_column, scale_level) - - - query_select = query_select[:-1] - query += from_part+" as (" - query += query_select - query += " FROM "+layer_table_name - year_query='' - if 'year' in layersData[layer]: - year_query="date = '{0}-01-01' and".format(layersData[layer]['year']) - if 'level_of_data' in layersData[layer] and NUTS_LAU_LEVELS[layersData[layer]['level_of_data']] < NUTS_LAU_LEVELS[scale_level]: - query += " WHERE "+ year_query+" ST_Intersects(st_transform(st_geomfromtext('"+ geometry +"'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + "),"+layer_table_name+"."+layersData[layer]['geo_column']+")" - else: - query += " WHERE "+ year_query+" ST_Within("+layer_table_name+"."+layersData[layer]['geo_column']+",st_transform(st_geomfromtext('"+ geometry +"'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + "))" - query += ")" - else: - agg_summary_stat = 'agg_summary_stat' - for indic in layersData[layer]['indicators']: - if 'table_column' in indic: - query_select += agg_summary_stat + '.'+indic['table_column']+' as '+ layer + indic['indicator_id'] + ',' - query_select = query_select[:-1] - query_select += " from (select (((ST_SummaryStatsAgg(ST_Clip("+ layersData[layer]['tablename'] + ".rast, 1, st_transform(st_geomfromtext('" + geometry + "'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + "),false),true,0))).*) as "+layersData[layer]['tablename'] - query += from_part+' AS ( ' - query += query_select - query += " FROM "+ layer_table_name - query += " WHERE ST_Intersects(st_transform(st_geomfromtext('"+ geometry +"'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + ")," + layersData[layer]['tablename'] + ".rast)) "+agg_summary_stat - query += ")" - - return query - -def constructWithPartEachLayerNutsLau(nuts, year, layer, scale_level): - # Get name of table to select nuts/lau - year='2013' - if len(layersData[layer]['indicators']) == 0 and scale_level not in layersData[layer]['data_lvl']: - return ' ' - query = '' - name_type = '' - scalelvl_column='' - nust_select_name = "nutsSelection_"+ layer - nuts_selection = None - if scale_level in NUTS_VAlUES: - scale_level_crs = CRS_NUTS - scale_level_name = 'nuts_id' - name_type = 'nuts' - fk_column_id = 'fk_nuts_gid' - nuts_selection = nust_select_name +" as (SELECT geom as geom from geo."+name_type+" where "+name_type+".year = date('"+year+"-01-01') and "+scale_level_name+" in ("+nuts+")), " - else: - scale_level_crs = CRS_LAU - scale_level_name = 'comm_id' - name_type = 'lau' - fk_column_id = 'fk_lau_gid' - nuts_selection = nust_select_name +" as (SELECT st_transform(geom,4326) as geom from public."+LAU_TABLE+" where "+scale_level_name+" in ("+nuts+")), " - if 'scalelvl_column' in layersData[layer]: - scalelvl_column = layersData[layer]['scalelvl_column'] - - - - - - #TODO: Make a nuts selection like heatload with within where clause in nuts selection. Do not use geom! Too slow - - - - - from_part = 'stat_' + layer - query_from_part = from_part+" as (" - layer_table_name = layersData[layer]['schema_scalelvl']+"."+layersData[layer]['tablename'] - query_select = 'SELECT ' - - - if layersData[layer]['table_type'] == 'raster' and layersData[layer]['data_aggregated']: #(layersData[layer]['tablename'] != 'wwtp' or layersData[layer]['tablename'] != 'industrial_database' or layersData[layer]['tablename'] != 'wind_50m'): - layer_table_name += '_'+name_type - - for indic in layersData[layer]['indicators']: - if 'table_column' in indic: - """ if 'diss_agg_method' in indic and indic['diss_agg_method'] == 'NUTS_result' and check_if_agg_or_dis_method(layer, scale_level): - get_dis_query(indic, layer_table_name, layer,scale_level_name) - else: """ - query_select+=get_indicator_as_query(indic, layer_table_name, layer,scalelvl_column,scale_level) - - query_select = query_select[:-1] - - - if layersData[layer]['data_aggregated'] == False: - query += nuts_selection - query += query_from_part - query += query_select - - - query_from =" from " + nust_select_name + ", "+layer_table_name - query += query_from - year_query='' - if 'year' in layersData[layer]: - year_query="date = '{0}-01-01' and".format(layersData[layer]['year']) - if check_if_agg_or_dis_method(layer, scale_level): - query += " where "+year_query+" st_within(st_centroid("+nust_select_name+".geom),st_transform("+layer_table_name+"."+layersData[layer]['geo_column']+","+scale_level_crs+"))) " - else: - - query += " where "+year_query+" st_within(st_transform("+layer_table_name+"."+layersData[layer]['geo_column']+","+scale_level_crs+"), "+nust_select_name+".geom)) " - else: - query += query_from_part - query += query_select - if scale_level in NUTS_VAlUES: - query += " FROM "+layer_table_name + ", geo." + name_type - query += " WHERE "+layer_table_name+"."+fk_column_id+" = geo."+name_type+".gid and "+name_type+".year = date('"+year+"-01-01') and "+layer_table_name+"."+scale_level_name+" IN ("+nuts+") ) " - else: - query += " FROM "+layer_table_name + ", public." + LAU_TABLE - query += " WHERE "+layer_table_name+"."+fk_column_id+" = public."+LAU_TABLE+".gid and "+layer_table_name+"."+scale_level_name+" IN ("+nuts+") ) " - - return query + if len(layersData[layer]['indicators']) == 0 and scale_level not in layersData[layer]['data_lvl']: + return ' ' + query = '' + layer_table_name = layersData[layer]['schema_hectare']+"."+layersData[layer]['tablename'] + query_select = 'SELECT ' + from_part = 'stat_' + layer + scalelvl_column = '' + if 'scalelvl_column' in layersData[layer]: + scalelvl_column = layersData[layer]['scalelvl_column'] + if layersData[layer]['table_type'] == vector_type: + for indic in layersData[layer]['indicators']: + if 'table_column' in indic: + query_select+=get_indicator_as_query(indic,layer_table_name,layer,scalelvl_column, scale_level) + + + query_select = query_select[:-1] + query += from_part+" as (" + query += query_select + query += " FROM "+layer_table_name + year_query='' + if 'year' in layersData[layer]: + year_query="date = '{0}-01-01' and".format(layersData[layer]['year']) + if 'level_of_data' in layersData[layer] and NUTS_LAU_LEVELS[layersData[layer]['level_of_data']] < NUTS_LAU_LEVELS[scale_level]: + query += " WHERE "+ year_query+" ST_Intersects(st_transform(st_geomfromtext('"+ geometry +"'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + "),"+layer_table_name+"."+layersData[layer]['geo_column']+")" + else: + query += " WHERE "+ year_query+" ST_Within("+layer_table_name+"."+layersData[layer]['geo_column']+",st_transform(st_geomfromtext('"+ geometry +"'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + "))" + query += ")" + else: + agg_summary_stat = 'agg_summary_stat' + for indic in layersData[layer]['indicators']: + if 'table_column' in indic: + query_select += agg_summary_stat + '.'+indic['table_column']+' as '+ layer + indic['indicator_id'] + ',' + query_select = query_select[:-1] + query_select += " from (select (((ST_SummaryStatsAgg(ST_Clip("+ layersData[layer]['tablename'] + ".rast, 1, st_transform(st_geomfromtext('" + geometry + "'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + "),false),true,0))).*) as "+layersData[layer]['tablename'] + query += from_part+' AS ( ' + query += query_select + query += " FROM "+ layer_table_name + query += " WHERE ST_Intersects(st_transform(st_geomfromtext('"+ geometry +"'::text,"+CRS_USER_GEOMETRY+")," + layersData[layer]['crs'] + ")," + layersData[layer]['tablename'] + ".rast)) "+agg_summary_stat + query += ")" + + return query + +def constructWithPartEachLayerNutsLau(nuts, year, layer, scale_level): + # Get name of table to select nuts/lau + year='2013' + if len(layersData[layer]['indicators']) == 0 and scale_level not in layersData[layer]['data_lvl']: + return ' ' + query = '' + name_type = '' + scalelvl_column='' + nust_select_name = "nutsSelection_"+ layer + nuts_selection = None + if scale_level in NUTS_VAlUES: + scale_level_crs = CRS_NUTS + scale_level_name = 'nuts_id' + name_type = 'nuts' + fk_column_id = 'fk_nuts_gid' + nuts_selection = nust_select_name +" as (SELECT geom as geom from geo."+name_type+" where "+name_type+".year = date('"+year+"-01-01') and "+scale_level_name+" in ("+nuts+")), " + else: + scale_level_crs = CRS_LAU + scale_level_name = 'comm_id' + name_type = 'lau' + fk_column_id = 'fk_lau_gid' + nuts_selection = nust_select_name +" as (SELECT st_transform(geom,4326) as geom from public."+LAU_TABLE+" where "+scale_level_name+" in ("+nuts+")), " + if 'scalelvl_column' in layersData[layer]: + scalelvl_column = layersData[layer]['scalelvl_column'] + + + + + + #TODO: Make a nuts selection like heatload with within where clause in nuts selection. Do not use geom! Too slow + + + + + from_part = 'stat_' + layer + query_from_part = from_part+" as (" + layer_table_name = layersData[layer]['schema_scalelvl']+"."+layersData[layer]['tablename'] + query_select = 'SELECT ' + + + if layersData[layer]['table_type'] == 'raster' and layersData[layer]['data_aggregated']: #(layersData[layer]['tablename'] != 'wwtp' or layersData[layer]['tablename'] != 'industrial_database' or layersData[layer]['tablename'] != 'wind_50m'): + layer_table_name += '_'+name_type + + for indic in layersData[layer]['indicators']: + if 'table_column' in indic: + """ if 'diss_agg_method' in indic and indic['diss_agg_method'] == 'NUTS_result' and check_if_agg_or_dis_method(layer, scale_level): + get_dis_query(indic, layer_table_name, layer,scale_level_name) + else: """ + query_select+=get_indicator_as_query(indic, layer_table_name, layer,scalelvl_column,scale_level) + + query_select = query_select[:-1] + + + if layersData[layer]['data_aggregated'] == False: + query += nuts_selection + query += query_from_part + query += query_select + + + query_from =" from " + nust_select_name + ", "+layer_table_name + query += query_from + year_query='' + if 'year' in layersData[layer]: + year_query="date = '{0}-01-01' and".format(layersData[layer]['year']) + if check_if_agg_or_dis_method(layer, scale_level): + query += " where "+year_query+" st_within(st_centroid("+nust_select_name+".geom),st_transform("+layer_table_name+"."+layersData[layer]['geo_column']+","+scale_level_crs+"))) " + else: + + query += " where "+year_query+" st_within(st_transform("+layer_table_name+"."+layersData[layer]['geo_column']+","+scale_level_crs+"), "+nust_select_name+".geom)) " + else: + query += query_from_part + query += query_select + if scale_level in NUTS_VAlUES: + query += " FROM "+layer_table_name + ", geo." + name_type + query += " WHERE "+layer_table_name+"."+fk_column_id+" = geo."+name_type+".gid and "+name_type+".year = date('"+year+"-01-01') and "+layer_table_name+"."+scale_level_name+" IN ("+nuts+") ) " + else: + query += " FROM "+layer_table_name + ", public." + LAU_TABLE + query += " WHERE "+layer_table_name+"."+fk_column_id+" = public."+LAU_TABLE+".gid and "+layer_table_name+"."+scale_level_name+" IN ("+nuts+") ) " + + return query def get_indicator_as_query(indic, layer_table_name, layer, scale_level_name, scale_level): - agg_method = indic['table_column'] - distinct='' - indic_id = 'as '+layer + indic['indicator_id'] + ',' - query_calcul = layer_table_name+'.' +indic['table_column'] + ')' + indic_id - if layer == 'agricultural_residues_view': - distinct = 'distinct ' - - switcher = { - 'sum':'sum('+query_calcul, - 'min':'min('+query_calcul, - 'max':'max('+query_calcul, - 'avg':'avg('+query_calcul, - 'mean_weighted_cell':'sum('+layer_table_name+'.count*'+layer_table_name+'.' +indic['table_column']+')/sum('+layer_table_name+'.count) '+indic_id, - 'mean_simple':'avg('+query_calcul, - 'NUTS_result':'sum('+layer_table_name+'.'+indic['table_column']+')/count('+distinct+layer_table_name+'.'+scale_level_name+') '+ indic_id - } - - if 'agg_method' in indic: - agg_method = indic['agg_method'] - if 'diss_agg_method' in indic and check_if_agg_or_dis_method(layer, scale_level): - agg_method = indic['diss_agg_method'] - if indic['table_column'] is 'mean': - quer = switcher.get(agg_method,switcher['mean_weighted_cell']) - else: - quer = switcher.get(agg_method,switcher['sum']) - - return quer - + agg_method = indic['table_column'] + distinct='' + indic_id = 'as '+layer + indic['indicator_id'] + ',' + query_calcul = layer_table_name+'.' +indic['table_column'] + ')' + indic_id + if layer == 'agricultural_residues_view': + distinct = 'distinct ' + + switcher = { + 'sum':'sum('+query_calcul, + 'min':'min('+query_calcul, + 'max':'max('+query_calcul, + 'avg':'avg('+query_calcul, + 'mean_weighted_cell':'sum('+layer_table_name+'.count*'+layer_table_name+'.' +indic['table_column']+')/sum('+layer_table_name+'.count) '+indic_id, + 'mean_simple':'avg('+query_calcul, + 'NUTS_result':'sum('+layer_table_name+'.'+indic['table_column']+')/count('+distinct+layer_table_name+'.'+scale_level_name+') '+ indic_id + } + + if 'agg_method' in indic: + agg_method = indic['agg_method'] + if 'diss_agg_method' in indic and check_if_agg_or_dis_method(layer, scale_level): + agg_method = indic['diss_agg_method'] + if indic['table_column'] is 'mean': + quer = switcher.get(agg_method,switcher['mean_weighted_cell']) + else: + quer = switcher.get(agg_method,switcher['sum']) + + return quer + def check_if_agg_or_dis_method(layer,scale_level): - return 'level_of_data' in layersData[layer] and NUTS_LAU_LEVELS[layersData[layer]['level_of_data']] < NUTS_LAU_LEVELS[scale_level] + return 'level_of_data' in layersData[layer] and NUTS_LAU_LEVELS[layersData[layer]['level_of_data']] < NUTS_LAU_LEVELS[scale_level] diff --git a/api/app/models/grids.py b/api/app/models/grids.py index c3a836ed..4503b8b9 100644 --- a/api/app/models/grids.py +++ b/api/app/models/grids.py @@ -1,4 +1,4 @@ -from app.models import dbGIS as db +from app.models import dbGIS as db from geoalchemy2 import Geometry @@ -21,4 +21,3 @@ class Grid1Km(db.Model): def __repr__(self): return "