Skip to content

Commit

Permalink
Updates for Tethys 4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
swainn committed Jan 20, 2023
1 parent e07e34a commit be41b98
Show file tree
Hide file tree
Showing 27 changed files with 351 additions and 394 deletions.
6 changes: 5 additions & 1 deletion install.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# This file should be committed to your app code.
version: 1.0
# This should be greater or equal to your tethys-platform in your environment
tethys_version: ">=4.0.0"
# This should match the app - package name in your setup.py
name: earth_engine

Expand All @@ -16,4 +18,6 @@ requirements:
- pyshp
pip:

post:
npm:

post:
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from setuptools import setup, find_namespace_packages
from tethys_apps.app_installation import find_resource_files
from tethys_apps.app_installation import find_all_resource_files
from tethys_apps.base.app_base import TethysAppBase

# -- Apps Definition -- #
app_package = 'earth_engine'
release_package = 'tethysapp-' + app_package
release_package = f'{TethysAppBase.package_namespace}-{app_package}'

# -- Python Dependencies -- #
dependencies = []

# -- Get Resource File -- #
resource_files = find_resource_files('tethysapp/' + app_package + '/templates', 'tethysapp/' + app_package)
resource_files += find_resource_files('tethysapp/' + app_package + '/public', 'tethysapp/' + app_package)
resource_files = find_all_resource_files(app_package, TethysAppBase.package_namespace)


setup(
Expand Down
2 changes: 1 addition & 1 deletion tethysapp/earth_engine/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Included for native namespace package support
# Included for native namespace package support
50 changes: 7 additions & 43 deletions tethysapp/earth_engine/app.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,18 @@
from tethys_sdk.base import TethysAppBase, url_map_maker
from tethys_sdk.base import TethysAppBase


class EarthEngine(TethysAppBase):
"""
Tethys app class for Earth Engine.
"""

name = 'Earth Engine'
index = 'earth_engine:home'
icon = 'earth_engine/images/earth-engine-logo.png'
package = 'earth_engine'
name = 'Google Earth Engine Tutorial'
description = ''
package = 'earth_engine' # WARNING: Do not change this value
index = 'home'
icon = f'{package}/images/earth-engine-logo.png'
root_url = 'earth-engine'
color = '#524745'
description = ''
tags = ''
enable_feedback = False
feedback_emails = []

def url_maps(self):
"""
Add controllers
"""
UrlMap = url_map_maker(self.root_url)

url_maps = (
UrlMap(
name='home',
url='earth-engine',
controller='earth_engine.controllers.home'
),
UrlMap(
name='viewer',
url='earth-engine/viewer',
controller='earth_engine.controllers.viewer'
),
UrlMap(
name='get_image_collection',
url='earth-engine/viewer/get-image-collection',
controller='earth_engine.controllers.get_image_collection'
),
UrlMap(
name='get_time_series_plot',
url='earth-engine/viewer/get-time-series-plot',
controller='earth_engine.controllers.get_time_series_plot'
),
UrlMap(
name='about',
url='earth-engine/about',
controller='earth_engine.controllers.about'
)
)

return url_maps
feedback_emails = []
129 changes: 30 additions & 99 deletions tethysapp/earth_engine/controllers.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
import os
import tempfile
import zipfile
import logging
import datetime as dt
import geojson
import ee
import shapefile
import logging
from simplejson.errors import JSONDecodeError
from django.http import JsonResponse, HttpResponseNotAllowed, HttpResponseRedirect
from django.shortcuts import render
from simplejson.errors import JSONDecodeError
from tethys_sdk.routing import controller
from tethys_sdk.gizmos import SelectInput, DatePicker, Button, MapView, MVView, PlotlyView, MVDraw
from tethys_sdk.permissions import login_required
from tethys_sdk.workspaces import user_workspace
from .helpers import generate_figure, find_shapefile, write_boundary_shapefile, prep_boundary_dir
from .gee.methods import get_image_collection_asset, get_time_series_from_image_collection, upload_shapefile_to_gee, \
from .gee.methods import get_image_collection_asset, get_time_series_from_image_collection, \
get_boundary_fc_props_for_user
from .gee.products import EE_PRODUCTS
from .helpers import generate_figure, handle_shapefile_upload

log = logging.getLogger(f'tethys.apps.{__name__}')


@login_required()
@controller
def home(request):
"""
Controller for the app home page.
Expand All @@ -29,7 +23,7 @@ def home(request):
return render(request, 'earth_engine/home.html', context)


@login_required()
@controller
def about(request):
"""
Controller for the app about page.
Expand All @@ -38,8 +32,7 @@ def about(request):
return render(request, 'earth_engine/about.html', context)


@login_required()
@user_workspace
@controller(user_workspace=True)
def viewer(request, user_workspace):
"""
Controller for the app viewer page.
Expand Down Expand Up @@ -146,24 +139,10 @@ def viewer(request, user_workspace):
load_button = Button(
name='load_map',
display_text='Load',
style='default',
style='outline-secondary',
attributes={'id': 'load_map'}
)

clear_button = Button(
name='clear_map',
display_text='Clear',
style='default',
attributes={'id': 'clear_map'}
)

plot_button = Button(
name='load_plot',
display_text='Plot AOI',
style='default',
attributes={'id': 'load_plot'}
)


# Get bounding box from user boundary if it exists
boundary_props = get_boundary_fc_props_for_user(request.user)

Expand Down Expand Up @@ -198,15 +177,30 @@ def viewer(request, user_workspace):
)
)

clear_button = Button(
name='clear_map',
display_text='Clear',
style='outline-secondary',
attributes={'id': 'clear_map'},
classes='mt-2',
)

plot_button = Button(
name='load_plot',
display_text='Plot AOI',
style='outline-secondary',
attributes={'id': 'load_plot'},
)

# Boundary Upload Form
set_boundary_button = Button(
name='set_boundary',
display_text='Set Boundary',
style='default',
style='outline-secondary',
attributes={
'id': 'set_boundary',
'data-toggle': 'modal',
'data-target': '#set-boundary-modal' # ID of the Set Boundary Modal
'data-bs-toggle': 'modal',
'data-bs-target': '#set-boundary-modal', # ID of the Set Boundary Modal
}
)

Expand Down Expand Up @@ -238,7 +232,7 @@ def viewer(request, user_workspace):
return render(request, 'earth_engine/viewer.html', context)


@login_required()
@controller(url='viewer/get-image-collection')
def get_image_collection(request):
"""
Controller to handle image collection requests.
Expand Down Expand Up @@ -280,8 +274,7 @@ def get_image_collection(request):

return JsonResponse(response_data)


@login_required()
@controller(url='viewer/get-time-series-plot')
def get_time_series_plot(request):
context = {'success': False}

Expand Down Expand Up @@ -351,65 +344,3 @@ def get_time_series_plot(request):
log.exception('An unexpected error occurred.')

return render(request, 'earth_engine/plot.html', context)


def handle_shapefile_upload(request, user_workspace):
"""
Uploads shapefile to Google Earth Engine as an Asset.
Args:
request (django.Request): the request object.
user_workspace (tethys_sdk.workspaces.Workspace): the User workspace object.
Returns:
str: Error string if errors occurred.
"""
# Write file to temp for processing
uploaded_file = request.FILES['boundary-file']

with tempfile.TemporaryDirectory() as temp_dir:
temp_zip_path = os.path.join(temp_dir, 'boundary.zip')

# Use with statements to ensure opened files are closed when done
with open(temp_zip_path, 'wb') as temp_zip:
for chunk in uploaded_file.chunks():
temp_zip.write(chunk)

try:
# Extract the archive to the temporary directory
with zipfile.ZipFile(temp_zip_path) as temp_zip:
temp_zip.extractall(temp_dir)

except zipfile.BadZipFile:
# Return error message
return 'You must provide a zip archive containing a shapefile.'

# Verify that it contains a shapefile
try:
# Find a shapefile in directory where we extracted the archive
shapefile_path = find_shapefile(temp_dir)

if not shapefile_path:
return 'No Shapefile found in the archive provided.'

with shapefile.Reader(shapefile_path) as shp_file:
# Check type (only Polygon supported)
if shp_file.shapeType != shapefile.POLYGON:
return 'Only shapefiles containing Polygons are supported.'

# Setup workspace directory for storing shapefile
workspace_dir = prep_boundary_dir(user_workspace.path)

# Write the shapefile to the workspace directory
write_boundary_shapefile(shp_file, workspace_dir)

# Upload shapefile as Asset in GEE
upload_shapefile_to_gee(request.user, shp_file)

except TypeError:
return 'Incomplete or corrupted shapefile provided.'

except ee.EEException:
msg = 'An unexpected error occurred while uploading the shapefile to Google Earth Engine.'
log.exception(msg)
return msg
6 changes: 3 additions & 3 deletions tethysapp/earth_engine/gee/cloud_mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def mask_l8_sr(image):
"""
Derived From: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C01_T1_SR
Cloud Mask for Landsat 8 surface reflectance. Derived From: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LC08_C01_T1_SR
"""
# Bits 3 and 5 are cloud shadow and cloud, respectively.
cloudShadowBitMask = (1 << 3)
Expand All @@ -19,7 +19,7 @@ def mask_l8_sr(image):

def cloud_mask_l457(image):
"""
Derived From: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LE07_C01_T1_SR
Cloud Mask for Landsat 7 surface reflectance. Derived From: https://developers.google.com/earth-engine/datasets/catalog/LANDSAT_LE07_C01_T1_SR
"""
qa = image.select('pixel_qa')

Expand All @@ -35,7 +35,7 @@ def cloud_mask_l457(image):

def mask_s2_clouds(image):
"""
Derived from: https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2
Cloud Mask for Sentinel 2 surface reflectance. Derived from: https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2
"""
qa = image.select('QA60')

Expand Down
5 changes: 2 additions & 3 deletions tethysapp/earth_engine/gee/methods.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import os
import math
import os
import logging
import ee
from ee.ee_exception import EEException
import geojson
import pandas as pd
from .products import EE_PRODUCTS
from . import params as gee_account
from . import cloud_mask as cm
from .products import EE_PRODUCTS


log = logging.getLogger(f'tethys.apps.{__name__}')

Expand Down
3 changes: 0 additions & 3 deletions tethysapp/earth_engine/handoff.py

This file was deleted.

Loading

0 comments on commit be41b98

Please sign in to comment.