jknife 0.0.8__tar.gz → 0.0.11__tar.gz
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.
- {jknife-0.0.8 → jknife-0.0.11}/PKG-INFO +1 -1
- {jknife-0.0.8 → jknife-0.0.11}/pyproject.toml +1 -1
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/commands/jknife.py +41 -30
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/mongo/users.py +1 -1
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/views/users.py +2 -2
- jknife-0.0.8/main.py +0 -40
- jknife-0.0.8/settings.py +0 -161
- {jknife-0.0.8 → jknife-0.0.11}/.gitignore +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/LICENSE +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/README.md +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/commands/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/mongo/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/mongo/network.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/mongo/personnel_info.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/mongo/settings.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/mongo/token.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/rdbms/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/rdbms/network.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/rdbms/personnel_info.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/rdbms/settings.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/rdbms/token.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/db/models/rdbms/users.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/dependencies/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/dependencies/token.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/dependencies/users.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/logging.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/views/__init__.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/views/error_message.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/views/personnel_info.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/jknife/views/tokens.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/src/settings_loader.py +0 -0
- {jknife-0.0.8 → jknife-0.0.11}/tests/__init__.py +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
import sys
|
2
2
|
import os
|
3
|
+
import subprocess
|
3
4
|
|
4
5
|
|
5
6
|
FOLDER_LIST: tuple = ("models", "routers", "views", )
|
@@ -12,7 +13,7 @@ Usage: jknife [sub_command] [3rd argument]
|
|
12
13
|
* sub_command:
|
13
14
|
- startproject [PROJECT_NAME] : create project filesystem
|
14
15
|
- createapp [APP_NAME] : create API application in project
|
15
|
-
-
|
16
|
+
- runserver [OPTIONS] : run server with uvicorn
|
16
17
|
|
17
18
|
[run OPTIONS]
|
18
19
|
--host [HOSTNAME] : run server with hostname [HOSTNAME]
|
@@ -20,9 +21,9 @@ Usage: jknife [sub_command] [3rd argument]
|
|
20
21
|
--reload : reload uvicorn server automatically after editing source.
|
21
22
|
"""
|
22
23
|
|
23
|
-
# Template for
|
24
|
-
|
25
|
-
# import packages from default or pip library
|
24
|
+
# Template for APP_NAME.py in each folder.
|
25
|
+
MODULE_IMPORT_STRING_DICT: dict = {
|
26
|
+
"models": """# import packages from default or pip library
|
26
27
|
from typing_extensions import Annotated, Doc
|
27
28
|
|
28
29
|
# import packages from this framework below
|
@@ -32,10 +33,8 @@ from typing_extensions import Annotated, Doc
|
|
32
33
|
|
33
34
|
|
34
35
|
# define your own customising class below
|
35
|
-
"""
|
36
|
-
|
37
|
-
# Template for routers/APP_NAME.py
|
38
|
-
MODULE_IMPORT_STRING_ROUTERS: str = """# import packages from default or pip library
|
36
|
+
""",
|
37
|
+
"views": """# import packages from default or pip library
|
39
38
|
from fastapi import APIRouter, Depends, status, HTTPException
|
40
39
|
from typing_extensions import Annotated, Doc
|
41
40
|
|
@@ -47,11 +46,9 @@ router = APIRouter(prefix="/{}",
|
|
47
46
|
tags=['{}'])
|
48
47
|
|
49
48
|
# define your own customising class below
|
50
|
-
"""
|
51
|
-
|
52
|
-
|
53
|
-
MODULE_IMPORT_STRING_VIEWS: str = """# import packages from default or pip library
|
54
|
-
from pydantic import BaseModel
|
49
|
+
""",
|
50
|
+
"routers": """# import packages from default or pip library
|
51
|
+
from pydantic import BaseModel, field_validator, ValidationError
|
55
52
|
|
56
53
|
# import packages from this framework below
|
57
54
|
|
@@ -61,10 +58,14 @@ from pydantic import BaseModel
|
|
61
58
|
|
62
59
|
# define your own customising class below
|
63
60
|
"""
|
61
|
+
}
|
64
62
|
|
65
63
|
# WARN MSGs
|
66
64
|
WARN_MSG_ALREADY_EXIST_PROJECT: str = """
|
67
|
-
[WARNING] You already have project '{}'.
|
65
|
+
[WARNING] You already have project named '{}'.
|
66
|
+
"""
|
67
|
+
WARN_MSG_ALREADY_EXIST_APP: str = """
|
68
|
+
[WARNING] You already have app named '{}'.
|
68
69
|
"""
|
69
70
|
|
70
71
|
# ERROR MSGs
|
@@ -74,6 +75,9 @@ ERROR_MSG_START_PROJECT: str = """
|
|
74
75
|
|
75
76
|
* Command for Starting Project: jknife startproject [PROJECT_NAME]
|
76
77
|
"""
|
78
|
+
ERROR_MSG_IMPOSSIBLE_RUNSERVER_OUT_OF_PROJECT: str = """
|
79
|
+
[ERROR] You have to execute 'runserver' command in your project folder.
|
80
|
+
"""
|
77
81
|
|
78
82
|
# File Contents
|
79
83
|
CONTENTS_IN_SETTINGS: str = """# this file is charge of config for custom fastapi.
|
@@ -315,24 +319,25 @@ def startproject(pjt_name: str) -> None:
|
|
315
319
|
def createapp(app_name: str) -> None:
|
316
320
|
# check main folders for jknife
|
317
321
|
for folder_name in FOLDER_LIST:
|
318
|
-
|
319
|
-
|
322
|
+
try:
|
323
|
+
if not os.listdir(folder_name):
|
320
324
|
with open(f"{folder_name}/__init__.py", "w") as f:
|
321
325
|
f.write("")
|
322
326
|
|
323
|
-
|
324
|
-
|
325
|
-
|
327
|
+
if f"{app_name}.py" not in os.listdir(folder_name):
|
328
|
+
with open(f"{folder_name}/{app_name}.py", "w") as f:
|
329
|
+
f.write(MODULE_IMPORT_STRING_DICT.get(folder_name))
|
326
330
|
|
327
|
-
|
328
|
-
|
329
|
-
f.write(MODULE_IMPORT_STRING_MODELS)
|
331
|
+
else:
|
332
|
+
raise AttributeError
|
330
333
|
|
331
|
-
|
332
|
-
|
334
|
+
except FileNotFoundError:
|
335
|
+
print(ERROR_MSG_START_PROJECT)
|
336
|
+
return None
|
333
337
|
|
334
|
-
|
335
|
-
|
338
|
+
except AttributeError:
|
339
|
+
print(WARN_MSG_ALREADY_EXIST_APP.format(app_name))
|
340
|
+
return None
|
336
341
|
|
337
342
|
return None
|
338
343
|
|
@@ -340,9 +345,15 @@ def help_msg():
|
|
340
345
|
print(HELP_MSG)
|
341
346
|
return None
|
342
347
|
|
343
|
-
def run_server(options: list):
|
344
|
-
|
345
|
-
|
348
|
+
def run_server(options: list, app_name: str = "main"):
|
349
|
+
for f in FOLDER_LIST:
|
350
|
+
if f not in os.listdir():
|
351
|
+
print(ERROR_MSG_IMPOSSIBLE_RUNSERVER_OUT_OF_PROJECT)
|
352
|
+
return None
|
353
|
+
|
354
|
+
args = " ".join([ option.replace("=", " ") for option in options ])
|
355
|
+
command = f"uvicorn {app_name}:app {args}"
|
356
|
+
result_cmd = subprocess.call(command, shell=True)
|
346
357
|
return None
|
347
358
|
|
348
359
|
def main() -> None:
|
@@ -359,7 +370,7 @@ def main() -> None:
|
|
359
370
|
createapp(app_name=read_command[2])
|
360
371
|
return None
|
361
372
|
|
362
|
-
elif sub_command == "
|
373
|
+
elif sub_command == "runserver":
|
363
374
|
run_server(read_command[2:])
|
364
375
|
return None
|
365
376
|
|
@@ -4,7 +4,7 @@ from typing_extensions import Annotated, Doc
|
|
4
4
|
from mongoengine import Document, BooleanField, DateTimeField, IntField, StringField
|
5
5
|
|
6
6
|
# import packages from this framework
|
7
|
-
from
|
7
|
+
from ..rdbms.users import encrypt_password
|
8
8
|
|
9
9
|
|
10
10
|
# define Class for Common SQLModel
|
@@ -4,8 +4,8 @@ from typing_extensions import Annotated, Doc
|
|
4
4
|
from pydantic import BaseModel, field_validator
|
5
5
|
|
6
6
|
# import packages from this framework
|
7
|
-
from
|
8
|
-
from
|
7
|
+
from jknife.views.personnel_info import EmailInputViewMixin
|
8
|
+
from jknife.dependencies.users import validate_password_policy
|
9
9
|
|
10
10
|
|
11
11
|
# define mixin class
|
jknife-0.0.8/main.py
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# import modules from python library
|
2
|
-
import importlib, os
|
3
|
-
from fastapi import FastAPI, Request, status
|
4
|
-
from fastapi.responses import JSONResponse
|
5
|
-
from fastapi.exceptions import RequestValidationError
|
6
|
-
|
7
|
-
|
8
|
-
# import required objects from projects
|
9
|
-
from src.jknife.db import DBConnector
|
10
|
-
from settings import API_VERSION
|
11
|
-
|
12
|
-
|
13
|
-
# set main url for all router
|
14
|
-
MAIN_URL: str = f"/api/{API_VERSION}"
|
15
|
-
|
16
|
-
|
17
|
-
# DB Connector
|
18
|
-
db_connector = DBConnector()
|
19
|
-
|
20
|
-
# start application
|
21
|
-
app = FastAPI(lifespan=db_connector.startup_db)
|
22
|
-
|
23
|
-
|
24
|
-
# add exception handler for ValidationException
|
25
|
-
@app.exception_handler(exc_class_or_status_code=RequestValidationError)
|
26
|
-
async def validation_error(req: Request, exc: RequestValidationError):
|
27
|
-
errors: dict = exc.errors()[0] if isinstance(exc.errors(), list) else dict(exc.errors())
|
28
|
-
result: dict = {"field": errors.get("input"), "msg": errors.get("msg")}
|
29
|
-
return JSONResponse(
|
30
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
31
|
-
content={"detail": result}
|
32
|
-
)
|
33
|
-
|
34
|
-
|
35
|
-
# add routers_bak
|
36
|
-
for router in os.listdir(os.path.abspath(path="routers")):
|
37
|
-
if not router.startswith("__"):
|
38
|
-
tmp_module = importlib.import_module(name=f"routers.{router.split('.')[0]}")
|
39
|
-
app.include_router(router=tmp_module.router,
|
40
|
-
prefix=MAIN_URL)
|
jknife-0.0.8/settings.py
DELETED
@@ -1,161 +0,0 @@
|
|
1
|
-
# this file is charge of config for custom fastapi.
|
2
|
-
|
3
|
-
from os import environ
|
4
|
-
|
5
|
-
|
6
|
-
# [ DEBUG ]
|
7
|
-
# this variable is a mode switcher.
|
8
|
-
# if you are about to publish your application to public, please turn this switch to False.
|
9
|
-
# on the other hands, during development, please switch this value to True.
|
10
|
-
# DEBUG_MODE provides
|
11
|
-
# - query logs on database.
|
12
|
-
DEBUG_MODE: bool = True
|
13
|
-
|
14
|
-
# [ API_VERSION ]
|
15
|
-
# API_VERSION is a management variables for your api.
|
16
|
-
# This value will be used to call api as an URL prefix. e.g) /api/{YOUR_API_VERSION}/
|
17
|
-
# you can modify the value of API_VERSION to whatever you want.
|
18
|
-
API_VERSION: str = "v1"
|
19
|
-
|
20
|
-
# [ DATABASE ]
|
21
|
-
# DATABASE is charge of connection to database server.
|
22
|
-
# recommend to store DB information in env var and get them by using environ.get()
|
23
|
-
# this framework supports some databases.
|
24
|
-
# - supported type: ["none", "postgresql", "mysql", "sqlite", "mongo"]
|
25
|
-
#
|
26
|
-
# type 'none': if you do not want to use database. it is a default if the type is None
|
27
|
-
# structure of database
|
28
|
-
# - type in ['postgresql', 'mysql', 'mongo']
|
29
|
-
# - key: "dbms"
|
30
|
-
# - values: {"username": DB_USERNAME, "password": DB_PASSWORD, "host": DB_HOST, "port": DB_PORT, "db": DB_NAME}
|
31
|
-
# - if you use mongo, it is possible to add key 'authSource' for name of database that is responsible for auth.
|
32
|
-
# - type 'sqlite'
|
33
|
-
# - sqlite_filepath: input path of sqlite3 database file in an absolute way or a relative one.
|
34
|
-
# "redis" exist for the Redis - cached db.
|
35
|
-
DATABASE: dict = {
|
36
|
-
"type": environ.get("db_type"),
|
37
|
-
"dbms": {
|
38
|
-
"username": environ.get("db_username"),
|
39
|
-
"password": environ.get("db_password"),
|
40
|
-
"host": environ.get("db_host"),
|
41
|
-
"port": int(environ.get("db_port")),
|
42
|
-
"db": environ.get("db_name"),
|
43
|
-
"authSource": environ.get("mongo_auth_source")
|
44
|
-
},
|
45
|
-
"sqlite": {
|
46
|
-
"sqlite_filepath": "./fastapi.db"
|
47
|
-
},
|
48
|
-
"redis": {
|
49
|
-
"host": environ.get("redis_host"),
|
50
|
-
"port": environ.get("redis_port"),
|
51
|
-
}
|
52
|
-
}
|
53
|
-
|
54
|
-
# [ AUTHENTICATION ]
|
55
|
-
# AUTHENTICATION is charge of JWT token for authenticated user.
|
56
|
-
# token: information for JWT token
|
57
|
-
# - token_issuer: token issuer
|
58
|
-
# - token_audience: IP or URL address that allows this token
|
59
|
-
# - token_valid_time: interval time between when the access token issued and expired in minutes.
|
60
|
-
# - token_refresh_time: interval time in minute for reissuing access token.
|
61
|
-
# - secret_key: secret key to encrypt token
|
62
|
-
# - algorithm: select encryption algorithm
|
63
|
-
# * HS: for HMAC symmetric algorithm
|
64
|
-
# * RS: for RSA symmetric algorithm
|
65
|
-
# * ES: for ECDSA asymmetric algorithm
|
66
|
-
AUTHENTICATION: dict = {
|
67
|
-
"token": {
|
68
|
-
"token_issuer": "http://127.0.0.1",
|
69
|
-
"token_audience": "http://127.0.0.1",
|
70
|
-
"token_valid_time": 20,
|
71
|
-
"token_refresh_time": 60 * 24 * 30,
|
72
|
-
"secret_key": "THIS IS A TEST",
|
73
|
-
"algorithm": "HS256"
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
# [ PASSWORD_POLICIES ]
|
78
|
-
# PASSWORD_POLICIES is charge of password compliance, when users are created or change their password
|
79
|
-
# compliance: the list of password policies
|
80
|
-
# - PASSWORD_MINLEN: limit the minimum length of password. default is 8 but it can be customized with 'min_length'.
|
81
|
-
# - PASSWORD_UPCHAR: password must contain at least one upper alphabet character.
|
82
|
-
# - PASSWORD_LOWCHAR: password must contain at least one lower alphabet character.
|
83
|
-
# - PASSWORD_NUMBER: password must contain at least one numeric character.
|
84
|
-
# - PASSWORD_SPECIAL: password must contain at least one special character.
|
85
|
-
# encrypt_type: algorithm for encrypting password. please refer to 'hashlib.algorithms_available'
|
86
|
-
# min_length: minimum length of password. it will be used for PASSWORD_MINLEN
|
87
|
-
PASSWORD_POLICIES: dict = {
|
88
|
-
"compliance": [
|
89
|
-
"PASSWORD_MINLEN",
|
90
|
-
"PASSWORD_UPCHAR",
|
91
|
-
"PASSWORD_LOWCHAR",
|
92
|
-
"PASSWORD_NUMBER",
|
93
|
-
"PASSWORD_SPECIAL"
|
94
|
-
],
|
95
|
-
"encrypt_type": "sha256",
|
96
|
-
"min_length": 8
|
97
|
-
}
|
98
|
-
|
99
|
-
|
100
|
-
# [ LOG_SETTINGS ]
|
101
|
-
# LOG_SETTINGS is based on python dictConfig
|
102
|
-
# (https://docs.python.org/3/library/logging.config.html#dictionary-schema-details).
|
103
|
-
# Refer to the official documentation, write down your own config for logging.
|
104
|
-
# {"version": 1, "disable_existing_logger": False} will be applied automatically.
|
105
|
-
# If DEBUG_MODE is True, uvicorn log will be printed out on your console.
|
106
|
-
# Default Logger:
|
107
|
-
# * DB: The logger 'db' is charge of database logging.
|
108
|
-
# if you want to change the name of logger, you should also change the DB_LOGGER_LIST below.
|
109
|
-
# or you can not see any proper log.
|
110
|
-
LOG_SETTINGS: dict = {
|
111
|
-
"formatters": {
|
112
|
-
"default": {
|
113
|
-
"format": "[%(asctime)s] %(name)s:%(levelname)s - %(message)s",
|
114
|
-
"datefmt": "%Y-%m-%d %H:%M:%S:%s"
|
115
|
-
}
|
116
|
-
},
|
117
|
-
"handlers": {
|
118
|
-
"main": {
|
119
|
-
"class": "logging.handlers.RotatingFileHandler",
|
120
|
-
"level": "INFO",
|
121
|
-
"formatter": "default",
|
122
|
-
"filename": "logs/all_logs.log",
|
123
|
-
"maxBytes": 1024 * 1024 * 100, # 10 MB
|
124
|
-
"backupCount": 3
|
125
|
-
},
|
126
|
-
"db": {
|
127
|
-
"class": "logging.handlers.RotatingFileHandler",
|
128
|
-
"level": "INFO",
|
129
|
-
"formatter": "default",
|
130
|
-
"filename": "logs/db.log",
|
131
|
-
"maxBytes": 1024 * 1024 * 100, # 10 MB
|
132
|
-
"backupCount": 3
|
133
|
-
},
|
134
|
-
"db_error": {
|
135
|
-
"class": "logging.handlers.RotatingFileHandler",
|
136
|
-
"level": "ERROR",
|
137
|
-
"formatter": "default",
|
138
|
-
"filename": "logs/db_error.log",
|
139
|
-
"maxBytes": 1024 * 1024 * 100, # 10 MB
|
140
|
-
"backupCount": 3
|
141
|
-
}
|
142
|
-
},
|
143
|
-
"loggers": {
|
144
|
-
"": {
|
145
|
-
"level": "INFO",
|
146
|
-
"handlers": ["main"],
|
147
|
-
},
|
148
|
-
"db": {
|
149
|
-
"level": "INFO",
|
150
|
-
"handlers": ["db", "db_error"],
|
151
|
-
"propagate": True,
|
152
|
-
},
|
153
|
-
}
|
154
|
-
}
|
155
|
-
|
156
|
-
# [ LOGGER_LIST ]
|
157
|
-
# create your own logger instance with core.logging.LoggerMgmt and use it in specific realm.
|
158
|
-
DB_LOGGER_LIST = ("db",)
|
159
|
-
|
160
|
-
|
161
|
-
### END CONTENTS ###
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|