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 from sanic import Blueprint
import importlib import importlib
import pkgutil import pkgutil
from api.utils.versioning import get_version
blueprints = [] # Dynamically import all modules in the 'api' package, excluding subdirectories
for _, module_name, _ in pkgutil.iter_modules(["api"]): versioned_blueprints = {}
for finder, module_name, ispkg in pkgutil.iter_modules(["api"]):
if not ispkg:
# Import the module # Import the module
module = importlib.import_module(f"api.{module_name}") module = importlib.import_module(f"api.{module_name}")
# Add the module's blueprint to the list, if it exists # Add the module's blueprint to the versioned list, if it exists
if hasattr(module, module_name): if hasattr(module, module_name):
blueprints.append(getattr(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 # Create Blueprint groups for each version
api = Blueprint.group(*blueprints, url_prefix="/") 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. - DELETE /announcements/<announcement_id:int>: Delete an announcement.
""" """
import os
import datetime import datetime
from sanic import Blueprint, Request from sanic import Blueprint, Request
from sanic.response import JSONResponse, json from sanic.response import JSONResponse, json
@ -21,10 +22,8 @@ import sanic_beskar
from api.models.announcements import AnnouncementResponseModel from api.models.announcements import AnnouncementResponseModel
from api.utils.limiter import limiter from api.utils.limiter import limiter
from api.utils.versioning import get_version
module_name = "announcements" announcements: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
announcements: Blueprint = Blueprint(module_name, version=get_version(module_name))
@announcements.get("/announcements") @announcements.get("/announcements")

View File

@ -9,8 +9,7 @@ Routes:
- GET /patches/<tag:str>: Retrieve a list of patches for a given release tag. - GET /patches/<tag:str>: Retrieve a list of patches for a given release tag.
""" """
import os
from sanic import Blueprint, Request from sanic import Blueprint, Request
from sanic.response import JSONResponse, json from sanic.response import JSONResponse, json
from sanic_ext import openapi from sanic_ext import openapi
@ -20,7 +19,7 @@ from api.models.github import *
from api.models.compat import ToolsResponseModel, ContributorsResponseModel from api.models.compat import ToolsResponseModel, ContributorsResponseModel
from config import compat_repositories, owner from config import compat_repositories, owner
compat: Blueprint = Blueprint("old") compat: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
github_backend: Github = Github() 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. - GET /donations: Get ReVanced donation links and wallets.
""" """
import os
from sanic import Blueprint, Request from sanic import Blueprint, Request
from sanic.response import JSONResponse, json from sanic.response import JSONResponse, json
from sanic_ext import openapi from sanic_ext import openapi
from api.models.donations import DonationsResponseModel from api.models.donations import DonationsResponseModel
from config import wallets, links from config import wallets, links
from api.utils.versioning import get_version
module_name = "donations" donations: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
donations: Blueprint = Blueprint(module_name, version=get_version(module_name))
@donations.get("/donations") @donations.get("/donations")

View File

@ -10,6 +10,7 @@ Routes:
""" """
import os
from sanic import Blueprint, Request from sanic import Blueprint, Request
from sanic.response import JSONResponse, json from sanic.response import JSONResponse, json
from sanic_ext import openapi 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.backends.github import Github, GithubRepository
from api.models.github import * from api.models.github import *
from config import owner, default_repository from config import owner, default_repository
from api.utils.versioning import get_version
module_name = "github" github: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
github: Blueprint = Blueprint("github", version=get_version(module_name))
github_backend: Github = Github() github_backend: Github = Github()

View File

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

View File

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

View File

@ -11,7 +11,7 @@ class SocialFields(BaseModel):
preferred: bool preferred: bool
class SocialsResponseModel(BaseModel): class ConnectionsResponseModel(BaseModel):
""" """
A Pydantic BaseModel that represents a dictionary of social links. 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 A dictionary where the keys are the names of the social networks, and
the values are the links to the profiles or pages. 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. - HEAD /ping: Ping the API.
""" """
import os
from sanic import Blueprint, HTTPResponse, Request, response from sanic import Blueprint, HTTPResponse, Request, response
from sanic_ext import openapi from sanic_ext import openapi
from api.utils.versioning import get_version
module_name = "ping" ping: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
ping: Blueprint = Blueprint(module_name, version=get_version(module_name))
@ping.head("/ping") @ping.head("/ping")

View File

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

View File

@ -5,19 +5,21 @@ Routes:
- GET /socials: Get ReVanced socials. - GET /socials: Get ReVanced socials.
""" """
import os
from sanic import Blueprint, Request from sanic import Blueprint, Request
from sanic.response import JSONResponse, json from sanic.response import JSONResponse, json
from sanic_ext import openapi from sanic_ext import openapi
from api.models.socials import SocialsResponseModel from api.models.socials import ConnectionsResponseModel
from config import social_links, api_version from config import social_links
socials: Blueprint = Blueprint(os.path.basename(__file__).strip(".py"))
socials: Blueprint = Blueprint("socials", version=api_version)
@socials.get("/socials") @socials.get("/socials")
@openapi.definition( @openapi.definition(
summary="Get ReVanced socials", summary="Get ReVanced socials",
response=[SocialsResponseModel], response=[ConnectionsResponseModel],
) )
async def root(request: Request) -> JSONResponse: 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 import sentry_sdk
if os.environ.get("SENTRY_DSN"): # if os.environ.get("SENTRY_DSN"):
sentry_sdk.init( # sentry_sdk.init(
dsn=os.environ["SENTRY_DSN"], # dsn=os.environ["SENTRY_DSN"],
enable_tracing=True, # enable_tracing=True,
traces_sample_rate=1.0, # traces_sample_rate=1.0,
debug=True, # )
) # else:
else: # print("WARNING: Sentry DSN not set, not enabling Sentry")
print("WARNING: Sentry DSN not set, not enabling Sentry")
REDIRECTS = { REDIRECTS = {
"/": "/docs/swagger", "/": "/docs/swagger",
@ -50,7 +49,9 @@ configure_auth(app)
# sanic-limiter # sanic-limiter
configure_limiter(app) configure_limiter(app)
app.blueprint(api)
for endpoint in api:
app.blueprint(api)
# https://sanic.dev/en/guide/how-to/static-redirects.html # https://sanic.dev/en/guide/how-to/static-redirects.html

View File

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