Skip to content
This repository was archived by the owner on Sep 26, 2025. It is now read-only.

Commit a882316

Browse files
authored
Merge pull request #64 from goat-community/feature/expressions
fix: add auth_lite to unique-value & enable auth_z for project publis…
2 parents 2036f4f + 30f1ad3 commit a882316

File tree

3 files changed

+63
-14
lines changed

3 files changed

+63
-14
lines changed

src/endpoints/v2/layer.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
HTTPException,
1515
Path,
1616
Query,
17+
Request,
1718
UploadFile,
1819
status,
1920
)
2021
from fastapi.responses import FileResponse, JSONResponse
2122
from fastapi_pagination import Page
2223
from fastapi_pagination import Params as PaginationParams
2324
from pydantic import UUID4
25+
from sqlmodel import select
2426

2527
from src.core.config import settings
2628

@@ -32,15 +34,17 @@
3234
from src.crud.crud_layer import CRUDLayerDatasetUpdate, CRUDLayerExport, CRUDLayerImport
3335
from src.crud.crud_layer import layer as crud_layer
3436
from src.crud.crud_layer_project import layer_project as crud_layer_project
37+
from src.db.models._link_model import LayerProjectLink
3538
from src.db.models.layer import (
3639
FeatureUploadType,
3740
FileUploadType,
3841
Layer,
3942
LayerType,
4043
TableUploadType,
4144
)
45+
from src.db.models.project import ProjectPublic
4246
from src.db.session import AsyncSession
43-
from src.deps.auth import auth_z
47+
from src.deps.auth import auth_z, auth_z_lite
4448
from src.endpoints.deps import get_db, get_user_id
4549
from src.schemas.common import OrderEnum
4650
from src.schemas.error import HTTPErrorHandler
@@ -684,9 +688,10 @@ async def get_area_statistics(
684688
summary="Get unique values of a column",
685689
response_model=Page[IUniqueValue],
686690
status_code=200,
687-
dependencies=[Depends(auth_z)],
691+
# dependencies=[Depends(auth_z)],
688692
)
689693
async def get_unique_values(
694+
request: Request,
690695
async_session: AsyncSession = Depends(get_db),
691696
page_params: PaginationParams = Depends(),
692697
layer_id: UUID4 = Path(
@@ -712,6 +717,30 @@ async def get_unique_values(
712717
):
713718
"""Get unique values of a column. Based on the passed CQL-filter and order."""
714719

720+
# Check authorization status
721+
try:
722+
await auth_z_lite(request, async_session)
723+
except HTTPException:
724+
725+
public_layer = (
726+
select(LayerProjectLink)
727+
.join(
728+
ProjectPublic,
729+
LayerProjectLink.project_id == ProjectPublic.project_id,
730+
)
731+
.where(
732+
LayerProjectLink.layer_id == layer_id,
733+
)
734+
.limit(1)
735+
)
736+
result = await async_session.execute(public_layer)
737+
public_layer = result.scalars().first()
738+
# Check if layer is public
739+
if not public_layer:
740+
raise HTTPException(
741+
status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized"
742+
)
743+
715744
with HTTPErrorHandler():
716745
values = await crud_layer.get_unique_values(
717746
async_session=async_session,

src/endpoints/v2/project.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1-
from typing import List, Annotated
1+
from typing import List
22
from uuid import UUID
33

4-
from fastapi import APIRouter, Body, Depends, HTTPException, Path, Query, status, Request
4+
from fastapi import (
5+
APIRouter,
6+
Body,
7+
Depends,
8+
HTTPException,
9+
Path,
10+
Query,
11+
Request,
12+
status,
13+
)
514
from fastapi.responses import JSONResponse
615
from fastapi_pagination import Page
716
from fastapi_pagination import Params as PaginationParams
@@ -31,6 +40,7 @@
3140
IProjectRead,
3241
IRasterProjectRead,
3342
ITableProjectRead,
43+
ProjectPublicRead,
3444
)
3545
from src.schemas.project import (
3646
request_examples as project_request_examples,
@@ -549,7 +559,7 @@ async def get_statistic_aggregation(
549559
expression: str | None = Query(
550560
None,
551561
description="The QGIS expression to use for the statistic operation",
552-
example="sum(\"population\")",
562+
example='sum("population")',
553563
),
554564
size: int = Query(
555565
100, description="The number of grouped values to return", example=5
@@ -570,14 +580,16 @@ async def get_statistic_aggregation(
570580
# Check authorization status
571581
try:
572582
await auth_z_lite(request, async_session)
573-
except HTTPException as e:
583+
except HTTPException:
574584
# Check publication status if unauthorized
575585
public_project = await crud_project.get_public_project(
576586
async_session=async_session,
577587
project_id=str(project_id),
578588
)
579589
if not public_project:
580-
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized")
590+
raise HTTPException(
591+
status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized"
592+
)
581593

582594
# Ensure an operation or expression is specified
583595
if operation is None and expression is None:
@@ -587,12 +599,16 @@ async def get_statistic_aggregation(
587599
)
588600

589601
# Ensure a column name is specified for all operations except count
590-
if operation and operation != ColumnStatisticsOperation.count and column_name is None:
602+
if (
603+
operation
604+
and operation != ColumnStatisticsOperation.count
605+
and column_name is None
606+
):
591607
raise HTTPException(
592608
status_code=status.HTTP_400_BAD_REQUEST,
593609
detail="A column name must be specified for all operations except count.",
594610
)
595-
611+
596612
# If an operation is specified, a group-by column name must also be specified
597613
if operation and group_by_column_name is None:
598614
raise HTTPException(
@@ -670,14 +686,16 @@ async def get_statistic_histogram(
670686
# Check authorization status
671687
try:
672688
await auth_z_lite(request, async_session)
673-
except HTTPException as e:
689+
except HTTPException:
674690
# Check publication status if unauthorized
675691
public_project = await crud_project.get_public_project(
676692
async_session=async_session,
677693
project_id=str(project_id),
678694
)
679695
if not public_project:
680-
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized")
696+
raise HTTPException(
697+
status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized"
698+
)
681699

682700
# Ensure the number of bins is not excessively large
683701
if num_bins > 100:
@@ -979,6 +997,8 @@ async def delete_scenario_features(
979997
@router.get(
980998
"/{project_id}/public",
981999
summary="Get public project",
1000+
response_model=ProjectPublicRead | None,
1001+
response_model_exclude_none=True,
9821002
)
9831003
async def get_public_project(
9841004
project_id: str,
@@ -997,7 +1017,7 @@ async def get_public_project(
9971017
@router.post(
9981018
"/{project_id}/publish",
9991019
summary="Publish a project",
1000-
# dependencies=[Depends(auth_z)],
1020+
dependencies=[Depends(auth_z)],
10011021
)
10021022
async def publish_project(
10031023
project_id: str,
@@ -1016,7 +1036,7 @@ async def publish_project(
10161036
@router.delete(
10171037
"/{project_id}/unpublish",
10181038
summary="Unpublish a project",
1019-
# dependencies=[Depends(auth_z)],
1039+
dependencies=[Depends(auth_z)],
10201040
)
10211041
async def unpublish_project(
10221042
project_id: str,

src/schemas/project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class ProjectPublicProjectConfig(BaseModel):
247247
id: UUID = Field(..., description="Project ID")
248248
name: str = Field(..., description="Project name")
249249
description: str | None = Field(..., description="Project description")
250-
tags: List[str] | None = Field(..., description="Project tags")
250+
tags: List[str] | None = Field(None, description="Project tags")
251251
thumbnail_url: HttpUrl | None = Field(None, description="Project thumbnail URL")
252252
initial_view_state: InitialViewState = Field(
253253
..., description="Initial view state of the project"

0 commit comments

Comments
 (0)