vibetuner 2.6.1__py3-none-any.whl → 2.7.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.

Potentially problematic release.


This version of vibetuner might be problematic. Click here for more details.

Files changed (85) hide show
  1. vibetuner/__init__.py +2 -0
  2. vibetuner/__main__.py +4 -0
  3. vibetuner/cli/__init__.py +68 -0
  4. vibetuner/cli/run.py +161 -0
  5. vibetuner/config.py +128 -0
  6. vibetuner/context.py +25 -0
  7. vibetuner/frontend/AGENTS.md +113 -0
  8. vibetuner/frontend/CLAUDE.md +113 -0
  9. vibetuner/frontend/__init__.py +94 -0
  10. vibetuner/frontend/context.py +10 -0
  11. vibetuner/frontend/deps.py +41 -0
  12. vibetuner/frontend/email.py +45 -0
  13. vibetuner/frontend/hotreload.py +13 -0
  14. vibetuner/frontend/lifespan.py +26 -0
  15. vibetuner/frontend/middleware.py +151 -0
  16. vibetuner/frontend/oauth.py +196 -0
  17. vibetuner/frontend/routes/__init__.py +12 -0
  18. vibetuner/frontend/routes/auth.py +150 -0
  19. vibetuner/frontend/routes/debug.py +414 -0
  20. vibetuner/frontend/routes/health.py +33 -0
  21. vibetuner/frontend/routes/language.py +43 -0
  22. vibetuner/frontend/routes/meta.py +55 -0
  23. vibetuner/frontend/routes/user.py +94 -0
  24. vibetuner/frontend/templates.py +176 -0
  25. vibetuner/logging.py +87 -0
  26. vibetuner/models/AGENTS.md +165 -0
  27. vibetuner/models/CLAUDE.md +165 -0
  28. vibetuner/models/__init__.py +14 -0
  29. vibetuner/models/blob.py +89 -0
  30. vibetuner/models/email_verification.py +84 -0
  31. vibetuner/models/mixins.py +76 -0
  32. vibetuner/models/oauth.py +57 -0
  33. vibetuner/models/registry.py +15 -0
  34. vibetuner/models/types.py +16 -0
  35. vibetuner/models/user.py +91 -0
  36. vibetuner/mongo.py +18 -0
  37. vibetuner/paths.py +112 -0
  38. vibetuner/services/AGENTS.md +104 -0
  39. vibetuner/services/CLAUDE.md +104 -0
  40. vibetuner/services/__init__.py +0 -0
  41. vibetuner/services/blob.py +175 -0
  42. vibetuner/services/email.py +50 -0
  43. vibetuner/tasks/AGENTS.md +98 -0
  44. vibetuner/tasks/CLAUDE.md +98 -0
  45. vibetuner/tasks/__init__.py +2 -0
  46. vibetuner/tasks/context.py +34 -0
  47. vibetuner/tasks/worker.py +18 -0
  48. vibetuner/templates/email/AGENTS.md +48 -0
  49. vibetuner/templates/email/CLAUDE.md +48 -0
  50. vibetuner/templates/email/default/magic_link.html.jinja +16 -0
  51. vibetuner/templates/email/default/magic_link.txt.jinja +5 -0
  52. vibetuner/templates/frontend/AGENTS.md +74 -0
  53. vibetuner/templates/frontend/CLAUDE.md +74 -0
  54. vibetuner/templates/frontend/base/favicons.html.jinja +1 -0
  55. vibetuner/templates/frontend/base/footer.html.jinja +3 -0
  56. vibetuner/templates/frontend/base/header.html.jinja +0 -0
  57. vibetuner/templates/frontend/base/opengraph.html.jinja +7 -0
  58. vibetuner/templates/frontend/base/skeleton.html.jinja +42 -0
  59. vibetuner/templates/frontend/debug/collections.html.jinja +103 -0
  60. vibetuner/templates/frontend/debug/components/debug_nav.html.jinja +55 -0
  61. vibetuner/templates/frontend/debug/index.html.jinja +83 -0
  62. vibetuner/templates/frontend/debug/info.html.jinja +256 -0
  63. vibetuner/templates/frontend/debug/users.html.jinja +137 -0
  64. vibetuner/templates/frontend/debug/version.html.jinja +53 -0
  65. vibetuner/templates/frontend/email/magic_link.txt.jinja +5 -0
  66. vibetuner/templates/frontend/email_sent.html.jinja +82 -0
  67. vibetuner/templates/frontend/index.html.jinja +19 -0
  68. vibetuner/templates/frontend/lang/select.html.jinja +4 -0
  69. vibetuner/templates/frontend/login.html.jinja +84 -0
  70. vibetuner/templates/frontend/meta/browserconfig.xml.jinja +10 -0
  71. vibetuner/templates/frontend/meta/robots.txt.jinja +3 -0
  72. vibetuner/templates/frontend/meta/site.webmanifest.jinja +7 -0
  73. vibetuner/templates/frontend/meta/sitemap.xml.jinja +6 -0
  74. vibetuner/templates/frontend/user/edit.html.jinja +85 -0
  75. vibetuner/templates/frontend/user/profile.html.jinja +156 -0
  76. vibetuner/templates/markdown/.placeholder +0 -0
  77. vibetuner/templates/markdown/AGENTS.md +29 -0
  78. vibetuner/templates/markdown/CLAUDE.md +29 -0
  79. vibetuner/templates.py +152 -0
  80. vibetuner/time.py +57 -0
  81. vibetuner/versioning.py +8 -0
  82. {vibetuner-2.6.1.dist-info → vibetuner-2.7.1.dist-info}/METADATA +2 -1
  83. vibetuner-2.7.1.dist-info/RECORD +84 -0
  84. vibetuner-2.6.1.dist-info/RECORD +0 -4
  85. {vibetuner-2.6.1.dist-info → vibetuner-2.7.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,256 @@
1
+ {% extends "base/skeleton.html.jinja" %}
2
+ {% block title %}
3
+ System Information - Debug
4
+ {% endblock title %}
5
+ {% block body %}
6
+ <div class="container mx-auto px-4 py-8 max-w-6xl">
7
+ <!-- Header -->
8
+ <header class="mb-8">
9
+ <h1 class="text-4xl font-bold text-base-content mb-2">System Information</h1>
10
+ <p class="text-base-content/70">Application configuration, runtime details, and session data</p>
11
+ </header>
12
+ <!-- Stats Overview -->
13
+ <div class="stats stats-vertical sm:stats-horizontal shadow-xl border border-base-200 mb-8 w-full">
14
+ <div class="stat">
15
+ <div class="stat-figure text-primary">
16
+ <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
17
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z">
18
+ </path>
19
+ </svg>
20
+ </div>
21
+ <div class="stat-title">Version</div>
22
+ <div class="stat-value text-primary">{{ version }}</div>
23
+ <div class="stat-desc">Build {{ v_hash[:8] }}</div>
24
+ </div>
25
+ <div class="stat">
26
+ <div class="stat-figure text-secondary">
27
+ <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
28
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129">
29
+ </path>
30
+ </svg>
31
+ </div>
32
+ <div class="stat-title">Languages</div>
33
+ <div class="stat-value text-secondary">{{ supported_languages | length }}</div>
34
+ <div class="stat-desc">{{ default_language }} default</div>
35
+ </div>
36
+ <div class="stat">
37
+ <div class="stat-figure">
38
+ {% if DEBUG %}
39
+ <div class="badge badge-warning gap-1">
40
+ <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
41
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z">
42
+ </path>
43
+ </svg>
44
+ DEBUG
45
+ </div>
46
+ {% else %}
47
+ <div class="badge badge-success gap-1">
48
+ <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
49
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z">
50
+ </path>
51
+ </svg>
52
+ PROD
53
+ </div>
54
+ {% endif %}
55
+ </div>
56
+ <div class="stat-title">Mode</div>
57
+ <div class="stat-value">{{ "Debug" if DEBUG else "Production" }}</div>
58
+ <div class="stat-desc">{{ "Development" if DEBUG else "Live" }} environment</div>
59
+ </div>
60
+ </div>
61
+ <!-- Project Configuration -->
62
+ <div class="card bg-base-100 shadow-xl border border-base-200 mb-6">
63
+ <div class="card-body">
64
+ <h2 class="card-title text-primary flex items-center gap-2 mb-6">
65
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
66
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z">
67
+ </path>
68
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
69
+ </svg>
70
+ Project Configuration
71
+ </h2>
72
+ <div class="overflow-x-auto">
73
+ <table class="table table-zebra">
74
+ <thead>
75
+ <tr>
76
+ <th class="font-bold">Setting</th>
77
+ <th class="font-bold">Value</th>
78
+ </tr>
79
+ </thead>
80
+ <tbody>
81
+ <tr>
82
+ <td>
83
+ <div class="flex items-center gap-2">
84
+ <div class="badge badge-ghost font-mono">Project Name</div>
85
+ </div>
86
+ </td>
87
+ <td>
88
+ <code class="text-sm bg-base-200 px-2 py-1 rounded">{{ project_name }}</code>
89
+ </td>
90
+ </tr>
91
+ <tr>
92
+ <td>
93
+ <div class="flex items-center gap-2">
94
+ <div class="badge badge-ghost font-mono">Project Slug</div>
95
+ </div>
96
+ </td>
97
+ <td>
98
+ <code class="text-sm bg-base-200 px-2 py-1 rounded">{{ project_slug }}</code>
99
+ </td>
100
+ </tr>
101
+ <tr>
102
+ <td>
103
+ <div class="flex items-center gap-2">
104
+ <div class="badge badge-ghost font-mono">Description</div>
105
+ </div>
106
+ </td>
107
+ <td>
108
+ <span class="text-sm">{{ project_description }}</span>
109
+ </td>
110
+ </tr>
111
+ <tr>
112
+ <td>
113
+ <div class="flex items-center gap-2">
114
+ <div class="badge badge-ghost font-mono">Copyright</div>
115
+ </div>
116
+ </td>
117
+ <td>
118
+ <span class="text-sm">{{ copyright }}</span>
119
+ </td>
120
+ </tr>
121
+ {% if umami_website_id %}
122
+ <tr>
123
+ <td>
124
+ <div class="flex items-center gap-2">
125
+ <div class="badge badge-ghost font-mono">Umami Website ID</div>
126
+ </div>
127
+ </td>
128
+ <td>
129
+ <code class="text-xs bg-base-200 px-2 py-1 rounded break-all">{{ umami_website_id }}</code>
130
+ </td>
131
+ </tr>
132
+ {% endif %}
133
+ </tbody>
134
+ </table>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ <!-- Runtime Information -->
139
+ <div class="card bg-base-100 shadow-xl border border-base-200 mb-6">
140
+ <div class="card-body">
141
+ <h2 class="card-title text-secondary flex items-center gap-2 mb-6">
142
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
143
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z">
144
+ </path>
145
+ </svg>
146
+ Runtime Information
147
+ </h2>
148
+ <div class="grid md:grid-cols-2 gap-6">
149
+ <div class="form-control">
150
+ <label class="label">
151
+ <span class="label-text font-medium">Current Language</span>
152
+ </label>
153
+ <div class="flex gap-2">
154
+ <div class="badge badge-primary badge-lg">{{ language }}</div>
155
+ </div>
156
+ </div>
157
+ <div class="form-control">
158
+ <label class="label">
159
+ <span class="label-text font-medium">Debug Status</span>
160
+ </label>
161
+ <div class="flex items-center gap-3">
162
+ {% if DEBUG %}
163
+ <div class="badge badge-warning gap-2">
164
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
165
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z">
166
+ </path>
167
+ </svg>
168
+ Debug Mode Active
169
+ </div>
170
+ {% else %}
171
+ <div class="badge badge-success gap-2">
172
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
173
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z">
174
+ </path>
175
+ </svg>
176
+ Production Mode
177
+ </div>
178
+ {% endif %}
179
+ </div>
180
+ </div>
181
+ <div class="form-control md:col-span-2">
182
+ <label class="label">
183
+ <span class="label-text font-medium">Supported Languages</span>
184
+ </label>
185
+ <div class="flex flex-wrap gap-2">
186
+ {% for lang in supported_languages %}
187
+ <div class="badge badge-outline {{ 'badge-primary' if lang == default_language else '' }}">
188
+ {{ lang }}
189
+ {% if lang == default_language %}
190
+ <svg class="w-3 h-3 ml-1"
191
+ fill="none"
192
+ stroke="currentColor"
193
+ viewBox="0 0 24 24">
194
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
195
+ </svg>
196
+ {% endif %}
197
+ </div>
198
+ {% endfor %}
199
+ </div>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ <!-- User Cookies -->
205
+ <div class="card bg-base-100 shadow-xl border border-base-200">
206
+ <div class="card-body">
207
+ <h2 class="card-title text-accent flex items-center gap-2 mb-6">
208
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
209
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">
210
+ </path>
211
+ </svg>
212
+ User Cookies
213
+ <div class="badge badge-neutral">{{ cookies | length if cookies else 0 }}</div>
214
+ </h2>
215
+ {% if cookies %}
216
+ <div class="overflow-x-auto">
217
+ <table class="table table-zebra">
218
+ <thead>
219
+ <tr>
220
+ <th class="font-bold">Cookie Name</th>
221
+ <th class="font-bold">Value</th>
222
+ </tr>
223
+ </thead>
224
+ <tbody>
225
+ {% for name, value in cookies.items() %}
226
+ <tr>
227
+ <td>
228
+ <div class="flex items-center gap-2">
229
+ <div class="badge badge-ghost font-mono">{{ name }}</div>
230
+ </div>
231
+ </td>
232
+ <td>
233
+ <code class="text-xs bg-base-200 px-2 py-1 rounded break-all">{{ value[:50] }}
234
+ {% if value|length > 50 %}...{% endif %}
235
+ </code>
236
+ </td>
237
+ </tr>
238
+ {% endfor %}
239
+ </tbody>
240
+ </table>
241
+ </div>
242
+ {% else %}
243
+ <div class="alert alert-info">
244
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
245
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z">
246
+ </path>
247
+ </svg>
248
+ <span>No cookies found in the current session</span>
249
+ </div>
250
+ {% endif %}
251
+ </div>
252
+ </div>
253
+ <!-- Debug Navigation Footer -->
254
+ {% include "debug/components/debug_nav.html.jinja" %}
255
+ </div>
256
+ {% endblock body %}
@@ -0,0 +1,137 @@
1
+ {% extends "base/skeleton.html.jinja" %}
2
+ {% block title %}
3
+ Debug - User Impersonation
4
+ {% endblock title %}
5
+ {% block body %}
6
+ <div class="container mx-auto px-4 py-8 max-w-4xl">
7
+ <!-- Header -->
8
+ <header class="mb-8">
9
+ <h1 class="text-4xl font-bold text-base-content mb-2">User Impersonation</h1>
10
+ <p class="text-base-content/70">Switch between users in debug mode for testing purposes</p>
11
+ <div class="alert alert-warning mt-4">
12
+ <svg xmlns="http://www.w3.org/2000/svg"
13
+ class="stroke-current shrink-0 h-6 w-6"
14
+ fill="none"
15
+ viewBox="0 0 24 24">
16
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z" />
17
+ </svg>
18
+ <span>⚠️ Debug mode only - This feature is disabled in production</span>
19
+ </div>
20
+ </header>
21
+ <!-- Current User Status -->
22
+ {% if current_user_id %}
23
+ <div class="card bg-primary text-primary-content shadow-xl mb-6">
24
+ <div class="card-body">
25
+ <h2 class="card-title">
26
+ <svg xmlns="http://www.w3.org/2000/svg"
27
+ class="h-6 w-6"
28
+ fill="none"
29
+ viewBox="0 0 24 24"
30
+ stroke="currentColor">
31
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
32
+ </svg>
33
+ Currently Impersonating
34
+ </h2>
35
+ <p class="opacity-90">
36
+ User ID: <code>{{ current_user_id }}</code>
37
+ </p>
38
+ <div class="card-actions justify-end">
39
+ <form method="post" action="/debug/stop-impersonation">
40
+ <button type="submit" class="btn btn-secondary btn-sm">Stop Impersonation</button>
41
+ </form>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ {% else %}
46
+ <div class="alert alert-info mb-6">
47
+ <svg xmlns="http://www.w3.org/2000/svg"
48
+ class="stroke-current shrink-0 h-6 w-6"
49
+ fill="none"
50
+ viewBox="0 0 24 24">
51
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
52
+ </svg>
53
+ <span>No user currently impersonated. Select a user below to impersonate.</span>
54
+ </div>
55
+ {% endif %}
56
+ <!-- Users List -->
57
+ <div class="card bg-base-100 shadow-xl">
58
+ <div class="card-body">
59
+ <h2 class="card-title text-2xl mb-4">
60
+ <svg xmlns="http://www.w3.org/2000/svg"
61
+ class="h-6 w-6"
62
+ fill="none"
63
+ viewBox="0 0 24 24"
64
+ stroke="currentColor">
65
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
66
+ </svg>
67
+ Available Users ({{ users | length }})
68
+ </h2>
69
+ {% if users %}
70
+ <div class="overflow-x-auto">
71
+ <table class="table table-zebra w-full">
72
+ <thead>
73
+ <tr>
74
+ <th>Email</th>
75
+ <th>Name</th>
76
+ <th>ID</th>
77
+ <th>Created</th>
78
+ <th class="text-center">Actions</th>
79
+ </tr>
80
+ </thead>
81
+ <tbody>
82
+ {% for user in users %}
83
+ <tr class="{% if current_user_id == user.id|string %}bg-primary/20{% endif %}">
84
+ <td>
85
+ <div class="flex items-center gap-2">
86
+ {% if current_user_id == user.id|string %}<div class="badge badge-primary badge-xs">CURRENT</div>{% endif %}
87
+ <span class="font-mono text-sm">{{ user.email or "No email" }}</span>
88
+ </div>
89
+ </td>
90
+ <td>
91
+ <span class="font-medium">{{ user.name or "No name" }}</span>
92
+ </td>
93
+ <td>
94
+ <code class="text-xs bg-base-200 px-2 py-1 rounded">{{ user.id }}</code>
95
+ </td>
96
+ <td>
97
+ <span class="text-sm text-base-content/70">
98
+ {% if user.db_insert_dt %}
99
+ {{ user.db_insert_dt.strftime("%Y-%m-%d %H:%M") }}
100
+ {% else %}
101
+ Unknown
102
+ {% endif %}
103
+ </span>
104
+ </td>
105
+ <td class="text-center">
106
+ {% if current_user_id != user.id|string %}
107
+ <form method="post"
108
+ action="/debug/impersonate/{{ user.id }}"
109
+ class="inline">
110
+ <button type="submit" class="btn btn-outline btn-sm">Impersonate</button>
111
+ </form>
112
+ {% else %}
113
+ <span class="text-primary font-medium">Active</span>
114
+ {% endif %}
115
+ </td>
116
+ </tr>
117
+ {% endfor %}
118
+ </tbody>
119
+ </table>
120
+ </div>
121
+ {% else %}
122
+ <div class="alert alert-warning">
123
+ <svg xmlns="http://www.w3.org/2000/svg"
124
+ class="stroke-current shrink-0 h-6 w-6"
125
+ fill="none"
126
+ viewBox="0 0 24 24">
127
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z" />
128
+ </svg>
129
+ <span>No users found in the database.</span>
130
+ </div>
131
+ {% endif %}
132
+ </div>
133
+ </div>
134
+ <!-- Debug Navigation Footer -->
135
+ {% include "debug/components/debug_nav.html.jinja" %}
136
+ </div>
137
+ {% endblock body %}
@@ -0,0 +1,53 @@
1
+ {% extends "base/skeleton.html.jinja" %}
2
+ {% block title %}
3
+ Version Information - Debug
4
+ {% endblock title %}
5
+ {% block body %}
6
+ <div class="container mx-auto px-4 py-8 max-w-4xl">
7
+ <!-- Header -->
8
+ <header class="mb-8">
9
+ <h1 class="text-4xl font-bold text-base-content mb-2">Version Information</h1>
10
+ <p class="text-base-content/70">Application version and build details</p>
11
+ </header>
12
+ <!-- Version Details Card -->
13
+ <div class="card bg-base-100 shadow-xl border border-base-200">
14
+ <div class="card-body">
15
+ <h2 class="card-title text-primary mb-6">Build Information</h2>
16
+ <div class="grid md:grid-cols-2 gap-6">
17
+ <div class="flex items-center gap-4">
18
+ <div class="w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center">
19
+ <svg class="w-6 h-6 text-primary"
20
+ fill="none"
21
+ stroke="currentColor"
22
+ viewBox="0 0 24 24">
23
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z">
24
+ </path>
25
+ </svg>
26
+ </div>
27
+ <div>
28
+ <h3 class="font-semibold text-base-content">Version</h3>
29
+ <p class="text-2xl font-bold text-primary">{{ version }}</p>
30
+ </div>
31
+ </div>
32
+ <div class="flex items-center gap-4">
33
+ <div class="w-12 h-12 bg-secondary/10 rounded-full flex items-center justify-center">
34
+ <svg class="w-6 h-6 text-secondary"
35
+ fill="none"
36
+ stroke="currentColor"
37
+ viewBox="0 0 24 24">
38
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h4a1 1 0 011 1v2m3 6V8a1 1 0 00-1-1H9a1 1 0 00-1 1v2m0 0v10a1 1 0 001 1h6a1 1 0 001-1V10H8z">
39
+ </path>
40
+ </svg>
41
+ </div>
42
+ <div>
43
+ <h3 class="font-semibold text-base-content">Version Hash</h3>
44
+ <p class="text-sm font-mono text-secondary bg-secondary/10 px-2 py-1 rounded">{{ v_hash }}</p>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ <!-- Debug Navigation Footer -->
51
+ {% include "debug/components/debug_nav.html.jinja" %}
52
+ </div>
53
+ {% endblock body %}
@@ -0,0 +1,5 @@
1
+ Sign in to {project_name}
2
+ Copy and paste this link into your browser to sign in:
3
+ {login_url}
4
+ This link will expire in 15 minutes.
5
+ If you didn't request this, you can safely ignore this email.
@@ -0,0 +1,82 @@
1
+ {% extends "base/skeleton.html.jinja" %}
2
+ {% block title %}
3
+ {{ _("Check Your Email") }}
4
+ {% endblock title %}
5
+ {% block body %}
6
+ <div class="min-h-screen bg-gradient-to-br from-primary to-secondary flex items-center justify-center p-4">
7
+ <div class="card w-full max-w-md bg-base-100 shadow-2xl backdrop-blur-sm bg-opacity-95">
8
+ <div class="card-body text-center">
9
+ <!-- Success Icon -->
10
+ <div class="flex justify-center mb-6">
11
+ <div class="bg-success/10 rounded-full p-4 animate-pulse">
12
+ <svg class="w-12 h-12 text-success"
13
+ fill="none"
14
+ stroke="currentColor"
15
+ viewBox="0 0 24 24">
16
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
17
+ </svg>
18
+ </div>
19
+ </div>
20
+ <!-- Header -->
21
+ <h2 class="text-2xl font-bold text-base-content mb-4">{{ _("Check Your Email") }}</h2>
22
+ <!-- Main Message -->
23
+ <div class="space-y-4 mb-6">
24
+ <p class="text-base-content/80">{{ _("We've sent a secure login link to") }}</p>
25
+ <div class="bg-base-200/50 rounded-lg p-3 border border-base-300/50">
26
+ <p class="font-semibold text-primary break-all">{{ email }}</p>
27
+ </div>
28
+ <div class="alert alert-info bg-info/10 border-info/20 text-left">
29
+ <svg class="w-5 h-5 text-info shrink-0"
30
+ fill="none"
31
+ stroke="currentColor"
32
+ viewBox="0 0 24 24">
33
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
34
+ </svg>
35
+ <div class="text-sm">
36
+ <p class="font-medium text-info">{{ _("Quick! Link expires in 15 minutes") }}</p>
37
+ <p class="text-info/80">{{ _("Click the link in the email to sign in instantly.") }}</p>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ <!-- Troubleshooting -->
42
+ <div class="bg-warning/5 border border-warning/20 rounded-lg p-4 mb-6">
43
+ <div class="flex items-start gap-3">
44
+ <svg class="w-5 h-5 text-warning shrink-0 mt-0.5"
45
+ fill="none"
46
+ stroke="currentColor"
47
+ viewBox="0 0 24 24">
48
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 15.5c-.77.833.192 2.5 1.732 2.5z" />
49
+ </svg>
50
+ <div class="text-left">
51
+ <p class="font-medium text-warning text-sm">{{ _("Don't see the email?") }}</p>
52
+ <p class="text-warning/80 text-sm">{{ _("Check your spam folder or try signing in again.") }}</p>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ <!-- Action Buttons -->
57
+ <div class="space-y-3">
58
+ <!-- Try Again Button -->
59
+ <a href="{{ url_for("auth_login") }}{% if next %}?next={{ next }}{% endif %}"
60
+ class="btn btn-outline btn-block gap-2 hover:btn-primary transition-all duration-300 hover:scale-[1.02]">
61
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
62
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
63
+ </svg>
64
+ {{ _("Try Again") }}
65
+ </a>
66
+ <!-- Back to Home -->
67
+ <a href="{{ url_for("homepage") }}"
68
+ class="btn btn-ghost btn-block gap-2 text-base-content/70 hover:text-base-content transition-all duration-300">
69
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
70
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
71
+ </svg>
72
+ {{ _("Back to Home") }}
73
+ </a>
74
+ </div>
75
+ <!-- Security Note -->
76
+ <div class="mt-6 pt-4 border-t border-base-300/30">
77
+ <p class="text-xs text-base-content/50">🔒 {{ _("This link is secure and can only be used once") }}</p>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ {% endblock body %}
@@ -0,0 +1,19 @@
1
+ {% set BODY_CLASS = "min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 flex flex-col justify-between" %}
2
+ {% extends "base/skeleton.html.jinja" %}
3
+ {% block body %}
4
+ <!-- Main Content -->
5
+ <div class="flex-1 flex items-center justify-center px-6">
6
+ <div class="text-center max-w-4xl mx-auto">
7
+ <!-- Main Title -->
8
+ <h1 class="text-6xl md:text-8xl font-bold text-slate-800 mb-6 tracking-tight">{{ project_name }}</h1>
9
+ <!-- Subtitle -->
10
+ <p class="text-xl md:text-2xl text-slate-600 font-light max-w-2xl mx-auto leading-relaxed">
11
+ {{ project_description }}
12
+ </p>
13
+ <!-- Decorative element -->
14
+ <div class="mt-12 flex justify-center">
15
+ <div class="w-24 h-1 bg-gradient-to-r from-blue-400 to-indigo-500 rounded-full"></div>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ {% endblock body %}
@@ -0,0 +1,4 @@
1
+ {% for code, language in locale_names.items() %}
2
+ <option value="{{ url_for('set_language', lang=code).path }}"
3
+ {% if code==current_language %}disabled selected{% endif %}>{{ language }}</option>
4
+ {% endfor %}