Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: feeds operations API function #838

Merged
merged 38 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2ab431f
add feeds operations api function and deploy script
davidgamez Nov 28, 2024
7fec9f3
Merge branch 'main' into feat/operations_api
davidgamez Nov 28, 2024
0d32e82
increase test coverage
davidgamez Nov 28, 2024
0c99b8d
add missing api generation script call
davidgamez Nov 28, 2024
6614855
fix local test imports
davidgamez Nov 29, 2024
662b3b4
open api schema cleanup
davidgamez Nov 29, 2024
c016098
add operational status temporary support
davidgamez Dec 2, 2024
4ad0194
Merge branch 'main' into feat/operations_api
davidgamez Dec 2, 2024
78dfb30
add unit tests
davidgamez Dec 2, 2024
ab808f7
add feed api endpoint unit tests
davidgamez Dec 3, 2024
510099e
add infra code
davidgamez Dec 3, 2024
35941ed
fix ci failing test
davidgamez Dec 3, 2024
88c2c63
add missing configuration
davidgamez Dec 3, 2024
8afc2df
add missing configuration
davidgamez Dec 3, 2024
53d54a2
fix ingress settings
davidgamez Dec 4, 2024
7c4935f
add missing generated code
davidgamez Dec 4, 2024
8b1660c
fix operations generated folder reference
davidgamez Dec 4, 2024
2c89a5b
update oauth2 client id from 1password
davidgamez Dec 4, 2024
5bed790
fix var name
davidgamez Dec 4, 2024
5656197
add update gtfs_rt feed
davidgamez Dec 4, 2024
3fd13f4
add update gtfs-rt fixes and unit test coverage
davidgamez Dec 4, 2024
a28edc7
allow operations api to run unauthenticated
davidgamez Dec 4, 2024
d125ddd
Fix GTFS-RT update endpoint when static reference is changed
davidgamez Dec 4, 2024
dbb0221
fix email restricted function
davidgamez Dec 4, 2024
f308820
add logging
davidgamez Dec 4, 2024
fef4bcd
fix request context email verification
davidgamez Dec 4, 2024
3a45595
add missing variables
davidgamez Dec 4, 2024
a2cb3f9
fix materialized view refresh
davidgamez Dec 4, 2024
b440494
waiting for the view to be refreshed
davidgamez Dec 5, 2024
839f1e5
revert materialized view changes
davidgamez Dec 5, 2024
6a49786
fix search wip filter
davidgamez Dec 5, 2024
3ffaeae
unifying oauth2 creds
davidgamez Dec 5, 2024
eeb2c7b
adding login
davidgamez Dec 5, 2024
6db8ae4
Revert "adding login"
davidgamez Dec 5, 2024
6d9094f
fix upper case issue for entity type
davidgamez Dec 5, 2024
d0ee801
fix operational status update
davidgamez Dec 6, 2024
0c17397
fix failing test
davidgamez Dec 6, 2024
9ce3f6c
Update .github/workflows/api-deployer.yml
davidgamez Dec 6, 2024
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
4 changes: 4 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ jobs:
scripts/setup-openapi-generator.sh
scripts/api-gen.sh

- name: Generate Operations API code
run: |
scripts/api-operations-gen.sh

- name: Unit tests - API
shell: bash
run: |
Expand Down
304 changes: 304 additions & 0 deletions docs/OperationsAPI.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Mobility Database Catalog Operations
description: |
API for the Mobility Database Catalog Operations. See [https://mobilitydatabase.org/](https://mobilitydatabase.org/). This is an API for internal management tool.

The Mobility Database Operation API uses API Token authentication.
termsOfService: https://mobilitydatabase.org/terms-and-conditions
contact:
name: MobilityData
url: https://mobilitydata.org/
email: [email protected]
license:
name: MobilityData License
url: https://www.apache.org/licenses/LICENSE-2.0

tags:
- name: "operations"
description: "Mobility Database Operations"

paths:
/v1/operations/feeds/gtfs:
put:
description: Update the specified feed in the Mobility Database.
tags:
- "operations"
operationId: updateGtfsFeed
security:
- ApiKeyAuth: []
requestBody:
description: Payload to update the specified feed. Must be either a GtfsFeed or GtfsRTFeed object.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateRequestGtfsFeed"
responses:
204:
description: >
The feed was successfully updated. No content is returned.

components:
schemas:
Redirect:
type: object
properties:
target_id:
description: The feed ID that should be used in replacement of the current one.
type: string
example: mdb-10
comment:
description: A comment explaining the redirect.
type: string
example: Redirected because of a change of URL.
BasicFeed:
Copy link
Contributor

@jcpitre jcpitre Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it refer to the BasicFeed in DatabaseCatalogAPI.yml?
Maybe it could be a future improvement

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be tricky to do an import from DatabaseCatalogAPI.ym as it will impact the development process and the generator. However, a good improvement when we implement the getFeeds endpoint, add a BasicFeed entity to this schema.

type: object
discriminator:
propertyName: data_type
mapping:
gtfs: '#/components/schemas/GtfsFeed'
gtfs_rt: '#/components/schemas/GtfsRTFeed'
properties:
id:
description: Unique identifier used as a key for the feeds table.
type: string
example: mdb-1210
data_type:
$ref: "#/components/schemas/DataType"
status:
description: >
Describes status of the Feed. Should be one of
* `active` Feed should be used in public trip planners.
* `deprecated` Feed is explicitly deprecated and should not be used in public trip planners.
* `inactive` Feed hasn't been recently updated and should be used at risk of providing outdated information.
* `development` Feed is being used for development purposes and should not be used in public trip planners.
type: string
enum:
- active
- deprecated
- inactive
- development
example: deprecated
# Have to put the enum inline because of a bug in openapi-generator
# $ref: "#/components/schemas/FeedStatus"
created_at:
description: The date and time the feed was added to the database, in ISO 8601 date-time format.
type: string
example: 2023-07-10T22:06:00Z
format: date-time
external_ids:
$ref: "#/components/schemas/ExternalIds"
provider:
description: A commonly used name for the transit provider included in the feed.
type: string
example: Los Angeles Department of Transportation (LADOT, DASH, Commuter Express)
feed_name:
description: >
An optional description of the data feed, e.g to specify if the data feed is an aggregate of
multiple providers, or which network is represented by the feed.
type: string
example: Bus
note:
description: A note to clarify complex use cases for consumers.
type: string
feed_contact_email:
description: Use to contact the feed producer.
type: string
example: [email protected]
source_info:
$ref: "#/components/schemas/SourceInfo"
redirects:
type: array
items:
$ref: "#/components/schemas/Redirect"
required:
- id
- data_type
- status

GtfsFeed:
allOf:
- $ref: "#/components/schemas/BasicFeed"
- type: object
# TODO add this properties when implementing the get endpoint
# properties:
# locations:
# $ref: "#/components/schemas/Locations"
# latest_dataset:
# $ref: "#/components/schemas/LatestDataset"

UpdateRequestGtfsRtFeed:
allOf:
- $ref: "#/components/schemas/BasicFeed"
- type: object
properties:
entity_types:
type: array
items:
$ref: "#/components/schemas/EntityType"
feed_references:
description:
A list of the GTFS feeds that the real time source is associated with, represented by their MDB source IDs.
type: array
items:
type: string
example: "mdb-20"

UpdateRequestGtfsFeed:
type: object
properties:
id:
description: Unique identifier used as a key for the feeds table.
type: string
example: mdb-1210
status:
$ref: "#/components/schemas/FeedStatus"
external_ids:
$ref: "#/components/schemas/ExternalIds"
provider:
description: A commonly used name for the transit provider included in the feed.
type: string
example: Los Angeles Department of Transportation (LADOT, DASH, Commuter Express)
feed_name:
description: >
An optional description of the data feed, e.g to specify if the data feed is an aggregate of
multiple providers, or which network is represented by the feed.
type: string
example: Bus
note:
description: A note to clarify complex use cases for consumers.
type: string
feed_contact_email:
description: Use to contact the feed producer.
type: string
example: [email protected]
source_info:
$ref: "#/components/schemas/SourceInfo"
redirects:
type: array
items:
$ref: "#/components/schemas/Redirect"
required:
- id
- status

EntityType:
type: string
enum:
- vp
- tu
- sa
example: vp
description: >
The type of realtime entry:
* vp - vehicle positions
* tu - trip updates
* sa - service alerts

ExternalIds:
type: array
items:
$ref: "#/components/schemas/ExternalId"

ExternalId:
type: object
properties:
external_id:
description: The ID that can be use to find the feed data in an external or legacy database.
type: string
example: 1210
source:
description: The source of the external ID, e.g. the name of the database where the external ID can be used.
type: string
example: mdb

SourceInfo:
type: object
properties:
producer_url:
description: >
URL where the producer is providing the dataset.
Refer to the authentication information to know how to access this URL.
type: string
format: url
example: https://ladotbus.com/gtfs
authentication_type:
description: >
Defines the type of authentication required to access the `producer_url`. Valid values for this field are:
* 0 or (empty) - No authentication required.
* 1 - The authentication requires an API key, which should be passed as value of the parameter api_key_parameter_name in the URL. Please visit URL in authentication_info_url for more information.
* 2 - The authentication requires an HTTP header, which should be passed as the value of the header api_key_parameter_name in the HTTP request.
When not provided, the authentication type is assumed to be 0.
type: string
enum:
- 0
- 1
- 2
example: 2
authentication_info_url:
description: >
Contains a URL to a human-readable page describing how the authentication should be performed and how credentials can be created.
This field is required for `authentication_type=1` and `authentication_type=2`.
type: string
format: url
example: https://apidevelopers.ladottransit.com
api_key_parameter_name:
type: string
description: >
Defines the name of the parameter to pass in the URL to provide the API key.
This field is required for `authentication_type=1` and `authentication_type=2`.
example: Ocp-Apim-Subscription-Key
license_url:
description: A URL where to find the license for the feed.
type: string
format: url
example: https://www.ladottransit.com/dla.html

FeedStatus:
description: >
Describes status of the Feed. Should be one of
* `active` Feed should be used in public trip planners.
* `deprecated` Feed is explicitly deprecated and should not be used in public trip planners.
* `inactive` Feed hasn't been recently updated and should be used at risk of providing outdated information.
* `development` Feed is being used for development purposes and should not be used in public trip planners.
type: string
enum:
- active
- deprecated
- inactive
- development
example: active

DataType:
description: >
Describes data type of a fee. Should be one of
* `gtfs` GTFS feed.
* `gtfs_rt` GTFS-RT feed.
* `gbfs` GBFS feed.
type: string
enum:
- gtfs
- gtfs_rt
- gbfs
example: gtfs

parameters:
feed_id_path_param:
name: id
in: path
description: The feed ID of the requested feed.
required: True
schema:
type: string
example: mdb-1210

securitySchemes:
ApiKeyAuth:
type: apiKey
name: X-API-KEY
in: header

security:
- ApiKeyAuth: []
2 changes: 1 addition & 1 deletion functions-python/.flake8
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[flake8]
max-line-length = 120
exclude = .git,__pycache__,__init__.py,.mypy_cache,.pytest_cache,venv,build,.*,database_gen
exclude = .git,__pycache__,__init__.py,.mypy_cache,.pytest_cache,venv,build,.*,database_gen,feeds_operations_gen
# Ignored because conflict with black
extend-ignore = E203
17 changes: 17 additions & 0 deletions functions-python/.gcloudignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This file specifies files that are *not* uploaded to Google Cloud
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore

node_modules
#!include:.gitignore
19 changes: 17 additions & 2 deletions functions-python/helpers/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,30 @@
import threading
from typing import Final

from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, text, event
from sqlalchemy.orm import sessionmaker, mapper
import logging

DB_REUSE_SESSION: Final[str] = "DB_REUSE_SESSION"
lock = threading.Lock()
global_session = None


def set_cascade(mapper, class_):
if class_.__name__ == "Gtfsfeed":
for rel in class_.__mapper__.relationships:
if rel.key in [
"redirectingids",
"redirectingids_",
"externalids",
"externalids_",
]:
rel.cascade = "all, delete-orphan"


event.listen(mapper, "mapper_configured", set_cascade)
jcpitre marked this conversation as resolved.
Show resolved Hide resolved


def get_db_engine(database_url: str = None, echo: bool = True):
"""
:return: Database engine
Expand Down
22 changes: 22 additions & 0 deletions functions-python/helpers/query_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Type

from database_gen.sqlacodegen_models import Feed, Gtfsrealtimefeed, Gtfsfeed, Gbfsfeed

feed_mapping = {"gtfs_rt": Gtfsrealtimefeed, "gtfs": Gtfsfeed, "gbfs": Gbfsfeed}


def get_model(data_type: str | None) -> Type[Feed]:
"""
Get the model based on the data type
"""
return feed_mapping.get(data_type, Feed)


def query_feed_by_stable_id(
session, stable_id: str, data_type: str | None
) -> Gtfsrealtimefeed | Gtfsfeed | Gbfsfeed:
"""
Query the feed by stable id
"""
model = get_model(data_type)
return session.query(model).filter(model.stable_id == stable_id).first()
Loading
Loading