Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tilemaker/client/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def create_sample_metadata(filename: str):

return [
MapGroup(
map_group_id="example-map-group",
name="Map Group",
description="Example",
maps=[
Expand Down
55 changes: 54 additions & 1 deletion tilemaker/metadata/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pydantic import BaseModel

from .boxes import Box
from .definitions import Layer, MapGroup
from .definitions import Band, Layer, MapGroup
from .sources import SourceGroup


Expand All @@ -22,6 +22,59 @@ def merge(self, other: "DataConfiguration") -> "DataConfiguration":
source_groups=self.source_groups + other.source_groups,
)

def _match(self, name: str, query: str) -> bool:
return query.lower() in name.lower()

def filter_map_groups(self, authorized_map_groups: list, query: str) -> dict:
matched_ids: set[str] = set()
filtered_groups = []

for group in authorized_map_groups:
# Group name matches — keep entire subtree intact
if self._match(group["name"], query):
matched_ids.add(group["map_group_id"])
filtered_groups.append(group)
continue

filtered_maps = []
for map in group.get("maps", []):
# Map name matches — keep entire subtree intact
if self._match(map["name"], query):
matched_ids.add(map["map_id"])
filtered_maps.append(map)
continue

filtered_bands = []
for band in map.get("bands", []):
# Band name matches — keep entire subtree intact
if self._match(band["name"], query):
matched_ids.add(band["band_id"])
filtered_bands.append(band)
continue

filtered_layers = [
layer
for layer in band.get("layers", [])
if self._match(layer["name"], query)
and matched_ids.add(layer["layer_id"]) is None
]
if filtered_layers:
filtered_bands.append({**band, "layers": filtered_layers})

if filtered_bands:
filtered_maps.append({**map, "bands": filtered_bands})

if filtered_maps:
filtered_groups.append({**group, "maps": filtered_maps})

return {"filtered_map_groups": filtered_groups, "matched_ids": matched_ids}

@property
def bands(self) -> Iterable[Band]:
return itertools.chain.from_iterable(
map.bands for group in self.map_groups for map in group.maps
)

@property
def layers(self) -> Iterable[Layer]:
return itertools.chain.from_iterable(
Expand Down
16 changes: 16 additions & 0 deletions tilemaker/metadata/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ def create_tables(self):
"""Create all tables in the database."""
Base.metadata.create_all(self.engine)

"""
TODO: Use database queries to filter map groups based on query string
"""

def filter_map_groups(self, authorized_map_groups: list, query: str) -> dict:
return {"filtered_map_groups": [], "matched_ids": []}

@property
def map_groups(self) -> list[MapGroup]:
"""Retrieve all map groups from the database."""
Expand All @@ -87,6 +94,13 @@ def source_groups(self) -> list[SourceGroup]:
for orm_group in orm_groups
]

@property
def bands(self) -> Iterable[Band]:
"""Retrieve all bands from the database."""
return itertools.chain.from_iterable(
map.bands for group in self.map_groups for map in group.maps
)

@property
def layers(self) -> Iterable[Layer]:
"""Retrieve all layers from the database."""
Expand Down Expand Up @@ -262,6 +276,7 @@ def _orm_to_map_group(self, session: Session, orm_group: MapGroupORM) -> MapGrou
description=orm_group.description,
maps=maps,
grant=orm_group.grant,
map_group_id=orm_group.map_group_id,
)

def populate_from_config(self, config: "DataConfiguration") -> None:
Expand All @@ -286,6 +301,7 @@ def populate_from_config(self, config: "DataConfiguration") -> None:
name=map_group.name,
description=map_group.description,
grant=map_group.grant,
map_group_id=map_group.map_group_id,
)
session.add(orm_group)
session.flush()
Expand Down
48 changes: 44 additions & 4 deletions tilemaker/metadata/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,13 @@ def auth(self, grants: set[str]):
return self.grant is None or self.grant in grants


class Layer(AuthenticatedModel):
class LayerSummary(AuthenticatedModel):
layer_id: str
name: str
description: str | None = None


class Layer(LayerSummary):
provider: FITSLayerProvider | FITSCombinationLayerProvider

bounding_left: float | None = None
Expand Down Expand Up @@ -115,26 +117,47 @@ def model_post_init(self, _):
self.tile_size, self.number_of_levels = self.provider.calculate_tile_size()


class Band(AuthenticatedModel):
class LayerWithMenuState(Layer):
map_group_id: str
map_id: str
band_id: str


class BandBase(AuthenticatedModel):
band_id: str
name: str
description: str


class Band(BandBase):
layers: list[Layer]


class Map(AuthenticatedModel):
class BandMenuState(BandBase):
layers: list[LayerSummary]


class MapBase(AuthenticatedModel):
map_id: str
name: str
description: str


class Map(MapBase):
bands: list[Band]


class MapGroup(AuthenticatedModel):
class MapMenuState(MapBase):
bands: list[BandMenuState]


class MapGroupBase(AuthenticatedModel):
map_group_id: str
name: str
description: str


class MapGroup(MapGroupBase):
maps: list[Map]

def get_layer(self, layer_id: str) -> Layer | None:
Expand All @@ -145,3 +168,20 @@ def get_layer(self, layer_id: str) -> Layer | None:
return layer

return None


class MapGroupMenuState(MapGroupBase):
maps: list[MapMenuState]


class LayerDefault(AuthenticatedModel):
layer: Layer | None
default_layer_menu: list[MapGroupMenuState]
default_map_group_id: str | None
default_map_id: str | None
default_band_id: str | None


class SearchResponse(AuthenticatedModel):
filtered_layer_menu: list[MapGroupMenuState]
matched_ids: list[str]
6 changes: 5 additions & 1 deletion tilemaker/metadata/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import os
import uuid
from hashlib import md5
from pathlib import Path
from typing import Any, Literal
Expand Down Expand Up @@ -76,7 +77,10 @@ def map_group_from_fits(
)

return MapGroup(
name="Auto-Populated", description="No description provided", maps=maps
map_group_id=f"map-group-{uuid.uuid4()}",
name="Auto-Populated",
description="No description provided",
maps=maps,
)


Expand Down
1 change: 1 addition & 0 deletions tilemaker/metadata/orm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MapGroupORM(Base):
__tablename__ = "map_groups"

id = Column(Integer, primary_key=True)
map_group_id = Column(String, unique=True, nullable=False)
name = Column(String, nullable=False)
description = Column(String)
grant = Column(String)
Expand Down
8 changes: 8 additions & 0 deletions tilemaker/server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
from ..settings import settings
from .analysis import analysis_router
from .auth import setup_auth
from .bands import bands_router
from .highlights import highlights_router
from .histogram import histogram_router
from .layers import layers_router
from .map_groups import map_groups_router
from .maps import maps_router
from .search import search_router
from .sources import sources_router


Expand Down Expand Up @@ -61,7 +65,11 @@ async def lifespan(app: FastAPI):
app.include_router(highlights_router)
app.include_router(histogram_router)
app.include_router(sources_router)
app.include_router(map_groups_router)
app.include_router(maps_router)
app.include_router(bands_router)
app.include_router(layers_router)
app.include_router(search_router)
app.include_router(analysis_router)

if settings.serve_frontend:
Expand Down
32 changes: 32 additions & 0 deletions tilemaker/server/bands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Endpoint for summary data of a band's layers
"""

from fastapi import (
APIRouter,
Request,
)

from tilemaker.metadata.definitions import LayerSummary

bands_router = APIRouter(prefix="/bands", tags=["List of Bands"])


@bands_router.get(
"/{band_id}/layers",
response_model=list[LayerSummary],
summary="Get the list of layer summaries associated with a Band.",
description="Retrieve a list of LayerSummary objects that belong to a particular Band.",
)
def get_layer_summaries_of_band(band_id: str, request: Request):
layer_summaries = []
for band in request.app.config.bands:
if band.band_id == band_id and band.auth(request.auth.scopes):
for layer in band.layers:
layer_summary = LayerSummary(
layer_id=layer.layer_id,
name=layer.name,
description=layer.description,
)
layer_summaries.append(layer_summary)
return layer_summaries
Loading
Loading