Skip to content

Commit 1f0e5d5

Browse files
committed
feat(subscription): enhance user subscription /info endpoint to include dynamic response headers
1 parent f7cdea0 commit 1f0e5d5

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

app/operation/subscription.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ def create_response_headers(user: UsersResponseWithInbounds, request_url: str, s
9494
"announce-url": sub_settings.announce_url,
9595
}
9696

97+
@staticmethod
98+
def create_info_response_headers(user: UsersResponseWithInbounds, sub_settings: SubSettings) -> dict:
99+
"""Create response headers for /info endpoint with only support-url, announce, and announce-url."""
100+
# Prefer admin's support_url over subscription settings
101+
support_url = (getattr(user.admin, "support_url", None) if user.admin else None) or sub_settings.support_url
102+
103+
headers = {
104+
"support-url": support_url,
105+
"announce": encode_title(sub_settings.announce),
106+
"announce-url": sub_settings.announce_url,
107+
}
108+
109+
# Only include headers that have values
110+
return {k: v for k, v in headers.items() if v}
111+
97112
async def fetch_config(self, user: UsersResponseWithInbounds, client_type: ConfigFormat) -> tuple[str, str]:
98113
# Get client configuration
99114
config = client_config.get(client_type)
@@ -171,15 +186,24 @@ async def user_subscription_with_client_type(
171186
# Create response headers
172187
return Response(content=conf, media_type=media_type, headers=response_headers)
173188

174-
async def user_subscription_info(self, db: AsyncSession, token: str) -> SubscriptionUserResponse:
189+
async def user_subscription_info(
190+
self, db: AsyncSession, token: str, request_url: str = ""
191+
) -> tuple[SubscriptionUserResponse, dict]:
175192
"""Retrieves detailed information about the user's subscription."""
176-
return await self.get_validated_sub(db, token=token)
193+
sub_settings: SubSettings = await subscription_settings()
194+
db_user = await self.get_validated_sub(db, token=token)
195+
user = await self.validated_user(db_user)
196+
197+
response_headers = self.create_info_response_headers(user, sub_settings)
198+
user_response = SubscriptionUserResponse.model_validate(db_user.__dict__)
199+
200+
return user_response, response_headers
177201

178202
async def user_subscription_apps(self, db: AsyncSession, token: str, request_url: str) -> list[Application]:
179203
"""
180204
Get available applications for user's subscription.
181205
"""
182-
await self.user_subscription_info(db, token)
206+
_, _ = await self.user_subscription_info(db, token, request_url)
183207
sub_settings: SubSettings = await subscription_settings()
184208
return self._make_apps_import_urls(request_url, sub_settings.applications)
185209

app/routers/subscription.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime as dt
22

33
from fastapi import APIRouter, Depends, Header, Query, Request
4+
from fastapi.responses import JSONResponse
45

56
from app.db import AsyncSession, get_db
67
from app.models.settings import Application, ConfigFormat
@@ -33,9 +34,14 @@ async def user_subscription(
3334

3435

3536
@router.get("/{token}/info", response_model=SubscriptionUserResponse)
36-
async def user_subscription_info(token: str, db: AsyncSession = Depends(get_db)):
37+
async def user_subscription_info(
38+
request: Request, token: str, db: AsyncSession = Depends(get_db)
39+
):
3740
"""Retrieves detailed information about the user's subscription."""
38-
return await subscription_operator.user_subscription_info(db, token=token)
41+
user_data, response_headers = await subscription_operator.user_subscription_info(
42+
db, token=token, request_url=str(request.url)
43+
)
44+
return JSONResponse(content=user_data.model_dump(), headers=response_headers)
3945

4046

4147
@router.get("/{token}/apps", response_model=list[Application])

0 commit comments

Comments
 (0)