cmdbox 0.5.1.2__py3-none-any.whl → 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cmdbox might be problematic. Click here for more details.
- cmdbox/app/app.py +4 -2
- cmdbox/app/auth/signin.py +633 -631
- cmdbox/app/client.py +10 -10
- cmdbox/app/common.py +50 -6
- cmdbox/app/commons/convert.py +9 -0
- cmdbox/app/commons/module.py +113 -113
- cmdbox/app/commons/redis_client.py +40 -29
- cmdbox/app/edge.py +4 -4
- cmdbox/app/features/cli/audit_base.py +135 -0
- cmdbox/app/features/cli/cmdbox_audit_createdb.py +224 -0
- cmdbox/app/features/cli/cmdbox_audit_delete.py +299 -0
- cmdbox/app/features/cli/cmdbox_audit_search.py +350 -0
- cmdbox/app/features/cli/cmdbox_audit_write.py +240 -0
- cmdbox/app/features/cli/cmdbox_client_file_copy.py +207 -207
- cmdbox/app/features/cli/cmdbox_client_file_download.py +207 -207
- cmdbox/app/features/cli/cmdbox_client_file_list.py +193 -193
- cmdbox/app/features/cli/cmdbox_client_file_mkdir.py +191 -191
- cmdbox/app/features/cli/cmdbox_client_file_move.py +199 -199
- cmdbox/app/features/cli/cmdbox_client_file_remove.py +190 -190
- cmdbox/app/features/cli/cmdbox_client_file_rmdir.py +190 -190
- cmdbox/app/features/cli/cmdbox_client_file_upload.py +212 -212
- cmdbox/app/features/cli/cmdbox_client_server_info.py +166 -166
- cmdbox/app/features/cli/cmdbox_server_list.py +88 -88
- cmdbox/app/features/cli/cmdbox_server_stop.py +138 -138
- cmdbox/app/features/web/cmdbox_web_del_cmd.py +2 -0
- cmdbox/app/features/web/cmdbox_web_del_pipe.py +1 -0
- cmdbox/app/features/web/cmdbox_web_do_signin.py +12 -2
- cmdbox/app/features/web/cmdbox_web_do_signout.py +1 -0
- cmdbox/app/features/web/cmdbox_web_exec_cmd.py +25 -1
- cmdbox/app/features/web/cmdbox_web_exec_pipe.py +1 -0
- cmdbox/app/features/web/cmdbox_web_filer download.py +43 -42
- cmdbox/app/features/web/cmdbox_web_filer.py +1 -0
- cmdbox/app/features/web/cmdbox_web_filer_upload.py +65 -64
- cmdbox/app/features/web/cmdbox_web_gui.py +166 -165
- cmdbox/app/features/web/cmdbox_web_load_pin.py +43 -43
- cmdbox/app/features/web/cmdbox_web_raw_pipe.py +87 -87
- cmdbox/app/features/web/cmdbox_web_save_cmd.py +1 -0
- cmdbox/app/features/web/cmdbox_web_save_pin.py +42 -42
- cmdbox/app/features/web/cmdbox_web_save_pipe.py +1 -0
- cmdbox/app/features/web/cmdbox_web_users.py +12 -0
- cmdbox/app/options.py +767 -601
- cmdbox/extensions/features.yml +20 -0
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_client_time.py +82 -82
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +145 -145
- cmdbox/licenses/{LICENSE.Sphinx.8.1.3(BSD License).txt → LICENSE.Sphinx.8.2.3(UNKNOWN).txt} +1 -1
- cmdbox/licenses/{LICENSE.babel.2.16.0(BSD License).txt → LICENSE.babel.2.17.0(BSD License).txt } +1 -1
- cmdbox/licenses/{LICENSE.pkginfo.1.10.0(MIT License).txt → LICENSE.charset-normalizer.3.4.1(MIT License).txt } +1 -1
- cmdbox/licenses/LICENSE.gunicorn.23.0.0(MIT License).txt +23 -0
- cmdbox/licenses/LICENSE.importlib_metadata.8.6.1(Apache Software License).txt +202 -0
- cmdbox/licenses/LICENSE.nh3.0.2.21(MIT).txt +21 -0
- cmdbox/licenses/{LICENSE.pillow.11.0.0(CMU License (MIT-CMU)).txt → LICENSE.pillow.11.1.0(CMU License (MIT-CMU)).txt } +27 -40
- cmdbox/licenses/LICENSE.plyer.2.1.0(MIT License).txt +19 -0
- cmdbox/licenses/LICENSE.prompt_toolkit.3.0.50(BSD License).txt +27 -0
- cmdbox/licenses/LICENSE.psycopg-binary.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +165 -0
- cmdbox/licenses/LICENSE.psycopg-pool.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +165 -0
- cmdbox/licenses/LICENSE.psycopg.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +165 -0
- cmdbox/licenses/LICENSE.pycryptodome.3.22.0(BSD License; Public Domain).txt +61 -0
- cmdbox/licenses/LICENSE.pystray.0.19.5(GNU Lesser General Public License v3 (LGPLv3)).txt +674 -0
- cmdbox/licenses/LICENSE.questionary.2.1.0(MIT License).txt +19 -0
- cmdbox/licenses/LICENSE.roman-numerals-py.3.1.0(CC0 1.0 Universal (CC0 1.0) Public Domain Dedication; Zero-Clause BSD (0BSD)).txt +146 -0
- cmdbox/licenses/{LICENSE.six.1.16.0(MIT License).txt → LICENSE.six.1.17.0(MIT License).txt } +1 -1
- cmdbox/licenses/{LICENSE.charset-normalizer.3.4.0(MIT License).txt → LICENSE.typing-inspection.0.4.0(MIT License).txt } +2 -2
- cmdbox/licenses/LICENSE.tzdata.2025.2(Apache Software License).txt +15 -0
- cmdbox/licenses/files.txt +48 -36
- cmdbox/logconf_audit.yml +30 -0
- cmdbox/logconf_cmdbox.yml +30 -0
- cmdbox/version.py +2 -2
- cmdbox/web/assets/cmdbox/color_mode.css +516 -0
- cmdbox/web/assets/cmdbox/common.js +19 -0
- cmdbox/web/assets/cmdbox/list_cmd.js +9 -10
- cmdbox/web/assets/cmdbox/main.js +2 -2
- cmdbox/web/assets/cmdbox/result.js +2 -2
- cmdbox/web/assets/cmdbox/signin.js +2 -2
- cmdbox/web/assets/cmdbox/users.js +2 -3
- cmdbox/web/assets/cmdbox/view_result.js +1 -1
- cmdbox/web/assets/filer/main.js +2 -2
- cmdbox/web/filer.html +16 -2
- cmdbox/web/gui.html +15 -1
- cmdbox/web/result.html +15 -1
- cmdbox/web/signin.html +35 -14
- cmdbox/web/users.html +15 -1
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/METADATA +25 -5
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/RECORD +116 -96
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/entry_points.txt +0 -1
- cmdbox/licenses/LICENSE.nh3.0.2.18(MIT).txt +0 -1
- /cmdbox/licenses/{LICENSE.Jinja2.3.1.4(BSD License).txt → LICENSE.Jinja2.3.1.6(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.Pygments.2.18.0(BSD License).txt → LICENSE.Pygments.2.19.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.anyio.4.6.2.post1(MIT License).txt → LICENSE.anyio.4.9.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.argcomplete.3.5.1(Apache Software License).txt → LICENSE.argcomplete.3.6.1(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.certifi.2024.8.30(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE.certifi.2025.1.31(Mozilla Public License 2.0 (MPL 2.0)).txt} +0 -0
- /cmdbox/licenses/{LICENSE.click.8.1.7(BSD License).txt → LICENSE.click.8.1.8(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.cryptography.43.0.3(Apache Software License; BSD License).txt → LICENSE.cryptography.44.0.2(Apache Software License; BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.fastapi.0.115.5(MIT License).txt → LICENSE.fastapi.0.115.12(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.importlib_metadata.8.5.0(Apache Software License).txt → LICENSE.id.1.5.0(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.keyring.25.5.0(MIT License).txt → LICENSE.keyring.25.6.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.more-itertools.10.5.0(MIT License).txt → LICENSE.more-itertools.10.6.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.numpy.2.1.3(BSD License).txt → LICENSE.numpy.2.2.4(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.prettytable.3.12.0(BSD License).txt → LICENSE.prettytable.3.16.0(UNKNOWN).txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic.2.10.2(MIT License).txt → LICENSE.pydantic.2.11.1(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic_core.2.27.1(MIT License).txt → LICENSE.pydantic_core.2.33.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-dotenv.1.0.1(BSD License).txt → LICENSE.python-dotenv.1.1.0(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-multipart.0.0.17(Apache Software License).txt → LICENSE.python-multipart.0.0.20(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.redis.5.2.0(MIT License).txt → LICENSE.redis.5.2.1(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.rich.13.9.4(MIT License).txt → LICENSE.rich.14.0.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinx-intl.2.3.0(BSD License).txt → LICENSE.sphinx-intl.2.3.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.starlette.0.41.3(BSD License).txt → LICENSE.starlette.0.46.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.tomli.2.1.0(MIT License).txt → LICENSE.tomli.2.2.1(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.twine.5.1.1(Apache Software License).txt → LICENSE.twine.6.1.0(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.typing_extensions.4.12.2(Python Software Foundation License).txt → LICENSE.typing_extensions.4.13.0(UNKNOWN).txt} +0 -0
- /cmdbox/licenses/{LICENSE.urllib3.2.2.3(MIT License).txt → LICENSE.urllib3.2.3.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.uvicorn.0.32.1(BSD License).txt → LICENSE.uvicorn.0.34.0(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.watchfiles.1.0.0(MIT License).txt → LICENSE.watchfiles.1.0.4(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.websockets.14.1(BSD License).txt → LICENSE.websockets.15.0.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.zope.interface.7.1.1(Zope Public License).txt → LICENSE.zope.interface.7.2(Zope Public License).txt} +0 -0
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/LICENSE +0 -0
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/WHEEL +0 -0
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/top_level.txt +0 -0
|
@@ -1,64 +1,65 @@
|
|
|
1
|
-
from cmdbox.app.features.web import cmdbox_web_exec_cmd
|
|
2
|
-
from cmdbox.app.web import Web
|
|
3
|
-
from fastapi import FastAPI, Request, Response, HTTPException
|
|
4
|
-
from fastapi.responses import PlainTextResponse
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from starlette.datastructures import UploadFile
|
|
7
|
-
import tempfile
|
|
8
|
-
import shutil
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class FilerUpload(cmdbox_web_exec_cmd.ExecCmd):
|
|
12
|
-
def route(self, web:Web, app:FastAPI) -> None:
|
|
13
|
-
"""
|
|
14
|
-
webモードのルーティングを設定します
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
web (Web): Webオブジェクト
|
|
18
|
-
app (FastAPI): FastAPIオブジェクト
|
|
19
|
-
"""
|
|
20
|
-
@app.post('/filer/upload', response_class=PlainTextResponse)
|
|
21
|
-
async def filer_upload(req:Request, res:Response):
|
|
22
|
-
signin = web.signin.check_signin(req, res)
|
|
23
|
-
if signin is not None:
|
|
24
|
-
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
25
|
-
return await self.filer_upload(web, req, res)
|
|
26
|
-
|
|
27
|
-
async def filer_upload(self, web:Web, req:Request, res:Response) -> str:
|
|
28
|
-
"""
|
|
29
|
-
ファイルをアップロードする
|
|
30
|
-
|
|
31
|
-
Args:
|
|
32
|
-
web (Web): Webオブジェクト
|
|
33
|
-
req (Request): リクエスト
|
|
34
|
-
res (Response): レスポンス
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
str: 結果
|
|
38
|
-
"""
|
|
39
|
-
q = req.query_params
|
|
40
|
-
svpath = q['svpath']
|
|
41
|
-
web.logger.info(f"filer_upload: svpath={svpath}")
|
|
42
|
-
opt = dict(mode='client', cmd='file_upload',
|
|
43
|
-
host=q['host'], port=q['port'], password=q['password'], svname=q['svname'],
|
|
44
|
-
scope=q["scope"], client_data=q['client_data'], orverwrite=('orverwrite' in q))
|
|
45
|
-
form = await req.form()
|
|
46
|
-
with tempfile.TemporaryDirectory() as tmpdir:
|
|
47
|
-
for _, fv in form.multi_items():
|
|
48
|
-
if not isinstance(fv, UploadFile): continue
|
|
49
|
-
raw_filename = fv.filename.replace('\\','/').replace('//','/')
|
|
50
|
-
raw_filename = raw_filename if not raw_filename.startswith('/') else raw_filename[1:]
|
|
51
|
-
upload_file:Path = Path(tmpdir) / raw_filename
|
|
52
|
-
if not upload_file.parent.exists():
|
|
53
|
-
upload_file.parent.mkdir(parents=True)
|
|
54
|
-
opt['svpath'] = str(svpath / Path(raw_filename).parent)
|
|
55
|
-
opt['upload_file'] = str(upload_file).replace('"','')
|
|
56
|
-
opt['capture_stdout'] = True
|
|
57
|
-
shutil.copyfileobj(fv.file, Path(opt['upload_file']).open('wb'))
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
1
|
+
from cmdbox.app.features.web import cmdbox_web_exec_cmd
|
|
2
|
+
from cmdbox.app.web import Web
|
|
3
|
+
from fastapi import FastAPI, Request, Response, HTTPException
|
|
4
|
+
from fastapi.responses import PlainTextResponse
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from starlette.datastructures import UploadFile
|
|
7
|
+
import tempfile
|
|
8
|
+
import shutil
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FilerUpload(cmdbox_web_exec_cmd.ExecCmd):
|
|
12
|
+
def route(self, web:Web, app:FastAPI) -> None:
|
|
13
|
+
"""
|
|
14
|
+
webモードのルーティングを設定します
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
web (Web): Webオブジェクト
|
|
18
|
+
app (FastAPI): FastAPIオブジェクト
|
|
19
|
+
"""
|
|
20
|
+
@app.post('/filer/upload', response_class=PlainTextResponse)
|
|
21
|
+
async def filer_upload(req:Request, res:Response):
|
|
22
|
+
signin = web.signin.check_signin(req, res)
|
|
23
|
+
if signin is not None:
|
|
24
|
+
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
25
|
+
return await self.filer_upload(web, req, res)
|
|
26
|
+
|
|
27
|
+
async def filer_upload(self, web:Web, req:Request, res:Response) -> str:
|
|
28
|
+
"""
|
|
29
|
+
ファイルをアップロードする
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
web (Web): Webオブジェクト
|
|
33
|
+
req (Request): リクエスト
|
|
34
|
+
res (Response): レスポンス
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
str: 結果
|
|
38
|
+
"""
|
|
39
|
+
q = req.query_params
|
|
40
|
+
svpath = q['svpath']
|
|
41
|
+
web.logger.info(f"filer_upload: svpath={svpath}")
|
|
42
|
+
opt = dict(mode='client', cmd='file_upload',
|
|
43
|
+
host=q['host'], port=q['port'], password=q['password'], svname=q['svname'],
|
|
44
|
+
scope=q["scope"], client_data=q['client_data'], orverwrite=('orverwrite' in q))
|
|
45
|
+
form = await req.form()
|
|
46
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
47
|
+
for _, fv in form.multi_items():
|
|
48
|
+
if not isinstance(fv, UploadFile): continue
|
|
49
|
+
raw_filename = fv.filename.replace('\\','/').replace('//','/')
|
|
50
|
+
raw_filename = raw_filename if not raw_filename.startswith('/') else raw_filename[1:]
|
|
51
|
+
upload_file:Path = Path(tmpdir) / raw_filename
|
|
52
|
+
if not upload_file.parent.exists():
|
|
53
|
+
upload_file.parent.mkdir(parents=True)
|
|
54
|
+
opt['svpath'] = str(svpath / Path(raw_filename).parent)
|
|
55
|
+
opt['upload_file'] = str(upload_file).replace('"','')
|
|
56
|
+
opt['capture_stdout'] = True
|
|
57
|
+
shutil.copyfileobj(fv.file, Path(opt['upload_file']).open('wb'))
|
|
58
|
+
web.options.audit_exec(req, res, web)
|
|
59
|
+
ret = self.exec_cmd(req, res, web, "file_upload", opt, nothread=True)
|
|
60
|
+
if type(ret) is dict and 'success' not in ret:
|
|
61
|
+
return str(ret)
|
|
62
|
+
if type(ret) is list and (len(ret) == 0 or 'success' not in ret[0]):
|
|
63
|
+
return str(ret)
|
|
64
|
+
return 'upload success'
|
|
65
|
+
#return f'upload {upload.filename}'
|
|
@@ -1,165 +1,166 @@
|
|
|
1
|
-
from cmdbox import version
|
|
2
|
-
from cmdbox.app import common, feature
|
|
3
|
-
from cmdbox.app.web import Web
|
|
4
|
-
from fastapi import FastAPI, Request, Response, HTTPException
|
|
5
|
-
from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse
|
|
6
|
-
from typing import Dict, Any
|
|
7
|
-
import logging
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Gui(feature.WebFeature):
|
|
11
|
-
def __init__(self, appcls, ver):
|
|
12
|
-
super().__init__(appcls=appcls, ver=ver)
|
|
13
|
-
self.version_info = [dict(tabid='versions_cmdbox', title=version.__appid__,
|
|
14
|
-
thisapp=True if version.__appid__ == ver.__appid__ else False,
|
|
15
|
-
icon=f'assets/cmdbox/icon.png', url='versions_cmdbox')]
|
|
16
|
-
|
|
17
|
-
def route(self, web:Web, app:FastAPI) -> None:
|
|
18
|
-
"""
|
|
19
|
-
webモードのルーティングを設定します
|
|
20
|
-
|
|
21
|
-
Args:
|
|
22
|
-
web (Web): Webオブジェクト
|
|
23
|
-
app (FastAPI): FastAPIオブジェクト
|
|
24
|
-
"""
|
|
25
|
-
if web.gui_html is not None:
|
|
26
|
-
if not web.gui_html.is_file():
|
|
27
|
-
raise FileNotFoundError(f'gui_html is not found. ({web.gui_html})')
|
|
28
|
-
with open(web.gui_html, 'r', encoding='utf-8') as f:
|
|
29
|
-
web.gui_html_data = f.read()
|
|
30
|
-
|
|
31
|
-
@app.get('/', response_class=HTMLResponse)
|
|
32
|
-
async def index(req:Request, res:Response):
|
|
33
|
-
return RedirectResponse(url='/gui')
|
|
34
|
-
|
|
35
|
-
@app.get('/gui', response_class=HTMLResponse)
|
|
36
|
-
@app.post('/gui', response_class=HTMLResponse)
|
|
37
|
-
async def gui(req:Request, res:Response):
|
|
38
|
-
signin = web.signin.check_signin(req, res)
|
|
39
|
-
if signin is not None:
|
|
40
|
-
return signin
|
|
41
|
-
res.headers['Access-Control-Allow-Origin'] = '*'
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@app.get('/gui/appid', response_class=PlainTextResponse)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
1
|
+
from cmdbox import version
|
|
2
|
+
from cmdbox.app import common, feature
|
|
3
|
+
from cmdbox.app.web import Web
|
|
4
|
+
from fastapi import FastAPI, Request, Response, HTTPException
|
|
5
|
+
from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse
|
|
6
|
+
from typing import Dict, Any
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Gui(feature.WebFeature):
|
|
11
|
+
def __init__(self, appcls, ver):
|
|
12
|
+
super().__init__(appcls=appcls, ver=ver)
|
|
13
|
+
self.version_info = [dict(tabid='versions_cmdbox', title=version.__appid__,
|
|
14
|
+
thisapp=True if version.__appid__ == ver.__appid__ else False,
|
|
15
|
+
icon=f'assets/cmdbox/icon.png', url='versions_cmdbox')]
|
|
16
|
+
|
|
17
|
+
def route(self, web:Web, app:FastAPI) -> None:
|
|
18
|
+
"""
|
|
19
|
+
webモードのルーティングを設定します
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
web (Web): Webオブジェクト
|
|
23
|
+
app (FastAPI): FastAPIオブジェクト
|
|
24
|
+
"""
|
|
25
|
+
if web.gui_html is not None:
|
|
26
|
+
if not web.gui_html.is_file():
|
|
27
|
+
raise FileNotFoundError(f'gui_html is not found. ({web.gui_html})')
|
|
28
|
+
with open(web.gui_html, 'r', encoding='utf-8') as f:
|
|
29
|
+
web.gui_html_data = f.read()
|
|
30
|
+
|
|
31
|
+
@app.get('/', response_class=HTMLResponse)
|
|
32
|
+
async def index(req:Request, res:Response):
|
|
33
|
+
return RedirectResponse(url='/gui')
|
|
34
|
+
|
|
35
|
+
@app.get('/gui', response_class=HTMLResponse)
|
|
36
|
+
@app.post('/gui', response_class=HTMLResponse)
|
|
37
|
+
async def gui(req:Request, res:Response):
|
|
38
|
+
signin = web.signin.check_signin(req, res)
|
|
39
|
+
if signin is not None:
|
|
40
|
+
return signin
|
|
41
|
+
res.headers['Access-Control-Allow-Origin'] = '*'
|
|
42
|
+
web.options.audit_exec(req, res, web)
|
|
43
|
+
return web.gui_html_data
|
|
44
|
+
|
|
45
|
+
@app.get('/signin/gui/appid', response_class=PlainTextResponse)
|
|
46
|
+
@app.get('/gui/appid', response_class=PlainTextResponse)
|
|
47
|
+
async def appid(req:Request, res:Response):
|
|
48
|
+
return self.ver.__appid__
|
|
49
|
+
|
|
50
|
+
@app.get('/gui/version_info')
|
|
51
|
+
async def version_info(req:Request, res:Response):
|
|
52
|
+
return self.version_info
|
|
53
|
+
|
|
54
|
+
@app.get('/gui/user_info')
|
|
55
|
+
async def user_info(req:Request, res:Response):
|
|
56
|
+
if 'signin' not in req.session:
|
|
57
|
+
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
58
|
+
if 'name' not in req.session['signin']:
|
|
59
|
+
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
60
|
+
name = req.session['signin']['name']
|
|
61
|
+
try:
|
|
62
|
+
users = web.user_list(name)
|
|
63
|
+
if users is None or len(users) == 0:
|
|
64
|
+
return dict(warn='User information is not found.')
|
|
65
|
+
return users[0]
|
|
66
|
+
except Exception as e:
|
|
67
|
+
return dict(error=f'{e}')
|
|
68
|
+
|
|
69
|
+
@app.get('/gui/filemenu')
|
|
70
|
+
async def filemenu(req:Request, res:Response):
|
|
71
|
+
return web.filemenu
|
|
72
|
+
|
|
73
|
+
@app.get('/gui/toolmenu')
|
|
74
|
+
async def toolmenu(req:Request, res:Response):
|
|
75
|
+
ret = dict()
|
|
76
|
+
for k, v in web.toolmenu.items():
|
|
77
|
+
path_jadge = web.signin.check_path(req, v['href'])
|
|
78
|
+
if path_jadge is not None:
|
|
79
|
+
continue
|
|
80
|
+
ret[k] = v
|
|
81
|
+
return ret
|
|
82
|
+
|
|
83
|
+
@app.get('/gui/viewmenu')
|
|
84
|
+
async def viewmenu(req:Request, res:Response):
|
|
85
|
+
return web.viewmenu
|
|
86
|
+
|
|
87
|
+
@app.get('/gui/aboutmenu')
|
|
88
|
+
async def aboutmenu(req:Request, res:Response):
|
|
89
|
+
return web.aboutmenu
|
|
90
|
+
|
|
91
|
+
def callback_console_modal_log_func(self, web:Web, output:Dict[str, Any]):
|
|
92
|
+
"""
|
|
93
|
+
コンソールモーダルにログを出力する
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
web (Web): Webオブジェクト
|
|
97
|
+
output (Dict[str, Any]): 出力
|
|
98
|
+
"""
|
|
99
|
+
if web.logger.level == logging.DEBUG:
|
|
100
|
+
output_str = common.to_str(output, slise=100)
|
|
101
|
+
web.logger.debug(f"web.callback_console_modal_log_func: output={output_str}")
|
|
102
|
+
web.cb_queue.put(('js_console_modal_log_func', None, output))
|
|
103
|
+
|
|
104
|
+
def callback_return_cmd_exec_func(self, web:Web, title:str, output:Dict[str, Any]):
|
|
105
|
+
"""
|
|
106
|
+
コマンド実行結果を返す
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
web (Web): Webオブジェクト
|
|
110
|
+
title (str): タイトル
|
|
111
|
+
output (Dict[str, Any]): 出力
|
|
112
|
+
"""
|
|
113
|
+
if web.logger.level == logging.DEBUG:
|
|
114
|
+
output_str = common.to_str(output, slise=100)
|
|
115
|
+
web.logger.debug(f"web.callback_return_cmd_exec_func: output={output_str}")
|
|
116
|
+
web.cb_queue.put(('js_return_cmd_exec_func', title, output))
|
|
117
|
+
|
|
118
|
+
def callback_return_pipe_exec_func(self, web:Web, title:str, output:Dict[str, Any]):
|
|
119
|
+
"""
|
|
120
|
+
パイプライン実行結果を返す
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
web (Web): Webオブジェクト
|
|
124
|
+
title (str): タイトル
|
|
125
|
+
output (Dict[str, Any]): 出力
|
|
126
|
+
"""
|
|
127
|
+
if web.logger.level == logging.DEBUG:
|
|
128
|
+
output_str = common.to_str(output, slise=100)
|
|
129
|
+
web.logger.debug(f"web.callback_return_pipe_exec_func: title={title}, output={output_str}")
|
|
130
|
+
web.cb_queue.put(('js_return_pipe_exec_func', title, output))
|
|
131
|
+
|
|
132
|
+
def callback_return_stream_log_func(self, web:Web, output:Dict[str, Any]):
|
|
133
|
+
"""
|
|
134
|
+
ストリームログを返す
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
web (Web): Webオブジェクト
|
|
138
|
+
output (Dict[str, Any]): 出力
|
|
139
|
+
"""
|
|
140
|
+
if web.logger.level == logging.DEBUG:
|
|
141
|
+
output_str = common.to_str(output, slise=100)
|
|
142
|
+
web.logger.debug(f"web.callback_return_stream_log_func: output={output_str}")
|
|
143
|
+
web.cb_queue.put(('js_return_stream_log_func', None, output))
|
|
144
|
+
|
|
145
|
+
def mk_curl_fileup(self, web:Web, cmd_opt:Dict[str, Any]) -> str:
|
|
146
|
+
"""
|
|
147
|
+
curlコマンド文字列を作成する
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
web (Web): Webオブジェクト
|
|
151
|
+
cmd_opt (dict): コマンドのオプション
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
str: curlコマンド文字列
|
|
155
|
+
"""
|
|
156
|
+
if 'mode' not in cmd_opt or 'cmd' not in cmd_opt:
|
|
157
|
+
return ""
|
|
158
|
+
curl_fileup = set()
|
|
159
|
+
for ref in web.options.get_cmd_choices(cmd_opt['mode'], cmd_opt['cmd'], True):
|
|
160
|
+
if 'fileio' not in ref or ref['fileio'] != 'in':
|
|
161
|
+
continue
|
|
162
|
+
if ref['opt'] in cmd_opt and cmd_opt[ref['opt']] != '':
|
|
163
|
+
curl_fileup.add(f'-F "{ref["opt"]}=@<{ref["opt"]}>"')
|
|
164
|
+
if 'stdin' in cmd_opt and cmd_opt['stdin']:
|
|
165
|
+
curl_fileup.add(f'-F "input_file=@<input_file>"')
|
|
166
|
+
return " ".join(curl_fileup)
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
from cmdbox.app import feature
|
|
2
|
-
from cmdbox.app.web import Web
|
|
3
|
-
from fastapi import FastAPI, Request, Response, HTTPException
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class LoadPin(feature.WebFeature):
|
|
7
|
-
def route(self, web:Web, app:FastAPI) -> None:
|
|
8
|
-
"""
|
|
9
|
-
webモードのルーティングを設定します
|
|
10
|
-
|
|
11
|
-
Args:
|
|
12
|
-
web (Web): Webオブジェクト
|
|
13
|
-
app (FastAPI): FastAPIオブジェクト
|
|
14
|
-
"""
|
|
15
|
-
@app.post('/gui/load_cmd_pin')
|
|
16
|
-
async def load_cmd_pin(req:Request, res:Response):
|
|
17
|
-
signin = web.signin.check_signin(req, res)
|
|
18
|
-
if signin is not None:
|
|
19
|
-
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
20
|
-
if 'signin' not in req.session or req.session['signin'] is None:
|
|
21
|
-
return dict(warn='Please sign in.')
|
|
22
|
-
form = await req.form()
|
|
23
|
-
title = form.get('title')
|
|
24
|
-
sess = req.session['signin']
|
|
25
|
-
data = web.user_data(req, sess['uid'], sess['name'], 'cmdpins', title)
|
|
26
|
-
if data is None:
|
|
27
|
-
return dict(success='off')
|
|
28
|
-
return dict(success=data)
|
|
29
|
-
|
|
30
|
-
@app.post('/gui/load_pipe_pin')
|
|
31
|
-
async def load_pipe_pin(req:Request, res:Response):
|
|
32
|
-
signin = web.signin.check_signin(req, res)
|
|
33
|
-
if signin is not None:
|
|
34
|
-
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
35
|
-
if 'signin' not in req.session or req.session['signin'] is None:
|
|
36
|
-
return dict(warn='Please sign in.')
|
|
37
|
-
form = await req.form()
|
|
38
|
-
title = form.get('title')
|
|
39
|
-
sess = req.session['signin']
|
|
40
|
-
data = web.user_data(req, sess['uid'], sess['name'], 'pipepins', title)
|
|
41
|
-
if data is None:
|
|
42
|
-
return dict(success='off')
|
|
43
|
-
return dict(success=data)
|
|
1
|
+
from cmdbox.app import feature
|
|
2
|
+
from cmdbox.app.web import Web
|
|
3
|
+
from fastapi import FastAPI, Request, Response, HTTPException
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LoadPin(feature.WebFeature):
|
|
7
|
+
def route(self, web:Web, app:FastAPI) -> None:
|
|
8
|
+
"""
|
|
9
|
+
webモードのルーティングを設定します
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
web (Web): Webオブジェクト
|
|
13
|
+
app (FastAPI): FastAPIオブジェクト
|
|
14
|
+
"""
|
|
15
|
+
@app.post('/gui/load_cmd_pin')
|
|
16
|
+
async def load_cmd_pin(req:Request, res:Response):
|
|
17
|
+
signin = web.signin.check_signin(req, res)
|
|
18
|
+
if signin is not None:
|
|
19
|
+
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
20
|
+
if 'signin' not in req.session or req.session['signin'] is None:
|
|
21
|
+
return dict(warn='Please sign in.')
|
|
22
|
+
form = await req.form()
|
|
23
|
+
title = form.get('title')
|
|
24
|
+
sess = req.session['signin']
|
|
25
|
+
data = web.user_data(req, sess['uid'], sess['name'], 'cmdpins', title)
|
|
26
|
+
if data is None:
|
|
27
|
+
return dict(success='off')
|
|
28
|
+
return dict(success=data)
|
|
29
|
+
|
|
30
|
+
@app.post('/gui/load_pipe_pin')
|
|
31
|
+
async def load_pipe_pin(req:Request, res:Response):
|
|
32
|
+
signin = web.signin.check_signin(req, res)
|
|
33
|
+
if signin is not None:
|
|
34
|
+
raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
|
|
35
|
+
if 'signin' not in req.session or req.session['signin'] is None:
|
|
36
|
+
return dict(warn='Please sign in.')
|
|
37
|
+
form = await req.form()
|
|
38
|
+
title = form.get('title')
|
|
39
|
+
sess = req.session['signin']
|
|
40
|
+
data = web.user_data(req, sess['uid'], sess['name'], 'pipepins', title)
|
|
41
|
+
if data is None:
|
|
42
|
+
return dict(success='off')
|
|
43
|
+
return dict(success=data)
|