Nexom 0.1.4__py3-none-any.whl → 1.0.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.
- 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.2.dist-info}/METADATA +76 -50
- nexom-1.0.2.dist-info/RECORD +56 -0
- {nexom-0.1.4.dist-info → nexom-1.0.2.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.2.dist-info}/entry_points.txt +0 -0
- {nexom-0.1.4.dist-info → nexom-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {nexom-0.1.4.dist-info → nexom-1.0.2.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.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Lightweight Python Web Framework (WSGI)
|
|
5
5
|
Author: TouriAida
|
|
6
6
|
License: MIT License
|
|
@@ -32,6 +32,7 @@ Keywords: wsgi,web,framework
|
|
|
32
32
|
Requires-Python: >=3.10
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
|
+
Requires-Dist: typing-extensions; python_version < "3.12"
|
|
35
36
|
Dynamic: license-file
|
|
36
37
|
|
|
37
38
|
|
|
@@ -44,64 +45,96 @@ Nexomは短いコードで最低限動作し、シンプルで理解のしやす
|
|
|
44
45
|
## はじめる
|
|
45
46
|
最初のサーバーを起動するには、3つの手順が必要です。
|
|
46
47
|
|
|
47
|
-
1.
|
|
48
|
-
2. nexomをpip
|
|
48
|
+
1. プロジェクトディレクトリを作成
|
|
49
|
+
2. nexomをpipでインストール、プロジェクトのビルド
|
|
49
50
|
3. 起動
|
|
50
51
|
|
|
51
|
-
### 1
|
|
52
|
+
### 1.プロジェクトディレクトリの作成
|
|
52
53
|
**準備**
|
|
53
|
-
|
|
54
|
+
|
|
55
|
+
用意していない場合はディレクトリを作成し、仮想環境も準備してください
|
|
54
56
|
```
|
|
55
|
-
mkdir
|
|
56
|
-
cd
|
|
57
|
+
mkdir banana_project
|
|
58
|
+
cd banana_project
|
|
57
59
|
|
|
58
60
|
python -m venv venv
|
|
59
61
|
source venv/bin/activate
|
|
60
62
|
```
|
|
61
|
-
### 2.
|
|
63
|
+
### 2. pipでインストール、サーバーのビルド
|
|
62
64
|
**インストール**
|
|
65
|
+
|
|
63
66
|
nexomをインストールします。
|
|
64
|
-
※まだベータ版のため、最新のバージョンを確認してください。
|
|
65
67
|
```
|
|
66
|
-
pip install
|
|
68
|
+
pip install
|
|
67
69
|
```
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
**プロジェクトのビルド**
|
|
71
|
+
|
|
72
|
+
プロジェクトディレクトリ上で、以下のコマンドを実行してください(名前は自由)
|
|
73
|
+
もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
$ python -m nexom start-project
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
以下の構成でプロジェクトが生成されます。
|
|
80
|
+
|
|
70
81
|
```
|
|
71
|
-
|
|
82
|
+
banana_project/
|
|
83
|
+
├─ app/
|
|
84
|
+
│ ├─ pages/
|
|
85
|
+
│ │ ├─ __init__.py
|
|
86
|
+
│ │ ├─ _templates.py
|
|
87
|
+
│ │ └─ * pages *
|
|
88
|
+
│ ├─ static/
|
|
89
|
+
│ │ └─ * static items *
|
|
90
|
+
│ ├─ templates/
|
|
91
|
+
│ │ └─ * html files *
|
|
92
|
+
│ ├─ __init__.py
|
|
93
|
+
│ ├─ config.py
|
|
94
|
+
│ ├─ gunicorn.conf.py
|
|
95
|
+
│ ├─ router.py
|
|
96
|
+
│ └─ wsgi.py
|
|
97
|
+
├─ auth/
|
|
98
|
+
│ ├─ __init__.py
|
|
99
|
+
│ ├─ config.py
|
|
100
|
+
│ ├─ gunicorn.conf.py
|
|
101
|
+
│ └─ wsgi.py
|
|
102
|
+
└─ data/
|
|
103
|
+
├─ log/
|
|
104
|
+
│ └─ * app logs *
|
|
105
|
+
├─ db/
|
|
106
|
+
│ └─ * app db *
|
|
107
|
+
└─ gateway/
|
|
108
|
+
├─ app.nginx.conf
|
|
109
|
+
└─ app.apache.conf
|
|
72
110
|
```
|
|
73
111
|
|
|
74
112
|
### 3.起動
|
|
75
113
|
以下のコマンドを起動します。
|
|
76
114
|
```
|
|
77
|
-
|
|
115
|
+
$ python -m nexom run
|
|
78
116
|
```
|
|
79
117
|
ブラウザからアクセスできるようになります。
|
|
80
118
|
デフォルトのポートは8080です。
|
|
81
|
-
|
|
119
|
+
|
|
120
|
+
[https://localhost:8080](https://localhost:8080)
|
|
121
|
+
|
|
82
122
|
ポートなどの設定は `config.py` から変更してください。
|
|
83
123
|
|
|
84
124
|
## Nginx等使用して外部公開する
|
|
85
|
-
|
|
125
|
+
gatewayディレクトリにある設定を読み込んでください
|
|
86
126
|
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
server_name nexom.ceez7.com;
|
|
90
|
-
|
|
91
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
92
|
-
|
|
93
|
-
location / {
|
|
94
|
-
proxy_pass http://localhost:8080;
|
|
95
|
-
}
|
|
127
|
+
http {
|
|
128
|
+
include /home/ubuntu/banana_project/gateway/*.conf;
|
|
96
129
|
}
|
|
97
130
|
```
|
|
98
131
|
|
|
99
132
|
## Systemdに登録して自動起動する
|
|
100
133
|
**Ubuntuの場合**
|
|
101
|
-
1. `/etc/systemd/system` に、 `
|
|
102
|
-
2. `
|
|
134
|
+
1. `/etc/systemd/system` に、 `banana_sample.service` を作成します。
|
|
135
|
+
2. `banana_sample.service` に以下を書き込みます。(これは一例です。環境に合わせて設定してください。)
|
|
103
136
|
|
|
104
|
-
サーバーのディレクトリが `/home/ubuntu/
|
|
137
|
+
サーバーのディレクトリが `/home/ubuntu/banana_project` にある場合
|
|
105
138
|
```
|
|
106
139
|
[Unit]
|
|
107
140
|
Description=Nexom Web Freamework
|
|
@@ -110,9 +143,11 @@ After=network.target
|
|
|
110
143
|
[Service]
|
|
111
144
|
User=www-data
|
|
112
145
|
Group=www-data
|
|
113
|
-
WorkingDirectory=/home/ubuntu/
|
|
114
|
-
Environment="
|
|
115
|
-
ExecStart=/home/ubuntu/
|
|
146
|
+
WorkingDirectory=/home/ubuntu/banana_project
|
|
147
|
+
Environment="PYTHONPATH=/home/ubuntu/banana_project"
|
|
148
|
+
ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn sample.wsgi:app --config sample/gunicorn.conf.py
|
|
149
|
+
Restart=always
|
|
150
|
+
RestartSec=3
|
|
116
151
|
[Install]
|
|
117
152
|
WantedBy=multi-user.target
|
|
118
153
|
```
|
|
@@ -120,23 +155,12 @@ WantedBy=multi-user.target
|
|
|
120
155
|
以下のコマンドを実行します
|
|
121
156
|
```
|
|
122
157
|
sudo systemd daemon-reload
|
|
123
|
-
sudo systemd enable
|
|
124
|
-
sudo systemd start
|
|
158
|
+
sudo systemd enable banana_sample
|
|
159
|
+
sudo systemd start banana_sample
|
|
125
160
|
```
|
|
126
161
|
|
|
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 ファイルを一枚にまとめられます。
|
|
162
|
+
### テンプレートユニットを活用して複数のアプリを効率的に管理
|
|
163
|
+
テンプレートユニットを活用し .service ファイルを一枚にまとめられます。
|
|
140
164
|
|
|
141
165
|
`/etc/systemd/system/banana-project@.service`
|
|
142
166
|
```
|
|
@@ -147,9 +171,11 @@ After=network.target
|
|
|
147
171
|
[Service]
|
|
148
172
|
User=www-data
|
|
149
173
|
Group=www-data
|
|
150
|
-
WorkingDirectory=/home/ubuntu/
|
|
151
|
-
Environment="
|
|
152
|
-
ExecStart=/home/ubuntu/
|
|
174
|
+
WorkingDirectory=/home/ubuntu/banana_project
|
|
175
|
+
Environment="PYTHONPATH=/home/ubuntu/banana_project"
|
|
176
|
+
ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn %iwsgi:app --config %i/gunicorn.conf.py
|
|
177
|
+
Restart=always
|
|
178
|
+
RestartSec=3
|
|
153
179
|
[Install]
|
|
154
180
|
WantedBy=multi-user.target
|
|
155
181
|
```
|
|
@@ -165,4 +191,4 @@ sudo systemd start banana-project@banana2
|
|
|
165
191
|
sudo systemd start banana-project@banana3
|
|
166
192
|
```
|
|
167
193
|
|
|
168
|
-
2026 1/
|
|
194
|
+
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.2.dist-info/licenses/LICENSE,sha256=YbcHyxYLJ5jePeMS_NXpR9yiZjP5skhn32LvcKeknJw,1066
|
|
52
|
+
nexom-1.0.2.dist-info/METADATA,sha256=Zk1zoBzcVBX5btwcMJm1D6jAlkoCWGt9RVj3-byZCng,5914
|
|
53
|
+
nexom-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
54
|
+
nexom-1.0.2.dist-info/entry_points.txt,sha256=0r1egKZmF1MUo25AKPt-2d55sk5Q_EIBOQwD3JC8RgI,46
|
|
55
|
+
nexom-1.0.2.dist-info/top_level.txt,sha256=mTyUruscL3rqXvYJRo8KGwDM6PWXRzgf4CamLr8LSX4,6
|
|
56
|
+
nexom-1.0.2.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
|