Nexom 0.1.4__py3-none-any.whl → 1.0.1__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.
- nexom/__init__.py +2 -2
- nexom/__main__.py +111 -17
- nexom/app/__init__.py +62 -0
- nexom/app/auth.py +322 -0
- nexom/{web → app}/cookie.py +4 -2
- nexom/app/db.py +88 -0
- nexom/app/path.py +195 -0
- nexom/app/request.py +267 -0
- nexom/{web → app}/response.py +13 -3
- nexom/{web → app}/template.py +1 -1
- nexom/app/user.py +31 -0
- nexom/assets/app/__init__.py +0 -0
- nexom/assets/app/__pycache__/__init__.cpython-313.pyc +0 -0
- nexom/assets/app/config.py +28 -0
- nexom/assets/app/gunicorn.conf.py +5 -0
- nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc +0 -0
- nexom/assets/app/pages/_templates.py +7 -0
- nexom/assets/{server → app}/pages/default.py +2 -2
- nexom/assets/{server → app}/pages/document.py +2 -2
- nexom/assets/app/router.py +12 -0
- nexom/assets/app/wsgi.py +64 -0
- nexom/assets/auth/__init__.py +0 -0
- nexom/assets/auth/__pycache__/__init__.cpython-313.pyc +0 -0
- nexom/assets/auth/config.py +27 -0
- nexom/assets/auth/gunicorn.conf.py +5 -0
- nexom/assets/auth/wsgi.py +62 -0
- nexom/assets/auth_page/login.html +95 -0
- nexom/assets/auth_page/signup.html +106 -0
- nexom/assets/error_page/error.html +3 -3
- nexom/assets/gateway/apache_app.conf +16 -0
- nexom/assets/gateway/nginx_app.conf +21 -0
- nexom/buildTools/__init__.py +1 -0
- nexom/buildTools/build.py +274 -54
- nexom/buildTools/run.py +185 -0
- nexom/core/__init__.py +2 -1
- nexom/core/error.py +81 -3
- nexom/core/log.py +111 -0
- nexom/{engine → core}/object_html_render.py +4 -1
- nexom/templates/__init__.py +0 -0
- nexom/templates/auth.py +72 -0
- {nexom-0.1.4.dist-info → nexom-1.0.1.dist-info}/METADATA +75 -50
- nexom-1.0.1.dist-info/RECORD +56 -0
- {nexom-0.1.4.dist-info → nexom-1.0.1.dist-info}/WHEEL +1 -1
- nexom/assets/server/config.py +0 -27
- nexom/assets/server/gunicorn.conf.py +0 -16
- nexom/assets/server/pages/__pycache__/__init__.cpython-313.pyc +0 -0
- nexom/assets/server/pages/_templates.py +0 -11
- nexom/assets/server/router.py +0 -18
- nexom/assets/server/wsgi.py +0 -30
- nexom/engine/__init__.py +0 -1
- nexom/web/__init__.py +0 -5
- nexom/web/path.py +0 -125
- nexom/web/request.py +0 -62
- nexom-0.1.4.dist-info/RECORD +0 -39
- /nexom/{web → app}/http_status_codes.py +0 -0
- /nexom/{web → app}/middleware.py +0 -0
- /nexom/assets/{server → app}/pages/__init__.py +0 -0
- /nexom/assets/{server → app}/static/dog.jpeg +0 -0
- /nexom/assets/{server → app}/static/style.css +0 -0
- /nexom/assets/{server → app}/templates/base.html +0 -0
- /nexom/assets/{server → app}/templates/default.html +0 -0
- /nexom/assets/{server → app}/templates/document.html +0 -0
- /nexom/assets/{server → app}/templates/footer.html +0 -0
- /nexom/assets/{server → app}/templates/header.html +0 -0
- {nexom-0.1.4.dist-info → nexom-1.0.1.dist-info}/entry_points.txt +0 -0
- {nexom-0.1.4.dist-info → nexom-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {nexom-0.1.4.dist-info → nexom-1.0.1.dist-info}/top_level.txt +0 -0
nexom/core/log.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import traceback
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# =========================
|
|
9
|
+
# App Logger
|
|
10
|
+
# =========================
|
|
11
|
+
|
|
12
|
+
class AppLogger:
|
|
13
|
+
"""
|
|
14
|
+
Application-level logger.
|
|
15
|
+
|
|
16
|
+
Used for:
|
|
17
|
+
- info
|
|
18
|
+
- warn
|
|
19
|
+
- error
|
|
20
|
+
- access
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
info: str | Path | None = None,
|
|
27
|
+
warn: str | Path | None = None,
|
|
28
|
+
error: str | Path | None = None,
|
|
29
|
+
access: str | Path | None = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
self.info_path = self._norm(info)
|
|
32
|
+
self.warn_path = self._norm(warn)
|
|
33
|
+
self.error_path = self._norm(error)
|
|
34
|
+
self.access_path = self._norm(access)
|
|
35
|
+
|
|
36
|
+
def info(self, msg: str) -> None:
|
|
37
|
+
self._write(self.info_path, "INFO", msg)
|
|
38
|
+
|
|
39
|
+
def warn(self, msg: str) -> None:
|
|
40
|
+
self._write(self.warn_path, "WARN", msg)
|
|
41
|
+
|
|
42
|
+
def error(self, err: Exception | str) -> None:
|
|
43
|
+
if isinstance(err, Exception):
|
|
44
|
+
msg = "".join(traceback.format_exception(err))
|
|
45
|
+
else:
|
|
46
|
+
msg = str(err)
|
|
47
|
+
self._write(self.error_path, "ERROR", msg)
|
|
48
|
+
|
|
49
|
+
def access(self, msg: str) -> None:
|
|
50
|
+
self._write(self.access_path, "ACCESS", msg)
|
|
51
|
+
|
|
52
|
+
# ---------- internal ----------
|
|
53
|
+
|
|
54
|
+
def _norm(self, path: str | Path | None) -> Path | None:
|
|
55
|
+
if not path:
|
|
56
|
+
return None
|
|
57
|
+
p = Path(path)
|
|
58
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
return p
|
|
60
|
+
|
|
61
|
+
def _write(self, path: Path | None, level: str, msg: str) -> None:
|
|
62
|
+
if path is None:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
ts = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
|
66
|
+
line = f"[{ts}] [{level}] {msg}\n"
|
|
67
|
+
|
|
68
|
+
with path.open("a", encoding="utf-8") as f:
|
|
69
|
+
f.write(line)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# =========================
|
|
73
|
+
# Auth Logger
|
|
74
|
+
# =========================
|
|
75
|
+
|
|
76
|
+
class AuthLogger:
|
|
77
|
+
"""
|
|
78
|
+
Authentication / Security logger.
|
|
79
|
+
|
|
80
|
+
Used for:
|
|
81
|
+
- login success / failure
|
|
82
|
+
- signup
|
|
83
|
+
- token verification failure
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def __init__(self, path: str | Path) -> None:
|
|
87
|
+
self.path = Path(path)
|
|
88
|
+
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
89
|
+
|
|
90
|
+
def login_success(self, *, user_id: str, ip: str | None = None) -> None:
|
|
91
|
+
self._write("LOGIN_OK", user_id, ip)
|
|
92
|
+
|
|
93
|
+
def login_failed(self, *, user_id: str, ip: str | None = None) -> None:
|
|
94
|
+
self._write("LOGIN_NG", user_id, ip)
|
|
95
|
+
|
|
96
|
+
def signup(self, *, user_id: str, ip: str | None = None) -> None:
|
|
97
|
+
self._write("SIGNUP", user_id, ip)
|
|
98
|
+
|
|
99
|
+
def token_invalid(self, *, token: str | None, ip: str | None = None) -> None:
|
|
100
|
+
t = token[:8] + "..." if token else "none"
|
|
101
|
+
self._write("TOKEN_INVALID", t, ip)
|
|
102
|
+
|
|
103
|
+
# ---------- internal ----------
|
|
104
|
+
|
|
105
|
+
def _write(self, action: str, subject: str, ip: str | None) -> None:
|
|
106
|
+
ts = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
|
107
|
+
ip_txt = ip or "-"
|
|
108
|
+
line = f"[{ts}] [{action}] subject={subject} ip={ip_txt}\n"
|
|
109
|
+
|
|
110
|
+
with self.path.open("a", encoding="utf-8") as f:
|
|
111
|
+
f.write(line)
|
|
@@ -17,11 +17,12 @@ import re
|
|
|
17
17
|
from collections import UserList
|
|
18
18
|
from typing import Final
|
|
19
19
|
|
|
20
|
-
from
|
|
20
|
+
from .error import (
|
|
21
21
|
HTMLDocLibNotFoundError,
|
|
22
22
|
ObjectHTMLImportError,
|
|
23
23
|
ObjectHTMLInsertValueError,
|
|
24
24
|
ObjectHTMLExtendsError,
|
|
25
|
+
ObjectHTMLTypeError
|
|
25
26
|
)
|
|
26
27
|
|
|
27
28
|
|
|
@@ -90,6 +91,8 @@ class ObjectHTML:
|
|
|
90
91
|
self._set_doc(doc)
|
|
91
92
|
|
|
92
93
|
def _set_doc(self, doc: HTMLDoc) -> None:
|
|
94
|
+
if not isinstance(doc, HTMLDoc):
|
|
95
|
+
raise ObjectHTMLTypeError()
|
|
93
96
|
def _call(**kwargs: str) -> str:
|
|
94
97
|
return self.render(doc.name, **kwargs)
|
|
95
98
|
|
|
File without changes
|
nexom/templates/auth.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# src/nexom/templates/auth.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from importlib import resources
|
|
5
|
+
|
|
6
|
+
from ..app.auth import AuthClient
|
|
7
|
+
from ..app.request import Request
|
|
8
|
+
from ..app.response import HtmlResponse, JsonResponse
|
|
9
|
+
from ..core.object_html_render import HTMLDoc, ObjectHTML
|
|
10
|
+
|
|
11
|
+
from ..core.error import NexomError
|
|
12
|
+
|
|
13
|
+
# --------------------
|
|
14
|
+
# Object HTML
|
|
15
|
+
# --------------------
|
|
16
|
+
|
|
17
|
+
_OHTML: ObjectHTML = ObjectHTML(
|
|
18
|
+
HTMLDoc(
|
|
19
|
+
"signup",
|
|
20
|
+
resources.files("nexom.assets.auth_page").joinpath("signup.html").read_text(encoding="utf-8"),
|
|
21
|
+
),
|
|
22
|
+
HTMLDoc(
|
|
23
|
+
"login",
|
|
24
|
+
resources.files("nexom.assets.auth_page").joinpath("login.html").read_text(encoding="utf-8"),
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# --------------------
|
|
30
|
+
# Pages
|
|
31
|
+
# --------------------
|
|
32
|
+
|
|
33
|
+
class LoginPage:
|
|
34
|
+
def __init__(self, auth_server: str) -> None:
|
|
35
|
+
self.client = AuthClient(auth_server)
|
|
36
|
+
|
|
37
|
+
def page(self, req: Request, args: dict) -> HtmlResponse | JsonResponse:
|
|
38
|
+
if req.method == "GET":
|
|
39
|
+
return HtmlResponse(_OHTML.render("login"))
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
data = req.json() or {}
|
|
43
|
+
token, user_id, exp = self.client.login(
|
|
44
|
+
user_id=data.get("user_id", ""),
|
|
45
|
+
password=data.get("password", ""),
|
|
46
|
+
)
|
|
47
|
+
return JsonResponse({"ok": True, "user_id": user_id, "token": token, "expires_at": exp})
|
|
48
|
+
except NexomError as e:
|
|
49
|
+
return JsonResponse({"error": e.code}, status=401)
|
|
50
|
+
except Exception:
|
|
51
|
+
return JsonResponse({"error": "Internal Server Error"}, status=401)
|
|
52
|
+
|
|
53
|
+
class SignupPage:
|
|
54
|
+
def __init__(self, auth_server: str) -> None:
|
|
55
|
+
self.client = AuthClient(auth_server)
|
|
56
|
+
|
|
57
|
+
def page(self, req: Request, args: dict) -> HtmlResponse | JsonResponse:
|
|
58
|
+
if req.method == "GET":
|
|
59
|
+
return HtmlResponse(_OHTML.render("signup"))
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
data = req.json() or {}
|
|
63
|
+
ok = self.client.signup(
|
|
64
|
+
user_id=data.get("user_id", ""),
|
|
65
|
+
public_name=data.get("public_name", ""),
|
|
66
|
+
password=data.get("password", ""),
|
|
67
|
+
)
|
|
68
|
+
return JsonResponse({"ok": ok})
|
|
69
|
+
except NexomError as e:
|
|
70
|
+
return JsonResponse({"error": e.code}, status=401)
|
|
71
|
+
except Exception:
|
|
72
|
+
return JsonResponse({"error": "Internal Server Error"}, status=401)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Nexom
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Lightweight Python Web Framework (WSGI)
|
|
5
5
|
Author: TouriAida
|
|
6
6
|
License: MIT License
|
|
@@ -44,64 +44,96 @@ Nexomは短いコードで最低限動作し、シンプルで理解のしやす
|
|
|
44
44
|
## はじめる
|
|
45
45
|
最初のサーバーを起動するには、3つの手順が必要です。
|
|
46
46
|
|
|
47
|
-
1.
|
|
48
|
-
2. nexomをpip
|
|
47
|
+
1. プロジェクトディレクトリを作成
|
|
48
|
+
2. nexomをpipでインストール、プロジェクトのビルド
|
|
49
49
|
3. 起動
|
|
50
50
|
|
|
51
|
-
### 1
|
|
51
|
+
### 1.プロジェクトディレクトリの作成
|
|
52
52
|
**準備**
|
|
53
|
-
|
|
53
|
+
|
|
54
|
+
用意していない場合はディレクトリを作成し、仮想環境も準備してください
|
|
54
55
|
```
|
|
55
|
-
mkdir
|
|
56
|
-
cd
|
|
56
|
+
mkdir banana_project
|
|
57
|
+
cd banana_project
|
|
57
58
|
|
|
58
59
|
python -m venv venv
|
|
59
60
|
source venv/bin/activate
|
|
60
61
|
```
|
|
61
|
-
### 2.
|
|
62
|
+
### 2. pipでインストール、サーバーのビルド
|
|
62
63
|
**インストール**
|
|
64
|
+
|
|
63
65
|
nexomをインストールします。
|
|
64
|
-
※まだベータ版のため、最新のバージョンを確認してください。
|
|
65
66
|
```
|
|
66
|
-
pip install
|
|
67
|
+
pip install
|
|
67
68
|
```
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
**プロジェクトのビルド**
|
|
70
|
+
|
|
71
|
+
プロジェクトディレクトリ上で、以下のコマンドを実行してください(名前は自由)
|
|
72
|
+
もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
$ python -m nexom start-project
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
以下の構成でプロジェクトが生成されます。
|
|
79
|
+
|
|
70
80
|
```
|
|
71
|
-
|
|
81
|
+
banana_project/
|
|
82
|
+
├─ app/
|
|
83
|
+
│ ├─ pages/
|
|
84
|
+
│ │ ├─ __init__.py
|
|
85
|
+
│ │ ├─ _templates.py
|
|
86
|
+
│ │ └─ * pages *
|
|
87
|
+
│ ├─ static/
|
|
88
|
+
│ │ └─ * static items *
|
|
89
|
+
│ ├─ templates/
|
|
90
|
+
│ │ └─ * html files *
|
|
91
|
+
│ ├─ __init__.py
|
|
92
|
+
│ ├─ config.py
|
|
93
|
+
│ ├─ gunicorn.conf.py
|
|
94
|
+
│ ├─ router.py
|
|
95
|
+
│ └─ wsgi.py
|
|
96
|
+
├─ auth/
|
|
97
|
+
│ ├─ __init__.py
|
|
98
|
+
│ ├─ config.py
|
|
99
|
+
│ ├─ gunicorn.conf.py
|
|
100
|
+
│ └─ wsgi.py
|
|
101
|
+
└─ data/
|
|
102
|
+
├─ log/
|
|
103
|
+
│ └─ * app logs *
|
|
104
|
+
├─ db/
|
|
105
|
+
│ └─ * app db *
|
|
106
|
+
└─ gateway/
|
|
107
|
+
├─ app.nginx.conf
|
|
108
|
+
└─ app.apache.conf
|
|
72
109
|
```
|
|
73
110
|
|
|
74
111
|
### 3.起動
|
|
75
112
|
以下のコマンドを起動します。
|
|
76
113
|
```
|
|
77
|
-
|
|
114
|
+
$ python -m nexom run
|
|
78
115
|
```
|
|
79
116
|
ブラウザからアクセスできるようになります。
|
|
80
117
|
デフォルトのポートは8080です。
|
|
81
|
-
|
|
118
|
+
|
|
119
|
+
[https://localhost:8080](https://localhost:8080)
|
|
120
|
+
|
|
82
121
|
ポートなどの設定は `config.py` から変更してください。
|
|
83
122
|
|
|
84
123
|
## Nginx等使用して外部公開する
|
|
85
|
-
|
|
124
|
+
gatewayディレクトリにある設定を読み込んでください
|
|
86
125
|
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
server_name nexom.ceez7.com;
|
|
90
|
-
|
|
91
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
92
|
-
|
|
93
|
-
location / {
|
|
94
|
-
proxy_pass http://localhost:8080;
|
|
95
|
-
}
|
|
126
|
+
http {
|
|
127
|
+
include /home/ubuntu/banana_project/gateway/*.conf;
|
|
96
128
|
}
|
|
97
129
|
```
|
|
98
130
|
|
|
99
131
|
## Systemdに登録して自動起動する
|
|
100
132
|
**Ubuntuの場合**
|
|
101
|
-
1. `/etc/systemd/system` に、 `
|
|
102
|
-
2. `
|
|
133
|
+
1. `/etc/systemd/system` に、 `banana_sample.service` を作成します。
|
|
134
|
+
2. `banana_sample.service` に以下を書き込みます。(これは一例です。環境に合わせて設定してください。)
|
|
103
135
|
|
|
104
|
-
サーバーのディレクトリが `/home/ubuntu/
|
|
136
|
+
サーバーのディレクトリが `/home/ubuntu/banana_project` にある場合
|
|
105
137
|
```
|
|
106
138
|
[Unit]
|
|
107
139
|
Description=Nexom Web Freamework
|
|
@@ -110,9 +142,11 @@ After=network.target
|
|
|
110
142
|
[Service]
|
|
111
143
|
User=www-data
|
|
112
144
|
Group=www-data
|
|
113
|
-
WorkingDirectory=/home/ubuntu/
|
|
114
|
-
Environment="
|
|
115
|
-
ExecStart=/home/ubuntu/
|
|
145
|
+
WorkingDirectory=/home/ubuntu/banana_project
|
|
146
|
+
Environment="PYTHONPATH=/home/ubuntu/banana_project"
|
|
147
|
+
ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn sample.wsgi:app --config sample/gunicorn.conf.py
|
|
148
|
+
Restart=always
|
|
149
|
+
RestartSec=3
|
|
116
150
|
[Install]
|
|
117
151
|
WantedBy=multi-user.target
|
|
118
152
|
```
|
|
@@ -120,23 +154,12 @@ WantedBy=multi-user.target
|
|
|
120
154
|
以下のコマンドを実行します
|
|
121
155
|
```
|
|
122
156
|
sudo systemd daemon-reload
|
|
123
|
-
sudo systemd enable
|
|
124
|
-
sudo systemd start
|
|
157
|
+
sudo systemd enable banana_sample
|
|
158
|
+
sudo systemd start banana_sample
|
|
125
159
|
```
|
|
126
160
|
|
|
127
|
-
###
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
/home/ubuntu/BananaProject/
|
|
131
|
-
└─ web/
|
|
132
|
-
├─ banana1 (Nexomサーバー)/
|
|
133
|
-
│ └─ wsgi.py
|
|
134
|
-
├─ banana2 (Nexomサーバー)/
|
|
135
|
-
│ └─ wsgi.py
|
|
136
|
-
└─ banana3 (Nexomサーバー)/
|
|
137
|
-
└─ wsgi.py
|
|
138
|
-
```
|
|
139
|
-
この構成の場合、テンプレートユニットを活用し .service ファイルを一枚にまとめられます。
|
|
161
|
+
### テンプレートユニットを活用して複数のアプリを効率的に管理
|
|
162
|
+
テンプレートユニットを活用し .service ファイルを一枚にまとめられます。
|
|
140
163
|
|
|
141
164
|
`/etc/systemd/system/banana-project@.service`
|
|
142
165
|
```
|
|
@@ -147,9 +170,11 @@ After=network.target
|
|
|
147
170
|
[Service]
|
|
148
171
|
User=www-data
|
|
149
172
|
Group=www-data
|
|
150
|
-
WorkingDirectory=/home/ubuntu/
|
|
151
|
-
Environment="
|
|
152
|
-
ExecStart=/home/ubuntu/
|
|
173
|
+
WorkingDirectory=/home/ubuntu/banana_project
|
|
174
|
+
Environment="PYTHONPATH=/home/ubuntu/banana_project"
|
|
175
|
+
ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn %iwsgi:app --config %i/gunicorn.conf.py
|
|
176
|
+
Restart=always
|
|
177
|
+
RestartSec=3
|
|
153
178
|
[Install]
|
|
154
179
|
WantedBy=multi-user.target
|
|
155
180
|
```
|
|
@@ -165,4 +190,4 @@ sudo systemd start banana-project@banana2
|
|
|
165
190
|
sudo systemd start banana-project@banana3
|
|
166
191
|
```
|
|
167
192
|
|
|
168
|
-
2026 1/
|
|
193
|
+
2026 1/25
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
nexom/__init__.py,sha256=V6US1i4gO-EOWsoHEgxzwbkrLPnzPhSn6TYue3uVsBA,367
|
|
2
|
+
nexom/__main__.py,sha256=VKT7WSe6552_mzwLwJqa55tfag5Olr28eYVhVnf9kWY,6196
|
|
3
|
+
nexom/app/__init__.py,sha256=meq2MgHUNgcjVn4V3dzm52EIlrGeIdNS-09sGLhita4,1090
|
|
4
|
+
nexom/app/auth.py,sha256=DQ8xM1xhHFMcZf22ZYAqItyT1quAz8mR2pJu-FdBHXI,10028
|
|
5
|
+
nexom/app/cookie.py,sha256=VCau9i8z6QlkaE_s8gKZXjcFtrV2bX1T4xssNtpJ5A0,2026
|
|
6
|
+
nexom/app/db.py,sha256=gUJOlUJqDaHCYU5JkzGV_wf_OTvFlqDWvM7vJDNVulY,2816
|
|
7
|
+
nexom/app/http_status_codes.py,sha256=R4ka3n4rijqvfahF5n5kS-Qrg8bZSsrvF8lGnpKWAgY,1934
|
|
8
|
+
nexom/app/middleware.py,sha256=7bHGtEem92QhgULOvTFDFlZ4K719CQgu9RKj1g7XOW8,1429
|
|
9
|
+
nexom/app/path.py,sha256=o7HUr_p4oRLhXo7YAD8jqgXVkrrRW6KUoY2unAI7s1Y,6007
|
|
10
|
+
nexom/app/request.py,sha256=4dvcfrrS9gKzVFtoizRw5eFvP7eHRXsavh21zEHXX2U,8867
|
|
11
|
+
nexom/app/response.py,sha256=qmLm8wCcexLjUIj8DaOBxt0cK3_J4Rn6DuWn6wkE7cE,4299
|
|
12
|
+
nexom/app/template.py,sha256=4V4YSaZ92Gq76lj6HgPaF7obvvzmM42Gh8f0e5oAIzM,3587
|
|
13
|
+
nexom/app/user.py,sha256=6KLLsb08Ma39CnLBbq5y290o33tfxtHFWu9lu1kT0NM,623
|
|
14
|
+
nexom/assets/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
nexom/assets/app/config.py,sha256=Ltpj40PE1--s0eRPTHiJNFqG8pFA7Lb6x02C39kwoYA,765
|
|
16
|
+
nexom/assets/app/gunicorn.conf.py,sha256=0kAQ7ddfpnPpqLAZxIXqYPF6EuUzkjIC9aOTqfxn6rc,149
|
|
17
|
+
nexom/assets/app/router.py,sha256=6VplXBlyvdsN144zy165sA3NZuvguMy6oO-mR0ebM2U,320
|
|
18
|
+
nexom/assets/app/wsgi.py,sha256=o-GtCPPHKiavTOmr8qxqCY95iUFU_IvRmwLqLK3ecwU,1743
|
|
19
|
+
nexom/assets/app/__pycache__/__init__.cpython-313.pyc,sha256=4WFkUYDuBZdpaXyXHrp3g5nTjc1XtExGRIyTPUyCFGM,195
|
|
20
|
+
nexom/assets/app/pages/__init__.py,sha256=DlX9iwM39JaMKfzK4mbgjE2uVMX3ax0wd2mCVnpg0b4,61
|
|
21
|
+
nexom/assets/app/pages/_templates.py,sha256=3lz42xOzHodOhFnujMhOuMX6IBJjMXGQKmOZ8SVhgE4,190
|
|
22
|
+
nexom/assets/app/pages/default.py,sha256=Kmm8ud8Uh1BAIba28Zp3Wz6WsTTx7cQ6-t6RMkuL9qU,257
|
|
23
|
+
nexom/assets/app/pages/document.py,sha256=JI9ChJ2BTXFyOiCnm4PRUnOY1xaLHeOI1ZEqHMQ7zPI,245
|
|
24
|
+
nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc,sha256=p0AGZjUdMtwO8e3cnmA3_R0rz1G5UFZNvVNICSHK8g0,273
|
|
25
|
+
nexom/assets/app/static/dog.jpeg,sha256=qGEhcg48FxRLRISzbmXvw1qvfbdluC_ukM8ZrHg7_XE,6559
|
|
26
|
+
nexom/assets/app/static/style.css,sha256=mDKNWue0uRLdWB0w1RsMSn6h3tHsuTVLuk3xOOJl7X8,566
|
|
27
|
+
nexom/assets/app/templates/base.html,sha256=RVW_63gA1sr7pqNkfB6Djk5an_VFpowahDIHGjfV-Wk,349
|
|
28
|
+
nexom/assets/app/templates/default.html,sha256=EKG9NTYkXngdCiDodSI1Kuic_ZwVwdeRc3VLq6fX5UI,167
|
|
29
|
+
nexom/assets/app/templates/document.html,sha256=16ClimpeqhLnXFNa8nMdMOlXUu8JOw7XxfpjU9DdIFs,6243
|
|
30
|
+
nexom/assets/app/templates/footer.html,sha256=1NZbbarU-CQhs1OPs2MTzhnWu0h7YYiEKDIP_cgIl9I,98
|
|
31
|
+
nexom/assets/app/templates/header.html,sha256=VgkCtCVE1J-eGEYvbBgWSUU-QauEf6xuvweOE-84U9c,75
|
|
32
|
+
nexom/assets/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
+
nexom/assets/auth/config.py,sha256=YgwEDhTsaxOxaOhUVSw6meay8Nc50A3GXafzmSdnhWo,804
|
|
34
|
+
nexom/assets/auth/gunicorn.conf.py,sha256=PbCWHG-A2OCfL71G04XS9xr78aH_gg-1UpH2tJhTWUk,141
|
|
35
|
+
nexom/assets/auth/wsgi.py,sha256=sMTj_ei0w1skoR_-xBNpveGAhRKWANfd1UaAItXQFO8,1698
|
|
36
|
+
nexom/assets/auth/__pycache__/__init__.cpython-313.pyc,sha256=dRCVl1pZMRjC5NpwgaW4uanJl9l4J8u4gcLhOzVXOEk,196
|
|
37
|
+
nexom/assets/auth_page/login.html,sha256=dMF098lsctmpDWHZL_wSDcqaBSLquiSXzcBZrtc5Phg,3536
|
|
38
|
+
nexom/assets/auth_page/signup.html,sha256=1fjw5R02EDFk2pyxqaa7eDU83uKegnXAOVaBLgbfOd0,4014
|
|
39
|
+
nexom/assets/error_page/error.html,sha256=JFi47UVxcxef_TTt1hDOuo93_45uSWCfixOJCUQVTs4,1230
|
|
40
|
+
nexom/assets/gateway/apache_app.conf,sha256=_QeZ0BqpuZaJfBONurNTW1FqJ7-PmunPrfbzAJRP3Qg,370
|
|
41
|
+
nexom/assets/gateway/nginx_app.conf,sha256=PaHRPGjJEyNiUU9OZiXS9HQhGwSe1oosSZp-6lnlQO0,521
|
|
42
|
+
nexom/buildTools/__init__.py,sha256=FbaFEMRjOKHNqNR-KuEatZjwPhmJf1CDZmR2hSH7YGk,19
|
|
43
|
+
nexom/buildTools/build.py,sha256=DSmHUIHNrXCdLUogmfHvnl9PtO1QOfQyRU15F-HLztk,10782
|
|
44
|
+
nexom/buildTools/run.py,sha256=HpSlkrNPFW961qgHjzedjGogdIYRQddhL95g3PcbM5s,5384
|
|
45
|
+
nexom/core/__init__.py,sha256=_ohRDLTerW9deZyh0WEp-ZB2LExkLvM9f26MhEdcp8g,52
|
|
46
|
+
nexom/core/error.py,sha256=1xwAynes65OEjhO8ZFC2lm_u_LGOAm4-nfGK-IedKOo,6199
|
|
47
|
+
nexom/core/log.py,sha256=q0FYz1-kkTUHvNkEBW5V1zvUv1phMYchOqwAfUXGHQI,3016
|
|
48
|
+
nexom/core/object_html_render.py,sha256=4yT3Aihia4oG62gr1rqZd757wEXsu78mTCCpjpVE7JM,7027
|
|
49
|
+
nexom/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
+
nexom/templates/auth.py,sha256=eWThgPR4E7y7YFcQ6rFZaO6yPKGL2zIbBC4SuzQ5M44,2332
|
|
51
|
+
nexom-1.0.1.dist-info/licenses/LICENSE,sha256=YbcHyxYLJ5jePeMS_NXpR9yiZjP5skhn32LvcKeknJw,1066
|
|
52
|
+
nexom-1.0.1.dist-info/METADATA,sha256=dacejsf9ca47t6GK-dBUEKT1EaEjxuwXKwmaJ4pTUPQ,5856
|
|
53
|
+
nexom-1.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
54
|
+
nexom-1.0.1.dist-info/entry_points.txt,sha256=0r1egKZmF1MUo25AKPt-2d55sk5Q_EIBOQwD3JC8RgI,46
|
|
55
|
+
nexom-1.0.1.dist-info/top_level.txt,sha256=mTyUruscL3rqXvYJRo8KGwDM6PWXRzgf4CamLr8LSX4,6
|
|
56
|
+
nexom-1.0.1.dist-info/RECORD,,
|
nexom/assets/server/config.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Nexom server settings.
|
|
3
|
-
|
|
4
|
-
This file is generated by Nexom buildTools.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# ======== module ========
|
|
13
|
-
# Project root directory
|
|
14
|
-
directory: str = "{pwd_dir}"
|
|
15
|
-
|
|
16
|
-
# ======== gunicorn ========
|
|
17
|
-
_address: str = "{g_address}"
|
|
18
|
-
_port: int = {g_port}
|
|
19
|
-
_workers: int = {g_workers}
|
|
20
|
-
_reload: bool = {g_reload}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def project_path(*parts: str) -> str:
|
|
24
|
-
"""
|
|
25
|
-
Build an absolute path under the project directory.
|
|
26
|
-
"""
|
|
27
|
-
return str(Path(directory, *parts))
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import sys
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
# Ensure config.py in the same directory is importable
|
|
8
|
-
ROOT = Path(__file__).resolve().parent
|
|
9
|
-
if str(ROOT) not in sys.path:
|
|
10
|
-
sys.path.insert(0, str(ROOT))
|
|
11
|
-
|
|
12
|
-
from config import _address, _port, _workers, _reload # noqa: E402
|
|
13
|
-
|
|
14
|
-
bind = f"{_address}:{_port}"
|
|
15
|
-
workers = int(_workers)
|
|
16
|
-
reload = bool(_reload)
|
|
Binary file
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
from nexom.web.template import ObjectHTMLTemplates
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# templates/ directory is located at: <project_root>/templates
|
|
9
|
-
TEMPLATES_DIR = (Path(__file__).resolve().parent.parent / "templates").resolve()
|
|
10
|
-
|
|
11
|
-
templates = ObjectHTMLTemplates(base_dir=str(TEMPLATES_DIR))
|
nexom/assets/server/router.py
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import pathlib as plib
|
|
4
|
-
|
|
5
|
-
from nexom.web.path import Path, Static, Pathlib
|
|
6
|
-
|
|
7
|
-
from pages import default, document
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Project root directory (where this file exists)
|
|
11
|
-
ROOT = plib.Path(__file__).resolve().parent
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
routing = Pathlib(
|
|
15
|
-
Path("", default.main, "DefaultPage"),
|
|
16
|
-
Path("doc/", document.main, "DocumentPage"),
|
|
17
|
-
Static("static/", str(ROOT / "static"), "StaticFiles"),
|
|
18
|
-
)
|
nexom/assets/server/wsgi.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Callable, Iterable
|
|
4
|
-
|
|
5
|
-
from nexom.web.request import Request
|
|
6
|
-
from nexom.web.response import Response, ErrorResponse
|
|
7
|
-
from nexom.core.error import PathNotFoundError
|
|
8
|
-
|
|
9
|
-
# Project-local router
|
|
10
|
-
from router import routing
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def app(environ: dict, start_response: Callable) -> Iterable[bytes]:
|
|
14
|
-
"""
|
|
15
|
-
WSGI application entrypoint.
|
|
16
|
-
"""
|
|
17
|
-
try:
|
|
18
|
-
request = Request(environ)
|
|
19
|
-
path = request.path
|
|
20
|
-
|
|
21
|
-
p = routing.get(path)
|
|
22
|
-
res = p.call_handler(request)
|
|
23
|
-
|
|
24
|
-
except PathNotFoundError as e:
|
|
25
|
-
res = ErrorResponse(404, str(e))
|
|
26
|
-
except Exception as e:
|
|
27
|
-
res = ErrorResponse(500, str(e))
|
|
28
|
-
|
|
29
|
-
start_response(res.status_text, res.headers)
|
|
30
|
-
return [res.body]
|
nexom/engine/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from . import object_html_render
|