Nexom 1.0.5__tar.gz → 1.0.6__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.
- {nexom-1.0.5/src/Nexom.egg-info → nexom-1.0.6}/PKG-INFO +6 -5
- {nexom-1.0.5 → nexom-1.0.6}/README.md +5 -4
- {nexom-1.0.5 → nexom-1.0.6}/pyproject.toml +1 -1
- {nexom-1.0.5 → nexom-1.0.6/src/Nexom.egg-info}/PKG-INFO +6 -5
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/__init__.py +1 -1
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/auth.py +39 -24
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/path.py +1 -1
- nexom-1.0.6/src/nexom/assets/app/pages/default.py +25 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/router.py +4 -1
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/static/style.css +56 -6
- nexom-1.0.6/src/nexom/assets/app/templates/default.html +18 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/document.html +11 -21
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/header.html +2 -2
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/buildTools/build.py +6 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/templates/auth.py +3 -3
- nexom-1.0.5/src/nexom/assets/app/pages/default.py +0 -10
- nexom-1.0.5/src/nexom/assets/app/templates/default.html +0 -11
- {nexom-1.0.5 → nexom-1.0.6}/LICENSE +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/setup.cfg +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/SOURCES.txt +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/dependency_links.txt +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/entry_points.txt +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/requires.txt +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/top_level.txt +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/__main__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/cookie.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/db.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/http_status_codes.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/middleware.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/request.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/response.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/template.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/user.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/__pycache__/__init__.cpython-313.pyc +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/config.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/gunicorn.conf.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/_templates.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/document.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/static/dog.jpeg +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/static/github.png +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/base.html +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/footer.html +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/wsgi.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/__pycache__/__init__.cpython-313.pyc +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/config.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/gunicorn.conf.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/wsgi.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth_page/login.html +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth_page/signup.html +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/error_page/error.html +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/gateway/apache_app.conf +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/gateway/nginx_app.conf +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/buildTools/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/buildTools/run.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/error.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/log.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/object_html_render.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/src/nexom/templates/__init__.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_buildtools.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_http_status_codes.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_middleware.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_path_routing.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_request.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_response.py +0 -0
- {nexom-1.0.5 → nexom-1.0.6}/tests/test_static.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Nexom
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: Lightweight Python Web Framework (WSGI)
|
|
5
5
|
Author: TouriAida
|
|
6
6
|
License: MIT License
|
|
@@ -69,11 +69,12 @@ pip install
|
|
|
69
69
|
```
|
|
70
70
|
**プロジェクトのビルド**
|
|
71
71
|
|
|
72
|
-
プロジェクトディレクトリ上で、以下のコマンドを実行してください
|
|
72
|
+
プロジェクトディレクトリ上で、以下のコマンドを実行してください
|
|
73
|
+
|
|
73
74
|
もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
|
|
74
75
|
|
|
75
76
|
```
|
|
76
|
-
$ python -m nexom start-project
|
|
77
|
+
$ python -m nexom start-project # --gateway nginx or apache
|
|
77
78
|
```
|
|
78
79
|
|
|
79
80
|
以下の構成でプロジェクトが生成されます。
|
|
@@ -117,7 +118,7 @@ $ python -m nexom run
|
|
|
117
118
|
ブラウザからアクセスできるようになります。
|
|
118
119
|
デフォルトのポートは8080です。
|
|
119
120
|
|
|
120
|
-
[
|
|
121
|
+
[http://localhost:8080](http://localhost:8080)
|
|
121
122
|
|
|
122
123
|
ポートなどの設定は `config.py` から変更してください。
|
|
123
124
|
|
|
@@ -191,4 +192,4 @@ sudo systemd start banana-project@banana2
|
|
|
191
192
|
sudo systemd start banana-project@banana3
|
|
192
193
|
```
|
|
193
194
|
|
|
194
|
-
2026 1/
|
|
195
|
+
2026 1/28
|
|
@@ -32,11 +32,12 @@ pip install
|
|
|
32
32
|
```
|
|
33
33
|
**プロジェクトのビルド**
|
|
34
34
|
|
|
35
|
-
プロジェクトディレクトリ上で、以下のコマンドを実行してください
|
|
35
|
+
プロジェクトディレクトリ上で、以下のコマンドを実行してください
|
|
36
|
+
|
|
36
37
|
もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
|
|
37
38
|
|
|
38
39
|
```
|
|
39
|
-
$ python -m nexom start-project
|
|
40
|
+
$ python -m nexom start-project # --gateway nginx or apache
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
以下の構成でプロジェクトが生成されます。
|
|
@@ -80,7 +81,7 @@ $ python -m nexom run
|
|
|
80
81
|
ブラウザからアクセスできるようになります。
|
|
81
82
|
デフォルトのポートは8080です。
|
|
82
83
|
|
|
83
|
-
[
|
|
84
|
+
[http://localhost:8080](http://localhost:8080)
|
|
84
85
|
|
|
85
86
|
ポートなどの設定は `config.py` から変更してください。
|
|
86
87
|
|
|
@@ -154,4 +155,4 @@ sudo systemd start banana-project@banana2
|
|
|
154
155
|
sudo systemd start banana-project@banana3
|
|
155
156
|
```
|
|
156
157
|
|
|
157
|
-
2026 1/
|
|
158
|
+
2026 1/28
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Nexom
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: Lightweight Python Web Framework (WSGI)
|
|
5
5
|
Author: TouriAida
|
|
6
6
|
License: MIT License
|
|
@@ -69,11 +69,12 @@ pip install
|
|
|
69
69
|
```
|
|
70
70
|
**プロジェクトのビルド**
|
|
71
71
|
|
|
72
|
-
プロジェクトディレクトリ上で、以下のコマンドを実行してください
|
|
72
|
+
プロジェクトディレクトリ上で、以下のコマンドを実行してください
|
|
73
|
+
|
|
73
74
|
もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
|
|
74
75
|
|
|
75
76
|
```
|
|
76
|
-
$ python -m nexom start-project
|
|
77
|
+
$ python -m nexom start-project # --gateway nginx or apache
|
|
77
78
|
```
|
|
78
79
|
|
|
79
80
|
以下の構成でプロジェクトが生成されます。
|
|
@@ -117,7 +118,7 @@ $ python -m nexom run
|
|
|
117
118
|
ブラウザからアクセスできるようになります。
|
|
118
119
|
デフォルトのポートは8080です。
|
|
119
120
|
|
|
120
|
-
[
|
|
121
|
+
[http://localhost:8080](http://localhost:8080)
|
|
121
122
|
|
|
122
123
|
ポートなどの設定は `config.py` から変更してください。
|
|
123
124
|
|
|
@@ -191,4 +192,4 @@ sudo systemd start banana-project@banana2
|
|
|
191
192
|
sudo systemd start banana-project@banana3
|
|
192
193
|
```
|
|
193
194
|
|
|
194
|
-
2026 1/
|
|
195
|
+
2026 1/28
|
|
@@ -76,15 +76,25 @@ KEY_NAME = "_nxt"
|
|
|
76
76
|
# --------------------
|
|
77
77
|
|
|
78
78
|
@dataclass
|
|
79
|
-
class
|
|
79
|
+
class LocalSession:
|
|
80
80
|
sid: str
|
|
81
81
|
uid: str
|
|
82
82
|
user_id: str
|
|
83
|
+
public_name: str
|
|
83
84
|
token: str
|
|
84
85
|
expires_at: int
|
|
85
86
|
revoked_at: int | None
|
|
86
87
|
user_agent: str | None
|
|
87
88
|
|
|
89
|
+
@dataclass
|
|
90
|
+
class Session:
|
|
91
|
+
pid: str
|
|
92
|
+
user_id: str
|
|
93
|
+
public_name: str
|
|
94
|
+
token: str
|
|
95
|
+
expires_at: int
|
|
96
|
+
user_agent: str | None
|
|
97
|
+
|
|
88
98
|
|
|
89
99
|
# --------------------
|
|
90
100
|
# AuthService (API only)
|
|
@@ -131,7 +141,7 @@ class AuthService:
|
|
|
131
141
|
status = _status_for_auth_error(e.code)
|
|
132
142
|
return JsonResponse({"ok": False, "error": e.code}, status=status)
|
|
133
143
|
|
|
134
|
-
except Exception:
|
|
144
|
+
except Exception as e:
|
|
135
145
|
return JsonResponse({"ok": False, "error": "InternalError"}, status=500)
|
|
136
146
|
|
|
137
147
|
# ---- handlers ----
|
|
@@ -156,7 +166,7 @@ class AuthService:
|
|
|
156
166
|
user_id = str(data.get("user_id") or "").strip()
|
|
157
167
|
password = str(data.get("password") or "")
|
|
158
168
|
|
|
159
|
-
|
|
169
|
+
lsess = self.dbm.login(
|
|
160
170
|
user_id,
|
|
161
171
|
password,
|
|
162
172
|
user_agent=request.headers.get("user-agent"),
|
|
@@ -166,9 +176,12 @@ class AuthService:
|
|
|
166
176
|
return JsonResponse(
|
|
167
177
|
{
|
|
168
178
|
"ok": True,
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
179
|
+
"pid":lsess.uid,
|
|
180
|
+
"user_id": lsess.user_id,
|
|
181
|
+
"public_name":lsess.public_name,
|
|
182
|
+
"token": lsess.token,
|
|
183
|
+
"expires_at": lsess.expires_at,
|
|
184
|
+
"user_agent": lsess.user_agent
|
|
172
185
|
}
|
|
173
186
|
)
|
|
174
187
|
|
|
@@ -186,15 +199,18 @@ class AuthService:
|
|
|
186
199
|
return JsonResponse({"ok": False, "error": "MethodNotAllowed"}, status=405)
|
|
187
200
|
|
|
188
201
|
token = str((request.json() or {}).get("token") or "")
|
|
189
|
-
|
|
190
|
-
if not
|
|
202
|
+
lsess = self.dbm.verify(token)
|
|
203
|
+
if not lsess:
|
|
191
204
|
return JsonResponse({"active": False}, status=200)
|
|
192
205
|
|
|
193
206
|
return JsonResponse(
|
|
194
207
|
{
|
|
195
208
|
"active": True,
|
|
196
|
-
"
|
|
197
|
-
"
|
|
209
|
+
"pid":lsess.uid,
|
|
210
|
+
"user_id": lsess.user_id,
|
|
211
|
+
"public_name":lsess.public_name,
|
|
212
|
+
"expires_at": lsess.expires_at,
|
|
213
|
+
"user_agent": lsess.user_agent
|
|
198
214
|
},
|
|
199
215
|
status=200,
|
|
200
216
|
)
|
|
@@ -256,21 +272,20 @@ class AuthClient:
|
|
|
256
272
|
return
|
|
257
273
|
self._raise_from_error_code(str(d.get("error") or ""))
|
|
258
274
|
|
|
259
|
-
def login(self, *, user_id: str, password: str) ->
|
|
275
|
+
def login(self, *, user_id: str, password: str) -> Session:
|
|
260
276
|
d = self._post(self.login_url, {"user_id": user_id, "password": password})
|
|
261
277
|
if not d.get("ok"):
|
|
262
278
|
self._raise_from_error_code(str(d.get("error") or ""))
|
|
263
279
|
|
|
264
|
-
return str(d["
|
|
280
|
+
return Session(str(d["pid"]), str(d["user_id"]), str(d["public_name"]), str(d["token"]), int(d["expires_at"]), str(d["user_agent"]))
|
|
265
281
|
|
|
266
|
-
def verify_token(self,
|
|
282
|
+
def verify_token(self, token: str) -> Session | None:
|
|
267
283
|
d = self._post(self.verify_url, {"token": token})
|
|
268
284
|
|
|
269
285
|
if d.get("active") is True:
|
|
270
|
-
return
|
|
286
|
+
return Session(str(d["pid"]), str(d["user_id"]), str(d["public_name"]), token, int(d["expires_at"]), str(d["user_agent"]))
|
|
271
287
|
|
|
272
|
-
|
|
273
|
-
return False, None, None
|
|
288
|
+
return None
|
|
274
289
|
|
|
275
290
|
def logout(self, *, token: str) -> None:
|
|
276
291
|
d = self._post(self.logout_url, {"token": token})
|
|
@@ -367,20 +382,20 @@ class AuthDBM(DatabaseManager):
|
|
|
367
382
|
except Exception as e:
|
|
368
383
|
raise AuthServiceUnavailableError()
|
|
369
384
|
|
|
370
|
-
def login(self, user_id: str, password: str, *, user_agent: str | None, ttl_sec: int) ->
|
|
385
|
+
def login(self, user_id: str, password: str, *, user_agent: str | None, ttl_sec: int) -> LocalSession:
|
|
371
386
|
if not user_id:
|
|
372
387
|
raise AuthMissingFieldError("user_id")
|
|
373
388
|
if not password:
|
|
374
389
|
raise AuthMissingFieldError("password")
|
|
375
390
|
|
|
376
391
|
rows = self.execute(
|
|
377
|
-
"SELECT uid, user_id, password_hash, password_salt, is_active FROM users WHERE user_id=?",
|
|
392
|
+
"SELECT uid, user_id, public_name, password_hash, password_salt, is_active FROM users WHERE user_id=?",
|
|
378
393
|
user_id,
|
|
379
394
|
)
|
|
380
395
|
if not rows:
|
|
381
396
|
raise AuthInvalidCredentialsError()
|
|
382
397
|
|
|
383
|
-
uid,
|
|
398
|
+
uid, user_id, public_name, pw_hash, salt, active = rows[0]
|
|
384
399
|
if not active:
|
|
385
400
|
raise AuthUserDisabledError()
|
|
386
401
|
|
|
@@ -401,7 +416,7 @@ class AuthDBM(DatabaseManager):
|
|
|
401
416
|
user_agent,
|
|
402
417
|
)
|
|
403
418
|
|
|
404
|
-
return
|
|
419
|
+
return LocalSession(sid, uid, user_id, public_name, token, exp, None, user_agent)
|
|
405
420
|
|
|
406
421
|
def logout(self, token: str) -> None:
|
|
407
422
|
if not token:
|
|
@@ -413,13 +428,13 @@ class AuthDBM(DatabaseManager):
|
|
|
413
428
|
_token_hash(token),
|
|
414
429
|
)
|
|
415
430
|
|
|
416
|
-
def verify(self, token: str | None) ->
|
|
431
|
+
def verify(self, token: str | None) -> LocalSession | None:
|
|
417
432
|
if not token:
|
|
418
433
|
return None
|
|
419
434
|
|
|
420
435
|
rows = self.execute(
|
|
421
436
|
"""
|
|
422
|
-
SELECT s.sid, s.uid, u.user_id, s.expires_at, s.revoked_at, s.user_agent
|
|
437
|
+
SELECT s.sid, s.uid, u.user_id, u.public_name, s.expires_at, s.revoked_at, s.user_agent
|
|
423
438
|
FROM sessions s
|
|
424
439
|
JOIN users u ON u.uid=s.uid
|
|
425
440
|
WHERE s.token_hash=?
|
|
@@ -429,8 +444,8 @@ class AuthDBM(DatabaseManager):
|
|
|
429
444
|
if not rows:
|
|
430
445
|
return None
|
|
431
446
|
|
|
432
|
-
sid, uid, user_id, exp, rev, ua = rows[0]
|
|
447
|
+
sid, uid, user_id, public_name, exp, rev, ua = rows[0]
|
|
433
448
|
if rev or int(exp) <= _now():
|
|
434
449
|
return None
|
|
435
450
|
|
|
436
|
-
return
|
|
451
|
+
return LocalSession(str(sid), str(uid), str(user_id), str(public_name), str(token), int(exp), None, ua)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from nexom.app.request import Request
|
|
2
|
+
from nexom.app.response import Response, HtmlResponse
|
|
3
|
+
|
|
4
|
+
from nexom.app.auth import AuthClient, KEY_NAME
|
|
5
|
+
|
|
6
|
+
from __app_name__.config import AUTH_SERVER
|
|
7
|
+
from ._templates import templates
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(request: Request, args: dict) -> Response:
|
|
11
|
+
ac = AuthClient(AUTH_SERVER)
|
|
12
|
+
|
|
13
|
+
# Get login token from request cookies
|
|
14
|
+
token = request.cookie.get(KEY_NAME) if request.cookie else None
|
|
15
|
+
# Verify with the authentication server
|
|
16
|
+
session = ac.verify_token(token) if token else None
|
|
17
|
+
|
|
18
|
+
if session:
|
|
19
|
+
msg = f"Hello <i>{session.public_name}@{session.user_id}</i> San!!"
|
|
20
|
+
else:
|
|
21
|
+
msg = "Not Logined."
|
|
22
|
+
|
|
23
|
+
return HtmlResponse(
|
|
24
|
+
templates.render("default", title="Nexom Default Page", user_message=msg)
|
|
25
|
+
)
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from nexom.app.path import Get, Static, Router
|
|
4
|
+
from nexom.templates.auth import AuthPages
|
|
4
5
|
|
|
5
|
-
from .config import APP_DIR
|
|
6
|
+
from .config import APP_DIR, AUTH_SERVER
|
|
6
7
|
from .pages import default, document
|
|
7
8
|
|
|
8
9
|
routing = Router(
|
|
9
10
|
Get("", default.main, "DefaultPage"),
|
|
10
11
|
Get("doc/", document.main, "DocumentPage"),
|
|
11
12
|
Static("static/", APP_DIR + "/static", "StaticFiles"),
|
|
13
|
+
|
|
14
|
+
AuthPages("user/", AUTH_SERVER),
|
|
12
15
|
)
|
|
@@ -520,8 +520,8 @@ textarea,
|
|
|
520
520
|
}
|
|
521
521
|
|
|
522
522
|
:root {
|
|
523
|
-
--mini-
|
|
524
|
-
--regular-
|
|
523
|
+
--mini-radius: var(--s2);
|
|
524
|
+
--regular-radius: var(--s3);
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
:root {
|
|
@@ -545,7 +545,7 @@ pre {
|
|
|
545
545
|
padding-inline: var(--s2);
|
|
546
546
|
background-color: var(--hevy-dark);
|
|
547
547
|
color: var(--white);
|
|
548
|
-
border-radius: var(--mini-
|
|
548
|
+
border-radius: var(--mini-radius);
|
|
549
549
|
}
|
|
550
550
|
|
|
551
551
|
.header-wrapper {
|
|
@@ -565,7 +565,7 @@ pre {
|
|
|
565
565
|
justify-content: space-between;
|
|
566
566
|
align-items: center;
|
|
567
567
|
background: var(--hevy-dark);
|
|
568
|
-
border-radius: var(--mini-
|
|
568
|
+
border-radius: var(--mini-radius);
|
|
569
569
|
overflow: hidden;
|
|
570
570
|
}
|
|
571
571
|
.header-speacer {
|
|
@@ -625,12 +625,62 @@ main {
|
|
|
625
625
|
display: flex;
|
|
626
626
|
flex-direction: column;
|
|
627
627
|
justify-content: center;
|
|
628
|
+
gap: var(--s5);
|
|
628
629
|
align-items: center;
|
|
629
|
-
border-radius: var(--regular-
|
|
630
|
+
border-radius: var(--regular-radius);
|
|
630
631
|
overflow: hidden;
|
|
631
632
|
}
|
|
632
633
|
|
|
633
634
|
.article-container {
|
|
634
635
|
width: 600px;
|
|
635
636
|
max-width: 100%;
|
|
636
|
-
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.message-card{
|
|
640
|
+
text-align: center;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.accounts-card{
|
|
644
|
+
padding: var(--s2);
|
|
645
|
+
border: var(--light-dark) solid 1px;
|
|
646
|
+
border-radius: var(--regular-radius);
|
|
647
|
+
|
|
648
|
+
display: grid;
|
|
649
|
+
grid-template-columns: 1fr var(--s2) 1fr;
|
|
650
|
+
gap: var(--s1);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
#ac1{
|
|
654
|
+
grid-column: 1 / -1;
|
|
655
|
+
|
|
656
|
+
margin-block-end: var(--s1);
|
|
657
|
+
font-size: 1.2rem;
|
|
658
|
+
text-align: center;
|
|
659
|
+
}
|
|
660
|
+
#ac2{
|
|
661
|
+
grid-column: 1 / 2;
|
|
662
|
+
}
|
|
663
|
+
#ac3{
|
|
664
|
+
grid-column: 3 / -1;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.btn {
|
|
668
|
+
padding-block: var(--s2);
|
|
669
|
+
padding-inline: var(--s3);
|
|
670
|
+
|
|
671
|
+
border: var(--light-dark) solid 1px;
|
|
672
|
+
border-radius: var(--mini-radius);
|
|
673
|
+
|
|
674
|
+
color: var(--black);
|
|
675
|
+
text-decoration: none;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.btn:hover{
|
|
679
|
+
box-shadow: 0 0 15px var(--light-dark);
|
|
680
|
+
transition: .3s;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.btn-p{
|
|
684
|
+
background-color: var(--hevy-dark);
|
|
685
|
+
color: var(--white);
|
|
686
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<Extends base />
|
|
2
|
+
<Insert main>
|
|
3
|
+
<div class="thumbnail-container">
|
|
4
|
+
<div class="message-card">
|
|
5
|
+
<h1>Welcome Nexom v1.05 Deeeeeeeev</h1>
|
|
6
|
+
<p>How are you? I'm fine! Thank you!</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="accounts-card">
|
|
9
|
+
<div id="ac1"><b>{{ user_message }}</b></div>
|
|
10
|
+
<a id="ac2" class="btn btn-p" href="/user/signup">Signup</a>
|
|
11
|
+
<a id="ac3" class="btn" href="/user/login">Login</a>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="container">
|
|
15
|
+
<p><a href="/static/dog.jpeg">Dog🐕</a> or <a href="/doc">Doc📕</a></p>
|
|
16
|
+
</div>
|
|
17
|
+
</Insert>
|
|
18
|
+
|
|
@@ -19,16 +19,13 @@
|
|
|
19
19
|
cd banana_project
|
|
20
20
|
|
|
21
21
|
python -m venv venv
|
|
22
|
-
source venv/bin/activate
|
|
23
|
-
</code></pre><h3 id="2-pipでインストール-サーバーのビルド">2. pipでインストール、サーバーのビルド </h3>
|
|
22
|
+
source venv/bin/activate</code></pre><h3 id="2-pipでインストール-サーバーのビルド">2. pipでインストール、サーバーのビルド </h3>
|
|
24
23
|
<p><strong>インストール</strong></p>
|
|
25
24
|
<p>nexomをインストールします。</p>
|
|
26
|
-
<pre data-role="codeBlock" data-info="" class="language-text"><code>pip install
|
|
27
|
-
</code></pre><p><strong>プロジェクトのビルド</strong></p>
|
|
25
|
+
<pre data-role="codeBlock" data-info="" class="language-text"><code>pip install</code></pre><p><strong>プロジェクトのビルド</strong></p>
|
|
28
26
|
<p>プロジェクトディレクトリ上で、以下のコマンドを実行してください(名前は自由)<br>
|
|
29
27
|
もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください</p>
|
|
30
|
-
<pre data-role="codeBlock" data-info="" class="language-text"><code>$ python -m nexom start-project
|
|
31
|
-
</code></pre><p>以下の構成でプロジェクトが生成されます。</p>
|
|
28
|
+
<pre data-role="codeBlock" data-info="" class="language-text"><code>$ python -m nexom start-project</code></pre><p>以下の構成でプロジェクトが生成されます。</p>
|
|
32
29
|
<pre data-role="codeBlock" data-info="" class="language-text"><code>banana_project/
|
|
33
30
|
├─ app/
|
|
34
31
|
│ ├─ pages/
|
|
@@ -56,20 +53,17 @@ source venv/bin/activate
|
|
|
56
53
|
│ └─ * app db *
|
|
57
54
|
└─ gateway/
|
|
58
55
|
├─ app.nginx.conf
|
|
59
|
-
└─ app.apache.conf
|
|
60
|
-
</code></pre><h3 id="3起動">3.起動 </h3>
|
|
56
|
+
└─ app.apache.conf</code></pre><h3 id="3起動">3.起動 </h3>
|
|
61
57
|
<p>以下のコマンドを起動します。</p>
|
|
62
|
-
<pre data-role="codeBlock" data-info="" class="language-text"><code>$ python -m nexom run
|
|
63
|
-
</code></pre><p>ブラウザからアクセスできるようになります。<br>
|
|
58
|
+
<pre data-role="codeBlock" data-info="" class="language-text"><code>$ python -m nexom run</code></pre><p>ブラウザからアクセスできるようになります。<br>
|
|
64
59
|
デフォルトのポートは8080です。</p>
|
|
65
|
-
<p><a href="
|
|
60
|
+
<p><a href="http://localhost:8080">http://localhost:8080</a></p>
|
|
66
61
|
<p>ポートなどの設定は <code>config.py</code> から変更してください。</p>
|
|
67
62
|
<h2 id="nginx等使用して外部公開する">Nginx等使用して外部公開する </h2>
|
|
68
63
|
<p>gatewayディレクトリにある設定を読み込んでください</p>
|
|
69
64
|
<pre data-role="codeBlock" data-info="" class="language-text"><code>http {
|
|
70
65
|
include /home/ubuntu/banana_project/gateway/*.conf;
|
|
71
|
-
}
|
|
72
|
-
</code></pre><h2 id="systemdに登録して自動起動する">Systemdに登録して自動起動する </h2>
|
|
66
|
+
}</code></pre><h2 id="systemdに登録して自動起動する">Systemdに登録して自動起動する </h2>
|
|
73
67
|
<p><strong>Ubuntuの場合</strong></p>
|
|
74
68
|
<ol>
|
|
75
69
|
<li><code>/etc/systemd/system</code> に、 <code>banana_sample.service</code> を作成します。</li>
|
|
@@ -89,12 +83,10 @@ ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn sample.wsgi:app --config
|
|
|
89
83
|
Restart=always
|
|
90
84
|
RestartSec=3
|
|
91
85
|
[Install]
|
|
92
|
-
WantedBy=multi-user.target
|
|
93
|
-
</code></pre><p>以下のコマンドを実行します</p>
|
|
86
|
+
WantedBy=multi-user.target</code></pre><p>以下のコマンドを実行します</p>
|
|
94
87
|
<pre data-role="codeBlock" data-info="" class="language-text"><code>sudo systemd daemon-reload
|
|
95
88
|
sudo systemd enable banana_sample
|
|
96
|
-
sudo systemd start banana_sample
|
|
97
|
-
</code></pre><h3 id="テンプレートユニットを活用して複数のアプリを効率的に管理">テンプレートユニットを活用して複数のアプリを効率的に管理 </h3>
|
|
89
|
+
sudo systemd start banana_sample</code></pre><h3 id="テンプレートユニットを活用して複数のアプリを効率的に管理">テンプレートユニットを活用して複数のアプリを効率的に管理 </h3>
|
|
98
90
|
<p>テンプレートユニットを活用し .service ファイルを一枚にまとめられます。</p>
|
|
99
91
|
<p><code>/etc/systemd/system/banana-project@.service</code></p>
|
|
100
92
|
<pre data-role="codeBlock" data-info="" class="language-text"><code>[Unit]
|
|
@@ -110,8 +102,7 @@ ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn %iwsgi:app --config %i
|
|
|
110
102
|
Restart=always
|
|
111
103
|
RestartSec=3
|
|
112
104
|
[Install]
|
|
113
|
-
WantedBy=multi-user.target
|
|
114
|
-
</code></pre><pre data-role="codeBlock" data-info="" class="language-text"><code>sudo systemd daemon-reload
|
|
105
|
+
WantedBy=multi-user.target</code></pre><pre data-role="codeBlock" data-info="" class="language-text"><code>sudo systemd daemon-reload
|
|
115
106
|
|
|
116
107
|
sudo systemd enable banana-project@banana1
|
|
117
108
|
sudo systemd enable banana-project@banana2
|
|
@@ -119,7 +110,6 @@ sudo systemd enable banana-project@banana3
|
|
|
119
110
|
|
|
120
111
|
sudo systemd start banana-project@banana1
|
|
121
112
|
sudo systemd start banana-project@banana2
|
|
122
|
-
sudo systemd start banana-project@banana3
|
|
123
|
-
</code></pre><p>2026 1/27</p>
|
|
113
|
+
sudo systemd start banana-project@banana3</code></pre><p>2026 1/27</p>
|
|
124
114
|
</div>
|
|
125
115
|
</Insert>
|
|
@@ -168,6 +168,12 @@ def create_app(
|
|
|
168
168
|
pages_templates_enabled = _replace_many(pages_templates_text, {"__app_name__": app_name})
|
|
169
169
|
pages_templates_path.write_text(pages_templates_enabled, encoding="utf-8")
|
|
170
170
|
|
|
171
|
+
# pages/_templates.py
|
|
172
|
+
pages_templates_path = pages_dir / "default.py"
|
|
173
|
+
pages_templates_text = pages_templates_path.read_text(encoding="utf-8")
|
|
174
|
+
pages_templates_enabled = _replace_many(pages_templates_text, {"__app_name__": app_name})
|
|
175
|
+
pages_templates_path.write_text(pages_templates_enabled, encoding="utf-8")
|
|
176
|
+
|
|
171
177
|
# gateway config (optional; only if gateway/ exists OR gateway_config explicitly given)
|
|
172
178
|
if gateway_config:
|
|
173
179
|
gw = project_root / "gateway"
|
|
@@ -71,13 +71,13 @@ class LoginPage(Path):
|
|
|
71
71
|
|
|
72
72
|
try:
|
|
73
73
|
data = req.json() or {}
|
|
74
|
-
|
|
74
|
+
sess = self.client.login(
|
|
75
75
|
user_id=str(data.get("user_id") or ""),
|
|
76
76
|
password=str(data.get("password") or ""),
|
|
77
77
|
)
|
|
78
78
|
|
|
79
|
-
set_cookie = Cookie(KEY_NAME, token, Path="/", MaxAge=
|
|
80
|
-
return JsonResponse({"ok": True, "user_id": user_id, "token": token, "expires_at":
|
|
79
|
+
set_cookie = Cookie(KEY_NAME, sess.token, Path="/", MaxAge=sess.expires_at)
|
|
80
|
+
return JsonResponse({"ok": True, "user_id": sess.user_id, "token": sess.token, "expires_at": sess.expires_at}, cookie=str(set_cookie))
|
|
81
81
|
except NexomError as e:
|
|
82
82
|
return JsonResponse({"ok": False, "error": e.code}, status=_status_for_auth_error(e.code))
|
|
83
83
|
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
<Extends base />
|
|
2
|
-
<Insert main>
|
|
3
|
-
<div class="thumbnail-container">
|
|
4
|
-
<h1>Welcome Nexom v1.05 Deeeeeeeev</h1>
|
|
5
|
-
<p>How are you? I'm fine! Thank you!</p>
|
|
6
|
-
</div>
|
|
7
|
-
<div class="container">
|
|
8
|
-
<p><a href="/static/dog.jpeg">Dog🐕</a> or <a href="/doc">Doc📕</a></p>
|
|
9
|
-
</div>
|
|
10
|
-
</Insert>
|
|
11
|
-
|
|
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
|
|
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
|