diff --git a/api/__init__.py b/api/__init__.py index 4c54019..514e262 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -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) diff --git a/api/announcements.py b/api/announcements.py index 112d017..bcdc4c0 100644 --- a/api/announcements.py +++ b/api/announcements.py @@ -10,6 +10,7 @@ Routes: - DELETE /announcements/: 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") diff --git a/api/compat.py b/api/compat.py index c6f5255..993e02a 100644 --- a/api/compat.py +++ b/api/compat.py @@ -9,8 +9,7 @@ Routes: - GET /patches/: 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() diff --git a/api/connections.py b/api/connections.py new file mode 100644 index 0000000..0d1595f --- /dev/null +++ b/api/connections.py @@ -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) diff --git a/api/donations.py b/api/donations.py index 8e00f32..25ae875 100644 --- a/api/donations.py +++ b/api/donations.py @@ -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") diff --git a/api/github.py b/api/github.py index 0979d1d..aaf98bc 100644 --- a/api/github.py +++ b/api/github.py @@ -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() diff --git a/api/info.py b/api/info.py index 2fcacd7..60fbeac 100644 --- a/api/info.py +++ b/api/info.py @@ -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") diff --git a/api/login.py b/api/login.py index 652d6c0..939960b 100644 --- a/api/login.py +++ b/api/login.py @@ -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") diff --git a/api/models/socials.py b/api/models/socials.py index 45edad0..c62a57e 100644 --- a/api/models/socials.py +++ b/api/models/socials.py @@ -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. + """ diff --git a/api/ping.py b/api/ping.py index 274ead5..125365c 100644 --- a/api/ping.py +++ b/api/ping.py @@ -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") diff --git a/api/robots.py b/api/robots.py index 6d3a421..10460c3 100644 --- a/api/robots.py +++ b/api/robots.py @@ -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") diff --git a/api/socials.py b/api/socials.py index 996cd21..1924139 100644 --- a/api/socials.py +++ b/api/socials.py @@ -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: """ diff --git a/app.py b/app.py index db5f484..600c492 100644 --- a/app.py +++ b/app.py @@ -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 diff --git a/tests/test_socials.py b/tests/test_socials.py index b9bc6d8..d35b73a 100644 --- a/tests/test_socials.py +++ b/tests/test_socials.py @@ -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)