Skip to content

Commit 9a29fcb

Browse files
phernandezphernandez
andauthored
Admin UI tweaks (#5)
* refactor register form to be simpler * refactor user_create flow * add hover effect to stat * Refactor .env, templates and config variables - Added APP_NAME variable in .env.ci and used it in app.py. - Removed redundant code and reorganized user_list.html templates. - Renamed 'user_list_view.html' to 'user_list_row.html' for consistency. - Updated TODO.md to reflect completed tasks. * setup sending emails via mailgun * increment project version, and release on pr to main * fix modal delete confirm * add comments to lazy loading of user list * upgrade email templates * enable preview envs in render via blueprint * set preview expiration to 1 day * add email config to .env.ci * fix webui test --------- Co-authored-by: phernandez <phernandez@basicmachines.co>
1 parent 362ecae commit 9a29fcb

38 files changed

Lines changed: 1333 additions & 1100 deletions

.bumpversion.cfg

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[bumpversion]
2+
current_version = 0.1.0
3+
commit = True
4+
tag = True
5+
6+
[bumpversion:file:pyproject.toml]
7+
search = version = "{current_version}"
8+
replace = version = "{new_version}"

.env.ci

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
APP_NAME=Basic Foundation
2+
13
POSTGRES_USER="postgres"
24
POSTGRES_PASSWORD="password"
35
POSTGRES_DB="api"

.github/workflows/release.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Release on Merge to Main
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
# Step 1: Checkout code
14+
- uses: actions/checkout@v4
15+
16+
# Step 2: Set up Python
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: '3.11'
21+
22+
# Step 3: Install dependencies (including bump2version)
23+
- name: Install Dependencies
24+
run: |
25+
pip install poetry
26+
poetry install
27+
pip install bump2version
28+
29+
# Step 4: Bump the version (patch, minor, or major)
30+
- name: Bump Version
31+
run: |
32+
bump2version patch
33+
34+
# Step 5: Build the project
35+
- name: Build Project
36+
run: |
37+
poetry build
38+
39+
# Step 6: Push changes (committed by bump2version)
40+
- name: Push Version Bump Changes
41+
run: |
42+
git config user.name "github-actions[bot]"
43+
git config user.email "github-actions[bot]@users.noreply.github.com"
44+
git push origin main
45+
46+
# Step 7: Create a GitHub Release
47+
- name: Create Release
48+
id: create_release
49+
uses: actions/create-release@v1
50+
env:
51+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
with:
53+
tag_name: 'v${{ steps.bump_version.outputs.new_version }}' # New version from bump2version
54+
release_name: 'Release v${{ steps.bump_version.outputs.new_version }}'
55+
draft: false
56+
prerelease: false
57+
58+
# # Step 8: Upload build artifacts to the release (optional)
59+
# - name: Upload Build Artifacts
60+
# uses: actions/upload-artifact@v4
61+
# with:
62+
# name: basic-foundation-build
63+
# path: dist/ # Path to your build artifacts

TODO.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@
22

33
## todo
44

5-
- [ ] package as separate modules?
5+
- [x] package as separate modules?
66
- core
77
- api
88
- web-htmx
9-
- [ ] uv
9+
- [-] uv
1010
- [ ] permission checks
1111
- [x] has to be at least one admin
1212
- [x] only admins can create/edit users
1313
- [ ] dashboard stats should link to filtered list
14-
- [ ] user service with current user
1514
- [ ] make active/admin colums enums
1615
- [ ] db: rename is_superuser to is_admin
17-
- [ ] page_size is appended to url
16+
- [-] page_size is appended to url
1817
- [x] use fixtures in web tests
1918
- [x] delete user after test
2019
- [x] add playwright to github ci
2120
- [x] code coverage for ci
22-
- [ ] Api docs say FASTAPI
21+
- [x] Api docs say FASTAPI
2322
- [ ] responsive tests for playwright
2423
- [x] pywright
25-
- [ ] form includes
26-
- [ ] users page refresh
27-
- [ ] mailapi - sendgrid? or mailgun?
28-
- https://sabuhish.github.io/fastapi-mail/example/
29-
- https://pramod4040.medium.com/fastapi-forget-password-api-setup-632ab90ba958
24+
- [x] form includes
25+
- [x] users page refresh
26+
- [ ] mailapi
27+
- mailgun
28+
- setup domain
29+
- mx record
3030
- [ ] automate github releases on merge to main
3131

3232
## feature

foundation/app.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
logger.remove()
2424
logger.add(sys.stderr, colorize=True, backtrace=True, diagnose=True)
2525

26-
app = FastAPI()
26+
app = FastAPI(title=settings.APP_NAME)
2727

2828
# Add middleware for sessions and CSRF protection
2929
app.add_middleware(SessionMiddleware, secret_key=settings.JWT_SECRET)
@@ -43,7 +43,8 @@ async def on_startup(): # pragma: no cover
4343
4444
:return: None
4545
"""
46-
logger.info(f"Welcome to {config.settings.app_name}")
46+
logger.info(f"Welcome to {config.settings.APP_NAME}")
47+
logger.info(f"email enabled: {config.settings.EMAIL_ENABLED}")
4748

4849
# silence bcrypt noise
4950
logging.getLogger("passlib").setLevel(logging.ERROR)

foundation/core/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class Settings(BaseSettings):
2727
DOMAIN: str = "localhost"
2828
ENVIRONMENT: Literal["local", "staging", "production"] = "local"
2929

30-
app_name: str = "Basic API"
30+
APP_NAME: str
3131
JWT_SECRET: str
3232
CSRF_SECRET: str
3333
POSTGRES_USER: str
Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class EmailData:
1818

1919
def render_email_template(*, template_name: str, context: dict[str, Any]) -> str:
2020
template_str = (
21-
BASE_DIR / "foundation" / "templates" / "email" / "build" / template_name
21+
BASE_DIR / "foundation" / "templates" / "email" / "build" / template_name
2222
).read_text()
2323
html_content = Template(template_str).render(context)
2424
return html_content
@@ -27,8 +27,8 @@ def render_email_template(*, template_name: str, context: dict[str, Any]) -> str
2727
def send_email( # pragma: no cover
2828
*,
2929
email_to: str,
30-
subject: str = "",
31-
html_content: str = "",
30+
subject: str,
31+
html_content: str,
3232
) -> SMTPResponse:
3333
assert settings.emails_enabled, "no provided configuration for email variables"
3434
message = emails.Message(
@@ -47,28 +47,28 @@ def send_email( # pragma: no cover
4747
if settings.EMAIL_SMTP_PASSWORD:
4848
smtp_options["password"] = settings.EMAIL_SMTP_PASSWORD
4949
response = message.send(to=email_to, smtp=smtp_options)
50-
logger.info(f"send email result: {response}")
50+
logger.info(f"send email {email_to} result: {response.__dict__}")
5151
return response
5252

5353

5454
def generate_test_email(email_to: str) -> EmailData:
55-
project_name = settings.app_name
56-
subject = f"{project_name} - Test email"
55+
app_name = settings.APP_NAME
56+
subject = f"{app_name} - Test email"
5757
html_content = render_email_template(
5858
template_name="test_email.html",
59-
context={"project_name": project_name, "email": email_to},
59+
context={"app_name": app_name, "email": email_to},
6060
)
6161
return EmailData(html_content=html_content, subject=subject)
6262

6363

6464
def generate_reset_password_email(email_to: str, email: str, token: str) -> EmailData:
65-
project_name = settings.app_name
66-
subject = f"{project_name} - Password recovery for user {email}"
65+
app_name = settings.APP_NAME
66+
subject = f"{app_name} - Password recovery for user {email}"
6767
link = f"{settings.server_host}/reset-password?token={token}"
6868
html_content = render_email_template(
6969
template_name="reset_password.html",
7070
context={
71-
"project_name": project_name,
71+
"app_name": app_name,
7272
"username": email,
7373
"email": email_to,
7474
"valid_hours": settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS,
@@ -82,12 +82,12 @@ def generate_reset_password_email(email_to: str, email: str, token: str) -> Emai
8282
def generate_new_account_email(
8383
email_to: str, username: str, password: str
8484
) -> EmailData:
85-
project_name = settings.app_name
86-
subject = f"{project_name} - New account for user {username}"
85+
app_name = settings.APP_NAME
86+
subject = f"{app_name} - New account for user {username}"
8787
html_content = render_email_template(
8888
template_name="new_account.html",
8989
context={
90-
"project_name": settings.app_name,
90+
"app_name": settings.APP_NAME,
9191
"username": username,
9292
"password": password,
9393
"email": email_to,

foundation/core/test/test_emails.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from fastapi_jwt.jwt_backends.abstract_backend import BackendException
55
from jwt import InvalidTokenError
66

7-
from foundation.core.emails import (
7+
from foundation.core.email import (
88
generate_test_email,
99
send_email,
1010
generate_reset_password_email,

0 commit comments

Comments
 (0)