Skip to content

Commit 14c9adf

Browse files
authored
Merge pull request #120 from ImMin5/master
Add new feature excel download
2 parents 5bb5109 + 6b845c4 commit 14c9adf

File tree

10 files changed

+610
-55
lines changed

10 files changed

+610
-55
lines changed

pkg/pip_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ spaceone-api
22
typing-inspect
33
python-multipart
44
PyJWT
5+
openpyxl

src/cloudforet/console_api_v2/conf/global_conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"default": {},
7171
"local": {
7272
"backend": "spaceone.core.cache.local_cache.LocalCache",
73-
"max_size": 128,
73+
"max_size": 1024,
7474
"ttl": 300,
7575
},
7676
}

src/cloudforet/console_api_v2/conf/router_conf.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
"tags": ["console-api > extension > agent"],
2121
},
2222
},
23+
{
24+
"router_path": "cloudforet.console_api_v2.interface.rest.extension.excel:router",
25+
"router_options": {
26+
"prefix": "/console-api/extension/excel",
27+
"tags": ["console-api > extension > excel"],
28+
},
29+
},
2330
{
2431
"router_path": "cloudforet.console_api_v2.interface.rest.swagger:router",
2532
},
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import json
2+
import logging
3+
import inspect
4+
from fastapi import APIRouter, Depends, Request, Query
5+
from fastapi.concurrency import run_in_threadpool
6+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
7+
from starlette.responses import StreamingResponse
8+
9+
from spaceone.core import cache
10+
from spaceone.core.error import ERROR_REQUIRED_PARAMETER, ERROR_CACHE_CONFIGURATION
11+
from spaceone.core.fastapi.api import BaseAPI, exception_handler
12+
13+
from cloudforet.console_api_v2.service.excel_service import ExcelService
14+
15+
_LOGGER = logging.getLogger(__name__)
16+
_AUTH_SCHEME = HTTPBearer(auto_error=False)
17+
18+
router = APIRouter(include_in_schema=True)
19+
20+
SERVICE = "console-api"
21+
RESOURCE = "Excel"
22+
23+
24+
@router.post("/export")
25+
@exception_handler
26+
async def export(
27+
request: Request, token: HTTPAuthorizationCredentials = Depends(_AUTH_SCHEME)
28+
) -> dict:
29+
base_api = BaseAPI()
30+
base_api.service = SERVICE
31+
verb = inspect.currentframe().f_code.co_name
32+
33+
if token:
34+
params, metadata = await base_api.parse_request(
35+
request, token=token.credentials, resource=RESOURCE, verb=verb
36+
)
37+
else:
38+
params, metadata = await base_api.parse_request(
39+
request, None, resource=RESOURCE, verb=verb
40+
)
41+
42+
excel_service = ExcelService(metadata)
43+
44+
response = await run_in_threadpool(excel_service.export, params)
45+
return response
46+
47+
48+
@router.get("/download")
49+
@exception_handler
50+
async def download(key: str = Query(default=None)) -> StreamingResponse:
51+
base_api = BaseAPI()
52+
base_api.service = SERVICE
53+
54+
if not key:
55+
raise ERROR_REQUIRED_PARAMETER(key="key")
56+
57+
if not cache.is_set(alias="local"):
58+
raise ERROR_CACHE_CONFIGURATION(alias="local")
59+
60+
json_str = cache.get(key=f"console-api:excel:{key}", alias="local")
61+
json_obj = json.loads(json_str)
62+
63+
params = json_obj["request_body"]
64+
metadata = json_obj["auth_info"]
65+
66+
excel_service = ExcelService(metadata)
67+
response = await run_in_threadpool(excel_service.download, params)
68+
return response

src/cloudforet/console_api_v2/manager/cloudforet_manager.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from typing import Tuple, Generator
23

34
from spaceone.core.connector.space_connector import SpaceConnector
45
from spaceone.core.manager import BaseManager
@@ -10,16 +11,58 @@
1011
class CloudforetManager(BaseManager):
1112
def __init__(self, *args, **kwargs):
1213
super().__init__(*args, **kwargs)
14+
self._page_size = 1000
1315

1416
def dispatch_api(self, grpc_method: str, params: dict, token: str = None):
1517
service, resource, verb = self._parse_grpc_method(grpc_method)
1618
space_connector = SpaceConnector(service=service, token=token)
1719
return space_connector.dispatch(f"{resource}.{verb}", params)
1820

21+
def paginate_api(
22+
self, grpc_method: str, params: dict, token: str = None, limit: int = 1000
23+
) -> Generator[dict, None, None]:
24+
start = 1
25+
paged_params = params.copy()
26+
while True:
27+
query = paged_params.get("query", {})
28+
page_info = query.get("page", {})
29+
page_info["start"] = start
30+
page_info["limit"] = max(page_info.get("limit", self._page_size), limit)
31+
32+
paged_params["query"].update({"page": page_info})
33+
34+
response = self.dispatch_api(grpc_method, paged_params, token)
35+
results = response.get("results", [])
36+
yield response
37+
38+
if len(results) < page_info["limit"]:
39+
break
40+
41+
start += page_info["limit"]
42+
1943
@staticmethod
20-
def _parse_grpc_method(grpc_method):
44+
def _parse_grpc_method(grpc_method: str) -> Tuple[str, str, str]:
2145
try:
2246
service, resource, verb = grpc_method.split(".")
2347
return service, resource, verb
2448
except Exception as e:
2549
raise ERROR_PARSE_GRPC_METHOD(grpc_method=grpc_method, reason=e)
50+
51+
@classmethod
52+
def convert_grpc_method_from_url(cls, url: str) -> str:
53+
try:
54+
parts = url.strip("/").split("/")
55+
print(parts)
56+
57+
if len(parts) != 3:
58+
raise ValueError("Path must have at least two segments")
59+
60+
service = parts[0].replace("-", "_") # snake_case
61+
r_source = "".join(
62+
word.capitalize() for word in parts[1].split("-")
63+
) # PascalCase
64+
verb = parts[2].replace("-", "_")
65+
66+
return ".".join([service, r_source, verb])
67+
except Exception as e:
68+
raise ERROR_PARSE_GRPC_METHOD(grpc_method=url, reason=e)

src/cloudforet/console_api_v2/model/auth/request.py

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import Union
2+
from pydantic import BaseModel
3+
4+
__all__ = ["ExcelExportRequest"]
5+
6+
7+
class ExcelSource(BaseModel):
8+
url: Union[str, None] = None
9+
param: Union[dict, None] = None
10+
data: Union[dict, list, None] = None
11+
12+
13+
class ExcelTemplate(BaseModel):
14+
options: Union[dict, None] = None
15+
fields: Union[list, None] = None
16+
17+
18+
class ExcelExportRequest(BaseModel):
19+
source: ExcelSource
20+
template: ExcelTemplate
21+
22+
23+
class ExcelDownloadRequest(BaseModel):
24+
key: str

src/cloudforet/console_api_v2/model/resource.py

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)