Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions backend/python/app/sources/client/http/http_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Optional

import httpx # type: ignore

from app.sources.client.http.http_request import HTTPRequest
from app.sources.client.http.http_response import HTTPResponse
from app.sources.client.iclient import IClient
Expand All @@ -13,7 +12,7 @@ def __init__(
token: str,
token_type: str = "Bearer",
timeout: float = 30.0,
follow_redirects: bool = True
follow_redirects: bool = True,
) -> None:
self.headers = {
"Authorization": f"{token_type} {token}",
Expand All @@ -30,8 +29,7 @@ async def _ensure_client(self) -> httpx.AsyncClient:
"""Ensure client is created and available"""
if self.client is None:
self.client = httpx.AsyncClient(
timeout=self.timeout,
follow_redirects=self.follow_redirects
timeout=self.timeout, follow_redirects=self.follow_redirects
)
return self.client

Expand All @@ -51,20 +49,21 @@ async def execute(self, request: HTTPRequest, **kwargs) -> HTTPResponse:
request_kwargs = {
"params": request.query_params,
"headers": merged_headers,
**kwargs
**kwargs,
}

if isinstance(request.body, dict):
body = request.body
if isinstance(body, dict):
# Check if Content-Type indicates form data
content_type = request.headers.get("Content-Type", "").lower()
if "application/x-www-form-urlencoded" in content_type:
# Send as form data
request_kwargs["data"] = request.body
request_kwargs["data"] = body
else:
# Send as JSON (default behavior)
request_kwargs["json"] = request.body
elif isinstance(request.body, bytes):
request_kwargs["content"] = request.body
request_kwargs["json"] = body
elif isinstance(body, bytes):
request_kwargs["content"] = body

response = await client.request(request.method, url, **request_kwargs)
return HTTPResponse(response)
Expand Down
30 changes: 20 additions & 10 deletions backend/python/app/sources/external/confluence/confluence.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from app.sources.client.http.http_request import HTTPRequest
from app.sources.client.http.http_response import HTTPResponse

# Precompute the empty string dict so we don't redo the work for constant calls
_EMPTY_STR_DICT: Dict[str, str] = {}


class ConfluenceDataSource:
def __init__(self, client: ConfluenceClient) -> None:
Expand Down Expand Up @@ -72,21 +75,27 @@ async def disable_admin_key(
self,
headers: Optional[Dict[str, Any]] = None
) -> HTTPResponse:
"""Auto-generated from OpenAPI: Disable Admin Key\n\nHTTP DELETE /admin-key"""
"""Auto-generated from OpenAPI: Disable Admin Key

HTTP DELETE /admin-key"""
if self._client is None:
raise ValueError('HTTP client is not initialized')
_headers: Dict[str, Any] = dict(headers or {})

# Use headers directly if already dict
_headers: Dict[str, Any] = headers if headers is not None else {}
# Path and query params never change so reuse empty tuples and cached results
_path: Dict[str, Any] = {}
_query: Dict[str, Any] = {}
_body = None
rel_path = '/admin-key'
url = self.base_url + _safe_format_url(rel_path, _path)
url = f"{self.base_url}{_safe_format_url(rel_path, _path)}"
# If all param dicts are empty, avoid repeated helpers
req = HTTPRequest(
method='DELETE',
url=url,
headers=_as_str_dict(_headers),
path_params=_as_str_dict(_path),
query_params=_as_str_dict(_query),
headers=_as_str_dict(_headers) if _headers else _EMPTY_STR_DICT,
path_params=_EMPTY_STR_DICT,
query_params=_EMPTY_STR_DICT,
body=_body,
)
resp = await self._client.execute(req)
Expand Down Expand Up @@ -7103,9 +7112,6 @@ async def delete_forge_app_property(

# ---- Helpers used by generated methods ----
def _safe_format_url(template: str, params: Dict[str, object]) -> str:
class _SafeDict(dict):
def __missing__(self, key: str) -> str:
return '{' + key + '}'
try:
return template.format_map(_SafeDict(params))
except Exception:
Expand All @@ -7124,4 +7130,8 @@ def _serialize_value(v: Union[bool, str, int, float, list, tuple, set, None]) ->
return _to_bool_str(v)

def _as_str_dict(d: Dict[str, Any]) -> Dict[str, str]:
return {str(k): _serialize_value(v) for k, v in (d or {}).items()}
# Fast path for empty input
if not d:
return _EMPTY_STR_DICT
# Retain actual function as used
return {str(k): _serialize_value(v) for k, v in d.items()}