gfw-api/forest-change-analysis-elastic

View on GitHub
gladanalysis/routes/api/v2/terrai_router.py

Summary

Maintainability
A
1 hr
Test Coverage
D
69%
import datetime
import logging
import os

from flask import jsonify, request

from gladanalysis.errors import GeostoreNotFound
from gladanalysis.routes.api.v2 import error
from gladanalysis.services import GeostoreService, DateService, QueryConstructorService, AnalysisService, \
    ResponseService, SummaryService, AreaService
from gladanalysis.validators import validate_geostore, validate_terrai_period, validate_agg, validate_admin, \
    validate_wdpa
from . import endpoints

datasetID = os.getenv('TERRAI_DATASET_ID')
indexID = os.getenv('TERRAI_INDEX_ID')


def analyze(area=None, geostore=None, iso=None, state=None, dist=None, geojson=None):
    """Analyze method to execute queries
    This is designed to format the dates of the request, create the sql and download sql queries from
    the dates, retrieve the data from the queries and send the data to a formatter service to format
    the API response.
    :param area: the area of the request retrieved by the geostore
    :param geostore: the geostore id of the request
    :param iso: the country iso if specified
    :param dist: the district ID based on gadm
    :param state: the state ID based on gadm
    :param geojson: the geojson included in the body (if post request)
    :return: returns the response of the API request formatted by the format service"""

    today = datetime.datetime.today().strftime('%Y-%m-%d')

    # get parameter from query string
    period = request.args.get('period', '2004-01-01,{}'.format(today))
    agg_values = request.args.get('aggregate_values', False)
    agg_by = request.args.get('aggregate_by', None)

    # grab geojson if it exists
    geojson = request.get_json(False, True).get('geojson', None) if request.get_json(False, True) else None

    # format period request to julian dates
    from_year, from_date, to_year, to_date = DateService.date_to_julian_day(request.headers.get('x-api-key'), period,
                                                                            datasetID, indexID, "day")

    # grab query and download sql from sql service
    sql, download_sql = QueryConstructorService.format_terrai_sql(from_year, from_date, to_year, to_date, iso, state,
                                                                  dist, agg_values)

    kwargs = {'download_sql': download_sql,
              'area': area,
              'geostore': geostore,
              'agg': agg_values,
              'period': period}

    if agg_values:
        if not agg_by or agg_by == 'julian_day':
            agg_by = 'day'

        kwargs['agg_by'] = agg_by

        data = AnalysisService.make_analysis_request(datasetID, sql, geostore, geojson,
                                                     request.headers.get('x-api-key'))
        agg_data = SummaryService.create_time_table('terrai', data, agg_by)
        standard_format = ResponseService.standardize_response(agg_data, datasetID, **kwargs)

    else:
        kwargs['agg_by'] = None
        kwargs['count'] = "COUNT(julian_day)"
        data = AnalysisService.make_analysis_request(datasetID, sql, geostore, geojson,
                                                     request.headers.get('x-api-key'))
        standard_format = ResponseService.standardize_response(data, datasetID, **kwargs)

    return jsonify({'data': standard_format}), 200


"""TERRA I ENDPOINTS"""


@endpoints.route('/terrai-alerts', methods=['GET', 'POST'])
@validate_terrai_period
@validate_geostore
@validate_agg
def query_terrai():
    """analyze terrai by geostore or geojson"""

    if request.method == 'GET':
        logging.info('[ROUTER]: get Terra I by Geostore')

        geostore = request.args.get('geostore', None)

        # get area of request in hectares from geostore
        try:
            area = GeostoreService.make_area_request(geostore, request.headers.get('x-api-key'))
        except GeostoreNotFound:
            logging.error('[ROUTER]: Geostore Not Found')
            return error(status=404, detail='Geostore not found')

        return analyze(area=area, geostore=geostore)

    elif request.method == 'POST':
        logging.info('[ROUTER]: post geojson to terrai')

        geojson = request.get_json().get('geojson', None) if request.get_json() else None
        area = AreaService.tabulate_area(geojson)

        return analyze(area=area, geojson=geojson)

    else:
        return error(status=405, detail="Operation not supported")


@endpoints.route('/terrai-alerts/admin/<iso_code>', methods=['GET'])
@validate_terrai_period
@validate_admin
def terrai_country(iso_code):
    """analyze terrai by gadm"""
    logging.info('Running Terra I country analysis')

    # get area in hectares of response from geostore
    area = GeostoreService.make_gadm_request(iso_code, request.headers.get('x-api-key'))

    return analyze(area, iso=iso_code)


@endpoints.route('/terrai-alerts/admin/<iso_code>/<admin_id>', methods=['GET'])
@validate_terrai_period
@validate_admin
def terrai_admin(iso_code, admin_id):
    """analyze terrai by gadm"""
    logging.info('Running Terra I state analysis')

    # get area in hectares of request from geostore
    area = GeostoreService.make_gadm_request(iso_code, request.headers.get('x-api-key'), admin_id)

    return analyze(area, iso=iso_code, state=admin_id)


@endpoints.route('/terrai-alerts/admin/<iso_code>/<admin_id>/<dist_id>', methods=['GET'])
@validate_terrai_period
@validate_admin
def terrai_dist(iso_code, admin_id, dist_id):
    """analyze terrai by gadm"""
    logging.info('Running Terra I Analysis on District')

    # get area in hectares of request from geostore
    area = GeostoreService.make_gadm_request(iso_code, request.headers.get('x-api-key'), admin_id, dist_id)

    return analyze(area, iso=iso_code, state=admin_id, dist=dist_id)


@endpoints.route('/terrai-alerts/use/<use_type>/<use_id>', methods=['GET'])
@validate_terrai_period
def terrai_use(use_type, use_id):
    """analyze terrai by land use"""
    logging.info('Intersect Terra I and Land Use data')

    # get geostore ID and area in hectares of request from geostore
    geostore, area = GeostoreService.make_use_request(use_type, use_id, request.headers.get('x-api-key'))

    return analyze(area, geostore)


@endpoints.route('/terrai-alerts/wdpa/<wdpa_id>', methods=['GET'])
@validate_terrai_period
@validate_wdpa
def terrai_wdpa(wdpa_id):
    """analyze terrai by wdpa geom"""
    logging.info('Intersect Terra I and WDPA')

    # get geostore id and area in hectares of request from geostore
    geostore, area = GeostoreService.make_wdpa_request(wdpa_id, request.headers.get('x-api-key'))

    return analyze(area, geostore)


@endpoints.route('/terrai-alerts/date-range', methods=['GET'])
def terrai_date_range():
    """get terrai date range"""
    logging.info('Creating Terra I Date Range')

    # get min and max date from sql queries
    min_year, min_julian, max_year, max_julian = DateService.get_min_max_date('day', datasetID, indexID,
                                                                              request.headers.get('x-api-key'))
    min_date, max_date = DateService.format_date_sql(min_year, min_julian, max_year, max_julian)

    # standardize response
    response = ResponseService.format_date_range("Terrai", min_date, max_date)

    return jsonify({'data': response}), 200


@endpoints.route('/terrai-alerts/latest', methods=['GET'])
def terrai_latest():
    """get TerraI latest date"""
    logging.info('Getting latest date')

    # get max date
    min_year, min_julian, max_year, max_julian = DateService.get_min_max_date('day', datasetID, indexID,
                                                                              request.headers.get('x-api-key'))
    max_date = DateService.format_date_sql(min_year, min_julian, max_year, max_julian)[1]

    # standardize latest date response
    response = ResponseService.format_latest_date("Terrai", max_date)

    return jsonify({'data': response}), 200