fasthtml-auth 0.1.1__tar.gz → 0.1.2__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 (23) hide show
  1. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/CHANGELOG.md +16 -0
  2. {fasthtml_auth-0.1.1/fasthtml_auth.egg-info → fasthtml_auth-0.1.2}/PKG-INFO +1 -1
  3. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/examples/basic_app.py +5 -5
  4. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/__init__.py +1 -1
  5. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/forms.py +8 -6
  6. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/middleware.py +17 -0
  7. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/routes.py +26 -3
  8. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2/fasthtml_auth.egg-info}/PKG-INFO +1 -1
  9. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/pyproject.toml +1 -1
  10. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/LICENSE +0 -0
  11. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/MANIFEST.in +0 -0
  12. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/README.md +0 -0
  13. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/database.py +0 -0
  14. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/init.py +0 -0
  15. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/manager.py +0 -0
  16. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/models.py +0 -0
  17. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/repository.py +0 -0
  18. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth/utils.py +0 -0
  19. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth.egg-info/SOURCES.txt +0 -0
  20. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth.egg-info/dependency_links.txt +0 -0
  21. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth.egg-info/requires.txt +0 -0
  22. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/fasthtml_auth.egg-info/top_level.txt +0 -0
  23. {fasthtml_auth-0.1.1 → fasthtml_auth-0.1.2}/setup.cfg +0 -0
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.2] - 2025-09-03
9
+
10
+ ### Added
11
+ - Implemented "Remember me" functionality with extended session duration
12
+ - Added session expiry handling for persistent logins
13
+ - Server-side validation for "Accept Terms" checkbox in registration
14
+ - Clear error message when terms are not accepted
15
+
16
+
17
+ ### Fixed
18
+ - "Remember me" checkbox now actually remembers users for 30 days
19
+ - "Checkbox for accept terms in the register form has been corrected so that it displays correctly
20
+ - Registration now properly validates terms acceptance
21
+ - Sorted out some styling issues with the admin forms in basic_app.py
22
+
23
+
8
24
  ## [0.1.1] - 2025-09-09
9
25
 
10
26
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fasthtml-auth
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Complete authentication system for FastHTML applications with beautiful UI, role-based access control, and session management
5
5
  Author-email: John Richmond <confusedjohn46@gmail.com>
6
6
  Maintainer-email: John Richmond <confusedjohn46@gmail.com>
@@ -117,13 +117,13 @@ def admin_panel(req):
117
117
  " ",
118
118
  Button("System Settings", cls=ButtonT.secondary, disabled=True),
119
119
  " ",
120
- Button("View Logs", cls=ButtonT.outline, disabled=True),
120
+ Button("View Logs", cls=ButtonT.secondary, disabled=True),
121
121
  cls="mt-4"
122
122
  ),
123
123
  P("(These buttons are disabled in demo)", cls="text-sm text-muted-foreground mt-2")
124
124
  )
125
125
  ),
126
- cls=ContainerT.md
126
+ cls=ContainerT.lg
127
127
  )
128
128
 
129
129
  # Test manager route
@@ -151,7 +151,7 @@ def manager_view(req, *args, **kwargs):
151
151
  P("(These buttons are disabled in demo)", cls="text-sm text-muted-foreground mt-2")
152
152
  )
153
153
  ),
154
- cls=ContainerT.md
154
+ cls=ContainerT.lg
155
155
  )
156
156
 
157
157
  # Public route for testing
@@ -180,7 +180,7 @@ def about():
180
180
  )
181
181
  )
182
182
  ),
183
- cls=ContainerT.md
183
+ cls=ContainerT.lg
184
184
  )
185
185
 
186
186
  # Contact page - another public route
@@ -199,7 +199,7 @@ def contact():
199
199
  P("Phone: (555) 123-4567")
200
200
  )
201
201
  ),
202
- cls=ContainerT.md
202
+ cls=ContainerT.lg
203
203
  )
204
204
 
205
205
  if __name__ == "__main__":
@@ -5,7 +5,7 @@ Provides user authentication, session management, role-based access control,
5
5
  and beautiful UI components out of the box.
6
6
  """
7
7
 
8
- __version__ = "0.1.1"
8
+ __version__ = "0.1.2"
9
9
  __author__ = "John Richmond"
10
10
  __email__ = "confusedjohn46@gmail.com"
11
11
 
@@ -42,9 +42,9 @@ def create_login_form(error=None, action="/auth/login", redirect_to="/"):
42
42
 
43
43
  Div(
44
44
  Label(
45
- Input(type="checkbox", name="remember_me"),
46
- " Remember me",
47
- cls="flex items-center text-sm"
45
+ CheckboxX(name="remember_me", selected=False),
46
+ Span(" Remember me", cls="ml-2"),
47
+ cls="flex items-center text-sm cursor-pointer"
48
48
  ),
49
49
  cls="mb-4"
50
50
  ),
@@ -87,6 +87,8 @@ def create_register_form(error=None, action="/auth/register"):
87
87
  error_message = "Please enter a valid email address."
88
88
  elif error == 'creation_failed':
89
89
  error_message = "Failed to create account. Please try again."
90
+ elif error == 'terms_required': # NEW ERROR MESSAGE
91
+ error_message = "You must accept the Terms and Conditions to register."
90
92
 
91
93
  return DivCentered(
92
94
  Card(
@@ -139,9 +141,9 @@ def create_register_form(error=None, action="/auth/register"):
139
141
 
140
142
  Div(
141
143
  Label(
142
- Input(type="checkbox", name="accept_terms", required=True),
143
- " I accept the Terms and Conditions",
144
- cls="flex items-center text-sm"
144
+ CheckboxX(name="accept_terms", selected=False, required=True),
145
+ Span(" I accept the Terms and Conditions", cls="ml-2"),
146
+ cls="flex items-center text-sm cursor-pointer"
145
147
  ),
146
148
  cls="mb-4"
147
149
  ),
@@ -35,6 +35,23 @@ class AuthBeforeware:
35
35
  """Check authentication prior to check"""
36
36
  auth_username = sess.get('auth')
37
37
 
38
+ # If no session auth, check for remember me cookie
39
+ if not auth_username:
40
+ remember_user = req.cookies.get('remember_user')
41
+ if remember_user:
42
+ # Verify user still exists and is active
43
+ user = self.auth_manager.get_user(remember_user)
44
+ if user and user.active:
45
+ # Restore session from remember me cookie
46
+ sess['auth'] = user.username
47
+ sess['user_id'] = user.id
48
+ sess['role'] = user.role
49
+ sess['remember_me'] = True
50
+ auth_username = user.username
51
+ else:
52
+ # Invalid remember me cookie, continue to redirect
53
+ pass
54
+
38
55
  if not auth_username:
39
56
  # No auth, redirect to login
40
57
  return RedirectResponse(self.login_path, status_code=303)
@@ -46,18 +46,37 @@ class AuthRoutes:
46
46
  form = await req.form()
47
47
  username = form.get('username', '').strip()
48
48
  password = form.get('password', '')
49
+ remember_me = form.get('remember_me') == 'on'
49
50
 
50
51
  # Authenticate
51
52
  user = self.auth.user_repo.authenticate(username, password)
53
+
52
54
  if user:
53
55
  # Set session
54
56
  sess['auth'] = user.username
55
57
  sess['user_id'] = user.id
56
58
  sess['role'] = user.role
57
-
58
- # Redirect to next URL or default
59
+
59
60
  redirect_url = form.get('redirect_to', '/')
60
- return RedirectResponse(redirect_url, status_code=303)
61
+ response = RedirectResponse(redirect_url, status_code=303)
62
+
63
+ if remember_me:
64
+ # Set a long-lived cookie (30 days)
65
+ response.set_cookie(
66
+ key='remember_user',
67
+ value=user.username,
68
+ max_age=30*24*60*60, # 30 days in seconds
69
+ httponly=True,
70
+ samesite='strict'
71
+ )
72
+ sess['remember_me'] = True
73
+ else:
74
+ # Remove remember me cookie if it exists
75
+ response.delete_cookie('remember_user')
76
+ sess.pop('remember_me', None)
77
+
78
+ return response
79
+
61
80
  # On failure, preserve the redirect_to parameter
62
81
  redirect_to = form.get('redirect_to', '/')
63
82
  error_url = f"{prefix}/login?error=invalid"
@@ -92,6 +111,10 @@ class AuthRoutes:
92
111
  email = form.get('email', '').strip()
93
112
  password = form.get('password', '')
94
113
  confirm = form.get('confirm_password', '')
114
+ accept_terms = form.get('accept_terms') == 'on'
115
+
116
+ if not accept_terms:
117
+ return RedirectResponse(f"{prefix}/register?error=terms_required", status_code=303)
95
118
 
96
119
  # Validation
97
120
  if password != confirm:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fasthtml-auth
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Complete authentication system for FastHTML applications with beautiful UI, role-based access control, and session management
5
5
  Author-email: John Richmond <confusedjohn46@gmail.com>
6
6
  Maintainer-email: John Richmond <confusedjohn46@gmail.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fasthtml-auth"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Complete authentication system for FastHTML applications with beautiful UI, role-based access control, and session management"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
File without changes
File without changes
File without changes
File without changes