Skip to content

Commit

Permalink
Merge pull request #139 from mzaglia/b-0.9.0
Browse files Browse the repository at this point in the history
Closes #130 #138 #140
  • Loading branch information
gqueiroz authored Feb 2, 2021
2 parents 8cb958e + 90f3fb1 commit 999b0f1
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 41 deletions.
28 changes: 24 additions & 4 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
kind: pipeline
type: docker
name: default

steps:
Expand All @@ -8,10 +9,29 @@ steps:
- pip install --upgrade pip
- pip install --upgrade setuptools
- pip install -e.[all]
- isort bdc_stac tests setup.py --check-only --diff
- check-manifest --ignore ".drone.yml,.readthedocs.yml"
- sphinx-build -qnW --color -b doctest docs/sphinx/ docs/sphinx/_build/doctest
# - pytest -v TODO: Review tests
- ./run-tests.sh

- name: discord-notify
image: brazildatacube/bdc-drone-discord
settings:
webhook:
from_secret: discord_webhook
when:
status:
- failure
- success

- name: coverage
image: plugins/codecov
settings:
token:
from_secret: codecov_token
files:
- coverage.xml
- .coverage
when:
event:
- push

- name: docker-registry
image: plugins/docker
Expand Down
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
Changes
=======

Version 0.9.0-13 (2021-01-22)
Version 0.9.0-13 (2021-01-28)
----------------------------

- Add drone support (`#133 <https://github.com/brazil-data-cube/bdc-stac/issues/133>`_)
- Remove collection metadata from item (`#136 <https://github.com/brazil-data-cube/bdc-stac/issues/136>`_)
- Add missing CORS headers (`#138 <https://github.com/brazil-data-cube/bdc-stac/issues/138>`_
- Pass auth parameters to asset url (`#130 <https://github.com/brazil-data-cube/bdc-stac/issues/130>`_
- Fix bug when access collection item id directly (`#140 <https://github.com/brazil-data-cube/bdc-stac/issues/140>`_

Version 0.9.0-12 (2021-01-14)
----------------------------
Expand Down
2 changes: 1 addition & 1 deletion bdc_stac/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
BDC_STAC_MAX_LIMIT = int(os.getenv("BDC_STAC_MAX_LIMIT", "1000"))
BDC_STAC_TITLE = os.getenv("BDC_STAC_TITLE", "Brazil Data Cube Catalog")
BDC_STAC_ID = os.getenv("BDC_STAC_ID", "bdc")

BDC_STAC_ASSETS_ARGS = os.getenv("BDC_STAC_ASSETS_ARGS", None)
BDC_AUTH_CLIENT_SECRET = os.getenv("BDC_AUTH_CLIENT_SECRET", None)
BDC_AUTH_CLIENT_ID = os.getenv("BDC_AUTH_CLIENT_ID", None)
BDC_AUTH_ACCESS_TOKEN_URL = os.getenv("BDC_AUTH_ACCESS_TOKEN_URL", None)
33 changes: 23 additions & 10 deletions bdc_stac/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,15 @@ def get_collection_items(

if ids is not None:
where += [Item.name.in_(ids.split(","))]
elif item_id is not None:
where += [Item.name.like(item_id)]
else:
if collections is not None:
where += [func.concat(Collection.name, "-", Collection.version).in_(collections.split(","))]
elif collection_id is not None:
where += [func.concat(Collection.name, "-", Collection.version) == collection_id]

if item_id is not None:
where += [Item.name.like(item_id)]

if query:
filters = create_query_filter(query)
if filters:
Expand All @@ -123,7 +124,11 @@ def get_collection_items(
where += [
func.ST_Intersects(
func.ST_MakeEnvelope(
split_bbox[0], split_bbox[1], split_bbox[2], split_bbox[3], func.ST_SRID(Item.geom),
split_bbox[0],
split_bbox[1],
split_bbox[2],
split_bbox[3],
func.ST_SRID(Item.geom),
),
Item.geom,
)
Expand Down Expand Up @@ -459,15 +464,22 @@ def get_catalog(roles=[]):
"""
collections = (
session.query(
Collection.id, func.concat(Collection.name, "-", Collection.version).label("name"), Collection.title,
Collection.id,
func.concat(Collection.name, "-", Collection.version).label("name"),
Collection.title,
)
.filter(
or_(
Collection.is_public.is_(True),
Collection.id.in_([int(r.split(":")[0]) for r in roles]),
)
)
.filter(or_(Collection.is_public.is_(True), Collection.id.in_([int(r.split(":")[0]) for r in roles]),))
.all()
)
return collections


def make_geojson(items, links, access_token=""):
def make_geojson(items, links, assets_kwargs=""):
"""Generate a list of STAC Items from a list of collection items.
:param items: collection items to be formated as GeoJSON Features
Expand Down Expand Up @@ -511,7 +523,8 @@ def make_geojson(items, links, access_token=""):
properties["eo:cloud_cover"] = i.cloud_cover

for key, value in i.assets.items():
value["href"] = BDC_STAC_FILE_ROOT + value["href"] + access_token
value["href"] = BDC_STAC_FILE_ROOT + value["href"] + assets_kwargs

for index, band in enumerate(properties["eo:bands"], start=0):
if band["name"] == key:
value["eo:bands"] = [index]
Expand All @@ -530,9 +543,9 @@ def make_geojson(items, links, access_token=""):
feature["assets"] = i.assets

feature["links"] = deepcopy(links)
feature["links"][0]["href"] += i.collection + "/items/" + i.item + access_token
feature["links"][1]["href"] += i.collection + access_token
feature["links"][2]["href"] += i.collection + access_token
feature["links"][0]["href"] += i.collection + "/items/" + i.item + assets_kwargs
feature["links"][1]["href"] += i.collection + assets_kwargs
feature["links"][2]["href"] += i.collection + assets_kwargs

features.append(feature)

Expand Down
83 changes: 61 additions & 22 deletions bdc_stac/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from werkzeug.exceptions import HTTPException, InternalServerError
from werkzeug.urls import url_encode

from .config import BDC_STAC_API_VERSION, BDC_STAC_BASE_URL, BDC_STAC_ID, BDC_STAC_TITLE
from .config import BDC_STAC_API_VERSION, BDC_STAC_ASSETS_ARGS, BDC_STAC_BASE_URL, BDC_STAC_ID, BDC_STAC_TITLE
from .data import InvalidBoundingBoxError, get_catalog, get_collection_items, get_collections, make_geojson, session

BASE_URL = BDC_STAC_BASE_URL
Expand All @@ -30,6 +30,8 @@ def teardown_appcontext(exceptions=None):
def after_request(response):
"""Enable CORS and compress response."""
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers", "Content-Type")
response.headers.add("Access-Control-Allow-Methods", "GET, POST")

accept_encoding = request.headers.get("Accept-Encoding", "")

Expand Down Expand Up @@ -69,7 +71,13 @@ def conformance():
@oauth2(required=False, throw_exception=False)
def index(roles=[], access_token=""):
"""Landing page of this API."""
access_token = f"?access_token={access_token}" if access_token else ""
assets_kwargs = None

if BDC_STAC_ASSETS_ARGS:
assets_kwargs = {arg: request.args.get(arg) for arg in BDC_STAC_ASSETS_ARGS.split(",")}
if access_token:
assets_kwargs["access_token"] = access_token
assets_kwargs = "?" + url_encode(assets_kwargs)

collections = get_catalog(roles=roles)
catalog = dict()
Expand Down Expand Up @@ -98,7 +106,7 @@ def index(roles=[], access_token=""):
for collection in collections:
links.append(
{
"href": f"{BASE_URL}/collections/{collection.name}{access_token}",
"href": f"{BASE_URL}/collections/{collection.name}{assets_kwargs}",
"rel": "child",
"type": "application/json",
"title": collection.title,
Expand All @@ -114,33 +122,39 @@ def index(roles=[], access_token=""):
@oauth2(required=False, throw_exception=False)
def root(roles=[], access_token=""):
"""Return the root catalog or collection."""
access_token = f"?access_token={access_token}" if access_token else ""
assets_kwargs = None

if BDC_STAC_ASSETS_ARGS:
assets_kwargs = {arg: request.args.get(arg) for arg in BDC_STAC_ASSETS_ARGS.split(",")}
if access_token:
assets_kwargs["access_token"] = access_token
assets_kwargs = "?" + url_encode(assets_kwargs)

collections = get_collections(roles=roles)
response = dict()

for collection in collections:
links = [
{
"href": f"{BASE_URL}/collections/{collection['id']}{access_token}",
"href": f"{BASE_URL}/collections/{collection['id']}{assets_kwargs}",
"rel": "self",
"type": "application/json",
"title": "Link to this document",
},
{
"href": f"{BASE_URL}/collections/{collection['id']}/items{access_token}",
"href": f"{BASE_URL}/collections/{collection['id']}/items{assets_kwargs}",
"rel": "items",
"type": "application/json",
"title": f"Items of the collection {collection['id']}",
},
{
"href": f"{BASE_URL}/collections{access_token}",
"href": f"{BASE_URL}/collections{assets_kwargs}",
"rel": "parent",
"type": "application/json",
"title": "Link to catalog collections",
},
{
"href": f"{BASE_URL}/{access_token}",
"href": f"{BASE_URL}/{assets_kwargs}",
"rel": "root",
"type": "application/json",
"title": "API landing page (root catalog)",
Expand All @@ -160,7 +174,13 @@ def collections_id(collection_id, roles=[], access_token=""):
:param collection_id: identifier (name) of a specific collection
"""
access_token = f"?access_token={access_token}" if access_token else ""
assets_kwargs = None

if BDC_STAC_ASSETS_ARGS:
assets_kwargs = {arg: request.args.get(arg) for arg in BDC_STAC_ASSETS_ARGS.split(",")}
if access_token:
assets_kwargs["access_token"] = access_token
assets_kwargs = "?" + url_encode(assets_kwargs)

collection = get_collections(collection_id, roles=roles)

Expand All @@ -171,25 +191,25 @@ def collections_id(collection_id, roles=[], access_token=""):

links = [
{
"href": f"{BASE_URL}/collections/{collection['id']}{access_token}",
"href": f"{BASE_URL}/collections/{collection['id']}{assets_kwargs}",
"rel": "self",
"type": "application/json",
"title": "Link to this document",
},
{
"href": f"{BASE_URL}/collections/{collection['id']}/items{access_token}",
"href": f"{BASE_URL}/collections/{collection['id']}/items{assets_kwargs}",
"rel": "items",
"type": "application/json",
"title": f"Items of the collection {collection['id']}",
},
{
"href": f"{BASE_URL}/collections{access_token}",
"href": f"{BASE_URL}/collections{assets_kwargs}",
"rel": "parent",
"type": "application/json",
"title": "Link to catalog collections",
},
{
"href": f"{BASE_URL}/{access_token}",
"href": f"{BASE_URL}/{assets_kwargs}",
"rel": "root",
"type": "application/json",
"title": "API landing page (root catalog)",
Expand All @@ -208,8 +228,6 @@ def collection_items(collection_id, roles=[], access_token=""):
:param collection_id: identifier (name) of a specific collection
"""
access_token = f"?access_token={access_token}" if access_token else ""

items = get_collection_items(collection_id=collection_id, roles=roles, **request.args.to_dict())

links = [
Expand Down Expand Up @@ -239,7 +257,15 @@ def collection_items(collection_id, roles=[], access_token=""):
gjson["stac_extensions"] = ["checksum", "commons", "context", "eo"]
gjson["type"] = "FeatureCollection"

features = make_geojson(items.items, links, access_token=access_token)
assets_kwargs = None

if BDC_STAC_ASSETS_ARGS:
assets_kwargs = {arg: request.args.get(arg) for arg in BDC_STAC_ASSETS_ARGS.split(",")}
if access_token:
assets_kwargs["access_token"] = access_token
assets_kwargs = "?" + url_encode(assets_kwargs)

features = make_geojson(items.items, links, assets_kwargs=assets_kwargs)

gjson["links"] = []

Expand Down Expand Up @@ -273,8 +299,6 @@ def items_id(collection_id, item_id, roles=[], access_token=""):
:param collection_id: identifier (name) of a specific collection
:param item_id: identifier (name) of a specific item
"""
access_token = f"?access_token={access_token}" if access_token else ""

item = get_collection_items(collection_id=collection_id, roles=roles, item_id=item_id)
links = [
{"href": f"{BASE_URL}/collections/", "rel": "self"},
Expand All @@ -283,7 +307,15 @@ def items_id(collection_id, item_id, roles=[], access_token=""):
{"href": f"{BASE_URL}/", "rel": "root"},
]

gjson = make_geojson(item.items, links, access_token=access_token)
assets_kwargs = None

if BDC_STAC_ASSETS_ARGS:
assets_kwargs = {arg: request.args.get(arg) for arg in BDC_STAC_ASSETS_ARGS.split(",")}
if access_token:
assets_kwargs["access_token"] = access_token
assets_kwargs = "?" + url_encode(assets_kwargs)

gjson = make_geojson(item.items, links, assets_kwargs=assets_kwargs)

if len(gjson) > 0:
return gjson[0]
Expand All @@ -295,8 +327,6 @@ def items_id(collection_id, item_id, roles=[], access_token=""):
@oauth2(required=False, throw_exception=False)
def stac_search(roles=[], access_token=""):
"""Search STAC items with simple filtering."""
access_token = f"?access_token={access_token}" if access_token else ""

bbox, datetime, ids, collections, page, limit, intersects, query = None, None, None, None, None, None, None, None
if request.method == "POST":
if request.is_json:
Expand Down Expand Up @@ -353,7 +383,15 @@ def stac_search(roles=[], access_token=""):
gjson = dict()
gjson["type"] = "FeatureCollection"

features = make_geojson(items.items, links, access_token=access_token)
assets_kwargs = None

if BDC_STAC_ASSETS_ARGS:
assets_kwargs = {arg: request.args.get(arg) for arg in BDC_STAC_ASSETS_ARGS.split(",")}
if access_token:
assets_kwargs["access_token"] = access_token
assets_kwargs = "?" + url_encode(assets_kwargs)

features = make_geojson(items.items, links, assets_kwargs=assets_kwargs)

gjson["links"] = []
context = dict()
Expand All @@ -376,6 +414,7 @@ def stac_search(roles=[], access_token=""):

@current_app.route("/schemas/<string:schema_name>")
def list_schema(schema_name):
"""Return jsonschemas."""
return send_from_directory("spec/jsonschemas", schema_name)


Expand Down
7 changes: 4 additions & 3 deletions run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
pydocstyle bdc_stac tests setup.py && \
isort bdc_stac tests setup.py --check-only --diff && \
black --check --diff -l 120 -t py37 bdc_stac tests setup.py && \
check-manifest --ignore ".travis-*" --ignore ".readthedocs.*" && \
sphinx-build -qnW --color -b doctest docs/sphinx/ docs/sphinx/_build/doctest && \
pytest
check-manifest --ignore ".drone.yml,.readthedocs.yml" && \
sphinx-build -qnW --color -b doctest docs/sphinx/ docs/sphinx/_build/doctest
# pytest Fix tests

0 comments on commit 999b0f1

Please sign in to comment.