refactor: move versioning efforts to initalization

This commit is contained in:
Alexandre Teles 2023-11-21 01:51:44 -03:00 committed by Alexandre Teles (afterSt0rm)
parent 8d36663610
commit 42c88290b1
14 changed files with 101 additions and 49 deletions

View File

@ -2,15 +2,26 @@
from sanic import Blueprint
import importlib
import pkgutil
from api.utils.versioning import get_version
blueprints = []
for _, module_name, _ in pkgutil.iter_modules(["api"]):
# Import the module
module = importlib.import_module(f"api.{module_name}")
# Dynamically import all modules in the 'api' package, excluding subdirectories
versioned_blueprints = {}
for finder, module_name, ispkg in pkgutil.iter_modules(["api"]):
if not ispkg:
# Import the module
module = importlib.import_module(f"api.{module_name}")
# Add the module's blueprint to the list, if it exists
if hasattr(module, module_name):
blueprints.append(getattr(module, module_name))
# Add the module's blueprint to the versioned list, if it exists
if hasattr(module, module_name):
blueprint = getattr(module, module_name)
version = get_version(module_name)
versioned_blueprints.setdefault(version, []).append(blueprint)
# Create the Blueprint group with the dynamically imported blueprints
api = Blueprint.group(*blueprints, url_prefix="/")
# Create Blueprint groups for each version
api = []
for version, blueprints in versioned_blueprints.items():
if version == "old":
group = Blueprint.group(*blueprints, url_prefix="/")
else:
group = Blueprint.group(*blueprints, version=version, url_prefix="/")
api.append(group)

View File

@ -10,6 +10,7 @@ Routes:
- DELETE /announcements/<announcement_id:int>: Delete an announcement.
"""
import os
import datetime
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
@ -21,10 +22,8 @@ import sanic_beskar
from api.models.announcements import AnnouncementResponseModel
from api.utils.limiter import limiter
from api.utils.versioning import get_version
module_name = "announcements"
announcements: Blueprint = Blueprint(module_name, version=get_version(module_name))
announcements: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@announcements.get("/announcements")

View File

@ -9,8 +9,7 @@ Routes:
- GET /patches/<tag:str>: Retrieve a list of patches for a given release tag.
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
@ -20,7 +19,7 @@ from api.models.github import *
from api.models.compat import ToolsResponseModel, ContributorsResponseModel
from config import compat_repositories, owner
compat: Blueprint = Blueprint("old")
compat: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
github_backend: Github = Github()

32
api/connections.py Normal file
View File

@ -0,0 +1,32 @@
"""
This module provides a blueprint for the connections endpoint.
Routes:
- GET /connections: Get ReVanced connection links.
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
from api.models.socials import ConnectionsResponseModel
from config import social_links
connections: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@connections.get("/connections")
@openapi.definition(
summary="Get ReVanced connection links",
response=[ConnectionsResponseModel],
)
async def root(request: Request) -> JSONResponse:
"""
Returns a JSONResponse with a dictionary containing ReVanced connection links.
**Returns:**
- JSONResponse: A Sanic JSONResponse instance containing a dictionary with the connection links.
"""
data: dict[str, dict] = {"connections": social_links}
return json(data, status=200)

View File

@ -5,16 +5,16 @@ Routes:
- GET /donations: Get ReVanced donation links and wallets.
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
from api.models.donations import DonationsResponseModel
from config import wallets, links
from api.utils.versioning import get_version
module_name = "donations"
donations: Blueprint = Blueprint(module_name, version=get_version(module_name))
donations: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@donations.get("/donations")

View File

@ -10,6 +10,7 @@ Routes:
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
@ -18,10 +19,8 @@ from api.backends.entities import Release, Contributor
from api.backends.github import Github, GithubRepository
from api.models.github import *
from config import owner, default_repository
from api.utils.versioning import get_version
module_name = "github"
github: Blueprint = Blueprint("github", version=get_version(module_name))
github: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
github_backend: Github = Github()

View File

@ -5,16 +5,15 @@ Routes:
- GET /info: Get info about the owner of the API.
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
from api.models.info import InfoResponseModel
from config import default_info
from api.utils.versioning import get_version
module_name = "info"
info: Blueprint = Blueprint("info", version=get_version(module_name))
info: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@info.get("/info")

View File

@ -5,6 +5,7 @@ Routes:
- POST /login: Login to the API
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
@ -13,10 +14,7 @@ from sanic_beskar.exceptions import AuthenticationError
from api.utils.auth import beskar
from api.utils.limiter import limiter
from api.utils.versioning import get_version
module_name = "login"
login: Blueprint = Blueprint(module_name, version=get_version(module_name))
login: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@login.post("/login")

View File

@ -11,7 +11,7 @@ class SocialFields(BaseModel):
preferred: bool
class SocialsResponseModel(BaseModel):
class ConnectionsResponseModel(BaseModel):
"""
A Pydantic BaseModel that represents a dictionary of social links.
"""
@ -21,3 +21,15 @@ class SocialsResponseModel(BaseModel):
A dictionary where the keys are the names of the social networks, and
the values are the links to the profiles or pages.
"""
class ConnectionsResponseModel(BaseModel):
"""
A Pydantic BaseModel that represents a dictionary of connection links.
"""
connections: list[SocialFields]
"""
A dictionary where the keys are the names of the social networks, and
the values are the links to the profiles or pages.
"""

View File

@ -5,12 +5,11 @@ Routes:
- HEAD /ping: Ping the API.
"""
import os
from sanic import Blueprint, HTTPResponse, Request, response
from sanic_ext import openapi
from api.utils.versioning import get_version
module_name = "ping"
ping: Blueprint = Blueprint(module_name, version=get_version(module_name))
ping: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@ping.head("/ping")

View File

@ -1,8 +1,9 @@
import os
from sanic import Blueprint
from sanic.response import text
robots: Blueprint = Blueprint("robots")
robots: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
@robots.get("/robots.txt")

View File

@ -5,19 +5,21 @@ Routes:
- GET /socials: Get ReVanced socials.
"""
import os
from sanic import Blueprint, Request
from sanic.response import JSONResponse, json
from sanic_ext import openapi
from api.models.socials import SocialsResponseModel
from config import social_links, api_version
from api.models.socials import ConnectionsResponseModel
from config import social_links
socials: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
socials: Blueprint = Blueprint("socials", version=api_version)
@socials.get("/socials")
@openapi.definition(
summary="Get ReVanced socials",
response=[SocialsResponseModel],
response=[ConnectionsResponseModel],
)
async def root(request: Request) -> JSONResponse:
"""

21
app.py
View File

@ -15,15 +15,14 @@ from api.utils.auth import configure_auth
import sentry_sdk
if os.environ.get("SENTRY_DSN"):
sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"],
enable_tracing=True,
traces_sample_rate=1.0,
debug=True,
)
else:
print("WARNING: Sentry DSN not set, not enabling Sentry")
# if os.environ.get("SENTRY_DSN"):
# sentry_sdk.init(
# dsn=os.environ["SENTRY_DSN"],
# enable_tracing=True,
# traces_sample_rate=1.0,
# )
# else:
# print("WARNING: Sentry DSN not set, not enabling Sentry")
REDIRECTS = {
"/": "/docs/swagger",
@ -50,7 +49,9 @@ configure_auth(app)
# sanic-limiter
configure_limiter(app)
app.blueprint(api)
for endpoint in api:
app.blueprint(api)
# https://sanic.dev/en/guide/how-to/static-redirects.html

View File

@ -1,7 +1,7 @@
import pytest
from sanic import Sanic
from api.models.socials import SocialsResponseModel
from api.models.socials import ConnectionsResponseModel
from config import api_version
@ -12,4 +12,4 @@ from config import api_version
async def test_socials(app: Sanic):
_, response = await app.asgi_client.get(f"/{api_version}/socials")
assert response.status == 200
assert SocialsResponseModel(**response.json)
assert ConnectionsResponseModel(**response.json)