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.
Files changed (71) hide show
  1. {nexom-1.0.5/src/Nexom.egg-info → nexom-1.0.6}/PKG-INFO +6 -5
  2. {nexom-1.0.5 → nexom-1.0.6}/README.md +5 -4
  3. {nexom-1.0.5 → nexom-1.0.6}/pyproject.toml +1 -1
  4. {nexom-1.0.5 → nexom-1.0.6/src/Nexom.egg-info}/PKG-INFO +6 -5
  5. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/__init__.py +1 -1
  6. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/auth.py +39 -24
  7. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/path.py +1 -1
  8. nexom-1.0.6/src/nexom/assets/app/pages/default.py +25 -0
  9. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/router.py +4 -1
  10. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/static/style.css +56 -6
  11. nexom-1.0.6/src/nexom/assets/app/templates/default.html +18 -0
  12. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/document.html +11 -21
  13. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/header.html +2 -2
  14. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/buildTools/build.py +6 -0
  15. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/templates/auth.py +3 -3
  16. nexom-1.0.5/src/nexom/assets/app/pages/default.py +0 -10
  17. nexom-1.0.5/src/nexom/assets/app/templates/default.html +0 -11
  18. {nexom-1.0.5 → nexom-1.0.6}/LICENSE +0 -0
  19. {nexom-1.0.5 → nexom-1.0.6}/setup.cfg +0 -0
  20. {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/SOURCES.txt +0 -0
  21. {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/dependency_links.txt +0 -0
  22. {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/entry_points.txt +0 -0
  23. {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/requires.txt +0 -0
  24. {nexom-1.0.5 → nexom-1.0.6}/src/Nexom.egg-info/top_level.txt +0 -0
  25. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/__main__.py +0 -0
  26. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/__init__.py +0 -0
  27. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/cookie.py +0 -0
  28. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/db.py +0 -0
  29. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/http_status_codes.py +0 -0
  30. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/middleware.py +0 -0
  31. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/request.py +0 -0
  32. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/response.py +0 -0
  33. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/template.py +0 -0
  34. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/app/user.py +0 -0
  35. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/__init__.py +0 -0
  36. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/__pycache__/__init__.cpython-313.pyc +0 -0
  37. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/config.py +0 -0
  38. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/gunicorn.conf.py +0 -0
  39. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/__init__.py +0 -0
  40. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc +0 -0
  41. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/_templates.py +0 -0
  42. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/pages/document.py +0 -0
  43. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/static/dog.jpeg +0 -0
  44. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/static/github.png +0 -0
  45. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/base.html +0 -0
  46. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/templates/footer.html +0 -0
  47. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/app/wsgi.py +0 -0
  48. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/__init__.py +0 -0
  49. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/__pycache__/__init__.cpython-313.pyc +0 -0
  50. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/config.py +0 -0
  51. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/gunicorn.conf.py +0 -0
  52. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth/wsgi.py +0 -0
  53. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth_page/login.html +0 -0
  54. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/auth_page/signup.html +0 -0
  55. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/error_page/error.html +0 -0
  56. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/gateway/apache_app.conf +0 -0
  57. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/assets/gateway/nginx_app.conf +0 -0
  58. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/buildTools/__init__.py +0 -0
  59. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/buildTools/run.py +0 -0
  60. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/__init__.py +0 -0
  61. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/error.py +0 -0
  62. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/log.py +0 -0
  63. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/core/object_html_render.py +0 -0
  64. {nexom-1.0.5 → nexom-1.0.6}/src/nexom/templates/__init__.py +0 -0
  65. {nexom-1.0.5 → nexom-1.0.6}/tests/test_buildtools.py +0 -0
  66. {nexom-1.0.5 → nexom-1.0.6}/tests/test_http_status_codes.py +0 -0
  67. {nexom-1.0.5 → nexom-1.0.6}/tests/test_middleware.py +0 -0
  68. {nexom-1.0.5 → nexom-1.0.6}/tests/test_path_routing.py +0 -0
  69. {nexom-1.0.5 → nexom-1.0.6}/tests/test_request.py +0 -0
  70. {nexom-1.0.5 → nexom-1.0.6}/tests/test_response.py +0 -0
  71. {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.5
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
- [https://localhost:8080](https://localhost:8080)
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/27
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
- [https://localhost:8080](https://localhost:8080)
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/27
158
+ 2026 1/28
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "Nexom"
7
- version = "1.0.5"
7
+ version = "1.0.6"
8
8
  description = "Lightweight Python Web Framework (WSGI)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Nexom
3
- Version: 1.0.5
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
- [https://localhost:8080](https://localhost:8080)
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/27
195
+ 2026 1/28
@@ -16,4 +16,4 @@ __all__ = [
16
16
  "__version__",
17
17
  ]
18
18
 
19
- __version__ = "0.1.2"
19
+ __version__ = "1.0.6"
@@ -76,15 +76,25 @@ KEY_NAME = "_nxt"
76
76
  # --------------------
77
77
 
78
78
  @dataclass
79
- class Session:
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
- sess = self.dbm.login(
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
- "user_id": sess.user_id,
170
- "token": sess.token,
171
- "expires_at": sess.expires_at,
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
- sess = self.dbm.verify(token)
190
- if not sess:
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
- "user_id": sess.user_id,
197
- "expires_at": sess.expires_at,
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) -> tuple[str, str, int]:
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["token"]), str(d["user_id"]), int(d["expires_at"])
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, *, token: str) -> tuple[bool, Optional[str], Optional[int]]:
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 True, str(d["user_id"]), int(d["expires_at"])
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
- # active False は正常系扱い
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) -> Session:
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, uid_text, pw_hash, salt, active = rows[0]
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 Session(sid, uid, uid_text, token, exp, None, user_agent)
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) -> Session | 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 Session(str(sid), str(uid), str(user_id), str(token), int(exp), None, ua)
451
+ return LocalSession(str(sid), str(uid), str(user_id), str(public_name), str(token), int(exp), None, ua)
@@ -84,7 +84,7 @@ class Path:
84
84
  return res
85
85
 
86
86
  except TypeError as e:
87
- # handler の引数不足だけは明示的に
87
+ # handler の引数不足
88
88
  if re.search(r"takes \d+ positional arguments? but \d+ were given", str(e)):
89
89
  raise PathHandlerMissingArgError()
90
90
  raise
@@ -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-border: var(--s2);
524
- --regular-border: var(--s3);
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-border);
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-border);
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-border);
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
- }/*# sourceMappingURL=style.css.map */
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="https://localhost:8080">https://localhost:8080</a></p>
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>
@@ -5,5 +5,5 @@
5
5
  <img src="/static/github.png" alt="GitHub Link">
6
6
  </a>
7
7
  </div>
8
- <div class="header-speacer"></div>
9
- </div>
8
+ </div>
9
+ <div class="header-speacer"></div>
@@ -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
- token, user_id, exp = self.client.login(
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=exp)
80
- return JsonResponse({"ok": True, "user_id": user_id, "token": token, "expires_at": exp}, cookie=str(set_cookie))
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,10 +0,0 @@
1
- from nexom.app.request import Request
2
- from nexom.app.response import Response
3
-
4
- from ._templates import templates
5
-
6
-
7
- def main(request: Request, args: dict) -> Response:
8
- return Response(
9
- templates.render("default", title="Nexom Default Page")
10
- )
@@ -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