Skip to content

Commit

Permalink
Stop using flask-pydantic-spec. (#2014)
Browse files Browse the repository at this point in the history
  • Loading branch information
tdilauro authored Aug 30, 2024
1 parent c18cc6b commit 85f6d58
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 174 deletions.
31 changes: 1 addition & 30 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ module = [
"feedparser",
"firebase_admin.*",
"flask_babel",
"flask_pydantic_spec.*",
"fuzzywuzzy",
"google.auth",
"greenlet",
Expand Down Expand Up @@ -234,7 +233,6 @@ firebase-admin = "^6.0.1"
Flask = "^3.0"
Flask-Babel = "^4.0"
Flask-Cors = "4.0.1"
flask-pydantic-spec = "^0.6.0"
fuzzywuzzy = "0.18.0" # fuzzywuzzy is for author name manipulations
html-sanitizer = "^2.1.0"
isbnlib = "^3.10.14"
Expand Down
46 changes: 21 additions & 25 deletions src/palace/manager/api/admin/controller/custom_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import flask
from flask import Response, url_for
from flask_babel import lazy_gettext as _
from flask_pydantic_spec.flask_backend import Context
from pydantic import BaseModel

from palace.manager.api.admin.controller.base import AdminPermissionsControllerMixin
Expand Down Expand Up @@ -38,6 +37,7 @@
from palace.manager.sqlalchemy.model.licensing import LicensePool
from palace.manager.sqlalchemy.model.work import Work
from palace.manager.sqlalchemy.util import create, get_one
from palace.manager.util.flask_util import parse_multi_dict
from palace.manager.util.problem_detail import ProblemDetail, ProblemDetailException


Expand Down Expand Up @@ -98,28 +98,22 @@ def custom_lists(self) -> dict | ProblemDetail | Response | None:
return dict(custom_lists=custom_lists)

if flask.request.method == "POST":
ctx: Context = flask.request.context.body # type: ignore
list_ = self.CustomListPostRequest.parse_obj(
parse_multi_dict(flask.request.form)
)
return self._create_or_update_list(
library,
ctx.name,
ctx.entries,
ctx.collections,
id=ctx.id,
auto_update=ctx.auto_update,
auto_update_facets=ctx.auto_update_facets,
auto_update_query=ctx.auto_update_query,
list_.name,
list_.entries,
list_.collections,
id=list_.id,
auto_update=list_.auto_update,
auto_update_facets=list_.auto_update_facets,
auto_update_query=list_.auto_update_query,
)

return None

def _getJSONFromRequest(self, values: str | None) -> list:
if values:
return_values = json.loads(values)
else:
return_values = []

return return_values

def _get_work_from_urn(self, library: Library, urn: str | None) -> Work | None:
identifier, ignore = Identifier.parse_urn(self._db, urn)

Expand Down Expand Up @@ -365,17 +359,19 @@ def custom_list(self, list_id: int) -> Response | dict | ProblemDetail | None:
)

elif flask.request.method == "POST":
ctx: Context = flask.request.context.body # type: ignore
list_ = self.CustomListPostRequest.parse_obj(
parse_multi_dict(flask.request.form)
)
return self._create_or_update_list(
library,
ctx.name,
ctx.entries,
ctx.collections,
deleted_entries=ctx.deletedEntries,
list_.name,
list_.entries,
list_.collections,
deleted_entries=list_.deletedEntries,
id=list_id,
auto_update=ctx.auto_update,
auto_update_query=ctx.auto_update_query,
auto_update_facets=ctx.auto_update_facets,
auto_update=list_.auto_update,
auto_update_query=list_.auto_update_query,
auto_update_facets=list_.auto_update_facets,
)

elif flask.request.method == "DELETE":
Expand Down
69 changes: 3 additions & 66 deletions src/palace/manager/api/admin/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,19 @@

import flask
from flask import Response, make_response, redirect, url_for
from flask_pydantic_spec import FileResponse as SpecFileResponse
from flask_pydantic_spec import Request as SpecRequest
from flask_pydantic_spec import Response as SpecResponse

from palace.manager.api.admin.config import Configuration as AdminClientConfig
from palace.manager.api.admin.config import OperationalMode
from palace.manager.api.admin.controller.custom_lists import CustomListsController
from palace.manager.api.admin.dashboard_stats import generate_statistics
from palace.manager.api.admin.model.dashboard_statistics import StatisticsResponse
from palace.manager.api.admin.model.inventory_report import InventoryReportInfo
from palace.manager.api.admin.model.quicksight import (
QuicksightDashboardNamesResponse,
QuicksightGenerateUrlRequest,
QuicksightGenerateUrlResponse,
)
from palace.manager.api.admin.templates import (
admin_sign_in_again as sign_in_again_template,
)
from palace.manager.api.app import api_spec, app
from palace.manager.api.app import app
from palace.manager.api.controller.static_file import StaticFileController
from palace.manager.api.routes import allows_library, has_library, library_route
from palace.manager.core.app_server import (
ensure_pydantic_after_problem_detail,
returns_problem_detail,
)
from palace.manager.util.problem_detail import (
BaseProblemDetailException,
ProblemDetail,
ProblemDetailModel,
)
from palace.manager.core.app_server import returns_problem_detail
from palace.manager.util.problem_detail import BaseProblemDetailException, ProblemDetail

# An admin's session will expire after this amount of time and
# the admin will have to log in again.
Expand Down Expand Up @@ -95,8 +78,6 @@ def decorated(*args, **kwargs):


def returns_json_or_response_or_problem_detail(f):
ensure_pydantic_after_problem_detail(f)

@wraps(f)
def decorated(*args, **kwargs):
try:
Expand Down Expand Up @@ -348,7 +329,6 @@ def circulation_events():


@app.route("/admin/stats")
@api_spec.validate(resp=SpecResponse(HTTP_200=StatisticsResponse), tags=["admin.stats"])
@returns_json_or_response_or_problem_detail
@requires_admin
def stats():
Expand All @@ -359,11 +339,6 @@ def stats():


@app.route("/admin/quicksight_embed/<dashboard_name>")
@api_spec.validate(
resp=SpecResponse(HTTP_200=QuicksightGenerateUrlResponse),
tags=["admin.quicksight"],
query=QuicksightGenerateUrlRequest,
)
@returns_json_or_response_or_problem_detail
@requires_admin
def generate_quicksight_url(dashboard_name: str):
Expand All @@ -373,10 +348,6 @@ def generate_quicksight_url(dashboard_name: str):


@app.route("/admin/quicksight_embed/names")
@api_spec.validate(
resp=SpecResponse(HTTP_200=QuicksightDashboardNamesResponse),
tags=["admin.quicksight"],
)
@returns_json_or_response_or_problem_detail
@requires_admin
def get_quicksight_names():
Expand Down Expand Up @@ -573,11 +544,6 @@ def discovery_service_library_registrations():


@library_route("/admin/custom_lists", methods=["POST"])
@api_spec.validate(
resp=SpecFileResponse(content_type="application/atom+xml"),
body=SpecRequest(CustomListsController.CustomListPostRequest),
tags=["admin.customlists"],
)
@has_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand All @@ -587,10 +553,6 @@ def custom_lists_post():


@library_route("/admin/custom_lists", methods=["GET"])
@api_spec.validate(
resp=SpecFileResponse(content_type="application/atom+xml"),
tags=["admin.customlists"],
)
@has_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand All @@ -600,10 +562,6 @@ def custom_lists_get():


@library_route("/admin/custom_list/<list_id>", methods=["GET"])
@api_spec.validate(
resp=SpecFileResponse(content_type="application/atom+xml"),
tags=["admin.customlists"],
)
@has_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand All @@ -613,11 +571,6 @@ def custom_list_get(list_id: int):


@library_route("/admin/custom_list/<list_id>", methods=["POST"])
@api_spec.validate(
resp=SpecFileResponse(content_type="application/atom+xml"),
body=SpecRequest(CustomListsController.CustomListPostRequest),
tags=["admin.customlists"],
)
@has_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand All @@ -636,13 +589,6 @@ def custom_list_delete(list_id):


@library_route("/admin/custom_list/<list_id>/share", methods=["POST"])
@api_spec.validate(
resp=SpecResponse(
HTTP_200=CustomListsController.CustomListSharePostResponse,
HTTP_403=ProblemDetailModel,
),
tags=["admin.customlists"],
)
@has_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand All @@ -653,7 +599,6 @@ def custom_list_share(list_id: int):


@library_route("/admin/custom_list/<list_id>/share", methods=["DELETE"])
@api_spec.validate(resp=SpecResponse(HTTP_204=None), tags=["admin.customlists"])
@has_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand Down Expand Up @@ -736,14 +681,6 @@ def diagnostics():
"/admin/reports/inventory_report/<path:library_short_name>",
methods=["GET"],
)
@api_spec.validate(
resp=SpecResponse(
HTTP_200=InventoryReportInfo,
HTTP_403=ProblemDetailModel,
HTTP_404=ProblemDetailModel,
),
tags=["admin.inventory"],
)
@allows_library
@returns_json_or_response_or_problem_detail
@requires_admin
Expand Down
7 changes: 0 additions & 7 deletions src/palace/manager/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import flask_babel
from flask import request
from flask_babel import Babel
from flask_pydantic_spec import FlaskPydanticSpec
from sqlalchemy.orm import Session

from palace.manager.api.admin.controller import setup_admin_controllers
Expand Down Expand Up @@ -39,12 +38,6 @@ def get_locale():
app.config["BABEL_TRANSLATION_DIRECTORIES"] = "../translations"
babel = Babel(app, locale_selector=get_locale)

# The autodoc spec, can be accessed at "/apidoc/swagger"
api_spec = FlaskPydanticSpec(
"Palace Manager", mode="strict", title="Palace Manager API"
)
api_spec.register(app)

# We use URIs as identifiers throughout the application, meaning that
# we never want werkzeug's merge_slashes feature.
app.url_map.merge_slashes = False
Expand Down
14 changes: 1 addition & 13 deletions src/palace/manager/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@
import flask
from flask import Response, make_response, request
from flask_cors.core import get_cors_options, set_cors_headers
from flask_pydantic_spec import Response as SpecResponse

from palace.manager.api.app import api_spec, app
from palace.manager.api.model.patron_auth import PatronAuthAccessToken
from palace.manager.api.model.time_tracking import (
PlaytimeEntriesPost,
PlaytimeEntriesPostResponse,
)
from palace.manager.api.app import app
from palace.manager.core.app_server import compressible, returns_problem_detail
from palace.manager.sqlalchemy.hassessioncache import HasSessionCache
from palace.manager.util.problem_detail import ProblemDetail
Expand Down Expand Up @@ -362,7 +356,6 @@ def delete_patron_devices():


@library_dir_route("/patrons/me/token", methods=["POST"])
@api_spec.validate(resp=SpecResponse(HTTP_200=PatronAuthAccessToken), tags=["patron"])
@has_library
@requires_auth
@returns_problem_detail
Expand Down Expand Up @@ -540,11 +533,6 @@ def track_analytics_event(identifier_type, identifier, event_type):
)
@has_library
@requires_auth
@api_spec.validate(
resp=SpecResponse(HTTP_200=PlaytimeEntriesPostResponse),
body=PlaytimeEntriesPost,
tags=["analytics"],
)
@returns_problem_detail
def track_playtime_events(collection_id, identifier_type, identifier):
"""The actual response type is 207, but due to a bug in flask-pydantic-spec we must document it as a 200"""
Expand Down
Loading

0 comments on commit 85f6d58

Please sign in to comment.