Skip to content

Commit 9e521d2

Browse files
authored
Merge pull request #17 from alimkhann/features/backend-organization
Features/backend organization
2 parents 95b6359 + 035ff2e commit 9e521d2

27 files changed

+517
-150
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*.cursorignore
33
cursor-logs.md
44
*.sql
5+
__pypackages__/
56
__pycache__
67
venv
78

@@ -117,6 +118,7 @@ temp/
117118

118119
# Editor directories and files
119120
.vscode/*
121+
.DS_Store
120122
!.vscode/extensions.json
121123
.idea
122124
*.suo
@@ -152,4 +154,4 @@ temp/
152154
*.crt
153155
*.csr
154156
*.p12
155-
*.pfx
157+
*.pfx

FORDEVS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ cd commitly-backend
1919
pip3 install -r requirements.txt
2020
```
2121
```bash
22+
python -m venv venv
23+
```
24+
```bash
25+
macOS
2226
source venv/bin/activate
27+
28+
Windows
29+
source venv/Scripts/activate
2330
```
2431
```bash
2532
uvicorn app.main:app

commitly-backend/.flake8

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[flake8]
2+
application-import-names = app
3+
max-line-length = 88
4+
exclude = .git,__pycache__,venv,.venv,migrations,alembic
5+
6+
# For Black compatibility
7+
extend-ignore = E203, W503, I101
8+
9+
# import order plugin (flake8-import-order)
10+
import-order-style = google
11+
12+
# flake8-quotes settings
13+
inline-quotes = double
14+
multiline-quotes = double
15+
docstring-quotes = double
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
paths:
7+
- 'commitly-backend/**'
8+
- '.github/workflows/ci.yml'
9+
pull_request:
10+
paths:
11+
- 'commitly-backend/**'
12+
- '.github/workflows/ci.yml'
13+
14+
jobs:
15+
lint:
16+
name: Lint (Flake8, Black, isort)
17+
runs-on: ubuntu-latest
18+
defaults:
19+
run:
20+
working-directory: commitly-backend
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: '3.12'
29+
30+
- name: Cache pip
31+
uses: actions/cache@v4
32+
with:
33+
path: ~/.cache/pip
34+
key: pip-${{ runner.os }}-py312-${{ hashFiles('commitly-backend/requirements.txt', 'commitly-backend/requirements/dev.txt') }}
35+
restore-keys: |
36+
pip-${{ runner.os }}-py312-
37+
38+
- name: Install dependencies (dev)
39+
run: |
40+
python -m pip install --upgrade pip
41+
pip install -r requirements.txt
42+
43+
- name: Flake8
44+
run: |
45+
echo "Running Flake8..."
46+
flake8 --version
47+
flake8 --verbose
48+
49+
- name: Black (check)
50+
run: |
51+
echo "Running Black..."
52+
black --version
53+
black --check .
54+
55+
- name: isort (check-only)
56+
run: |
57+
echo "Running isort..."
58+
isort --version
59+
isort --check-only --profile black .
60+
61+
test:
62+
name: Test
63+
runs-on: ubuntu-latest
64+
needs: lint
65+
defaults:
66+
run:
67+
working-directory: commitly-backend
68+
steps:
69+
- name: Checkout
70+
uses: actions/checkout@v4
71+
72+
- name: Set up Python
73+
uses: actions/setup-python@v5
74+
with:
75+
python-version: '3.12'
76+
77+
- name: Cache pip
78+
uses: actions/cache@v4
79+
with:
80+
path: ~/.cache/pip
81+
key: pip-${{ runner.os }}-py312-${{ hashFiles('commitly-backend/requirements.txt', 'commitly-backend/requirements/test.txt') }}
82+
restore-keys: |
83+
pip-${{ runner.os }}-py312-
84+
85+
- name: Install dependencies (dev)
86+
run: |
87+
python -m pip install --upgrade pip
88+
pip install -r requirements.txt
89+
90+
- name: Run pytest
91+
run: |
92+
pytest -q
93+

commitly-backend/alembic/env.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
from alembic import context
88
from sqlalchemy import engine_from_config, pool
99

10+
from app.core.config import settings
11+
from app.core.database import Base
12+
1013
PROJECT_ROOT = Path(__file__).resolve().parents[1]
1114
if str(PROJECT_ROOT) not in sys.path:
1215
sys.path.append(str(PROJECT_ROOT))
1316

14-
from app.core.config import settings # noqa: E402
15-
from app.core.database import Base # noqa: E402
16-
1717
config = context.config
1818

1919
if config.config_file_name is not None:

commitly-backend/alembic/versions/6b3b2a7f804c_create_waitlist_and_support_tables.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from alembic import op
1212
import sqlalchemy as sa
1313

14-
1514
revision: str = "6b3b2a7f804c"
1615
down_revision: Union[str, Sequence[str], None] = None
1716
branch_labels: Union[str, Sequence[str], None] = None
@@ -23,7 +22,9 @@ def upgrade() -> None:
2322
"waitlist",
2423
sa.Column("id", sa.Integer(), primary_key=True),
2524
sa.Column("email", sa.String(length=255), nullable=False),
26-
sa.Column("source", sa.String(length=100), nullable=False, server_default="landing"),
25+
sa.Column(
26+
"source", sa.String(length=100), nullable=False, server_default="landing"
27+
),
2728
sa.Column(
2829
"created_at",
2930
sa.TIMESTAMP(timezone=True),
@@ -60,7 +61,9 @@ def upgrade() -> None:
6061
DO $$
6162
BEGIN
6263
IF NOT EXISTS (
63-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'waitlist' AND policyname = 'Allow public insert on waitlist'
64+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
65+
AND tablename = 'waitlist'
66+
AND policyname = 'Allow public insert on waitlist'
6467
) THEN
6568
CREATE POLICY "Allow public insert on waitlist"
6669
ON waitlist FOR INSERT
@@ -75,7 +78,9 @@ def upgrade() -> None:
7578
DO $$
7679
BEGIN
7780
IF NOT EXISTS (
78-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'waitlist' AND policyname = 'Allow public select count on waitlist'
81+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
82+
AND tablename = 'waitlist'
83+
AND policyname = 'Allow public select count on waitlist'
7984
) THEN
8085
CREATE POLICY "Allow public select count on waitlist"
8186
ON waitlist FOR SELECT
@@ -90,7 +95,9 @@ def upgrade() -> None:
9095
DO $$
9196
BEGIN
9297
IF NOT EXISTS (
93-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'support' AND policyname = 'Allow public insert on support'
98+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
99+
AND tablename = 'support'
100+
AND policyname = 'Allow public insert on support'
94101
) THEN
95102
CREATE POLICY "Allow public insert on support"
96103
ON support FOR INSERT
@@ -105,7 +112,9 @@ def upgrade() -> None:
105112
DO $$
106113
BEGIN
107114
IF NOT EXISTS (
108-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'support' AND policyname = 'Allow public select on support'
115+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
116+
AND tablename = 'support'
117+
AND policyname = 'Allow public select on support'
109118
) THEN
110119
CREATE POLICY "Allow public select on support"
111120
ON support FOR SELECT
@@ -134,10 +143,12 @@ def upgrade() -> None:
134143
def downgrade() -> None:
135144
op.execute("DROP FUNCTION IF EXISTS public.waitlist_count();")
136145

137-
op.execute("DROP POLICY IF EXISTS \"Allow public insert on support\" ON support;")
138-
op.execute("DROP POLICY IF EXISTS \"Allow public select on support\" ON support;")
139-
op.execute("DROP POLICY IF EXISTS \"Allow public insert on waitlist\" ON waitlist;")
140-
op.execute("DROP POLICY IF EXISTS \"Allow public select count on waitlist\" ON waitlist;")
146+
op.execute('DROP POLICY IF EXISTS "Allow public insert on support" ON support;')
147+
op.execute('DROP POLICY IF EXISTS "Allow public select on support" ON support;')
148+
op.execute('DROP POLICY IF EXISTS "Allow public insert on waitlist" ON waitlist;')
149+
op.execute(
150+
'DROP POLICY IF EXISTS "Allow public select count on waitlist" ON waitlist;'
151+
)
141152

142153
op.drop_index("ix_support_status", table_name="support")
143154
op.drop_index("ix_support_email", table_name="support")

commitly-backend/alembic/versions/9d1e2f3a_drop_support_feature.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from alembic import op
1212
import sqlalchemy as sa
1313

14-
1514
revision: str = "9d1e2f3a"
1615
down_revision: Union[str, Sequence[str], None] = "6b3b2a7f804c"
1716
branch_labels: Union[str, Sequence[str], None] = None
@@ -25,12 +24,16 @@ def upgrade() -> None:
2524
DO $$
2625
BEGIN
2726
IF EXISTS (
28-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'support' AND policyname = 'Allow public insert on support'
27+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
28+
AND tablename = 'support'
29+
AND policyname = 'Allow public insert on support'
2930
) THEN
3031
DROP POLICY "Allow public insert on support" ON public.support;
3132
END IF;
3233
IF EXISTS (
33-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'support' AND policyname = 'Allow public select on support'
34+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
35+
AND tablename = 'support'
36+
AND policyname = 'Allow public select on support'
3437
) THEN
3538
DROP POLICY "Allow public select on support" ON public.support;
3639
END IF;
@@ -74,7 +77,9 @@ def downgrade() -> None:
7477
DO $$
7578
BEGIN
7679
IF NOT EXISTS (
77-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'support' AND policyname = 'Allow public insert on support'
80+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
81+
AND tablename = 'support'
82+
AND policyname = 'Allow public insert on support'
7883
) THEN
7984
CREATE POLICY "Allow public insert on support"
8085
ON support FOR INSERT
@@ -90,7 +95,9 @@ def downgrade() -> None:
9095
DO $$
9196
BEGIN
9297
IF NOT EXISTS (
93-
SELECT 1 FROM pg_policies WHERE schemaname = 'public' AND tablename = 'support' AND policyname = 'Allow public select on support'
98+
SELECT 1 FROM pg_policies WHERE schemaname = 'public'
99+
AND tablename = 'support'
100+
AND policyname = 'Allow public select on support'
94101
) THEN
95102
CREATE POLICY "Allow public select on support"
96103
ON support FOR SELECT
@@ -99,4 +106,4 @@ def downgrade() -> None:
99106
END
100107
$$;
101108
"""
102-
)
109+
)

commitly-backend/app/api/donate.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from fastapi import APIRouter, HTTPException, status
44
from pydantic import BaseModel, EmailStr, Field
55

6-
from app.services.polar import PolarService, PolarConfigurationError
6+
from app.services.polar import PolarConfigurationError, PolarService
77

88
router = APIRouter()
99

@@ -18,15 +18,26 @@ class DonateResponse(BaseModel):
1818
url: str
1919

2020

21-
@router.post("/checkout", response_model=DonateResponse, status_code=status.HTTP_201_CREATED)
21+
@router.post(
22+
"/checkout", response_model=DonateResponse, status_code=status.HTTP_201_CREATED
23+
)
2224
def create_donation_checkout(payload: DonateRequest) -> DonateResponse:
2325
try:
2426
service = PolarService()
25-
result = service.create_checkout(amount_cents=payload.amount_cents, email=payload.email)
27+
result = service.create_checkout(
28+
amount_cents=payload.amount_cents, email=payload.email
29+
)
2630
return DonateResponse(checkout_id=result["id"], url=result["url"])
2731
except PolarConfigurationError as exc:
28-
raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=str(exc))
32+
raise HTTPException(
33+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=str(exc)
34+
)
2935
except ValueError as exc:
30-
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc))
36+
raise HTTPException(
37+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)
38+
)
3139
except Exception as exc: # noqa: BLE001
32-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to create donation checkout") from exc
40+
raise HTTPException(
41+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
42+
detail="Failed to create donation checkout",
43+
) from exc

commitly-backend/app/api/waitlist.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from sqlalchemy.orm import Session
33

44
from app.core.database import get_db
5-
from app.models.waitlist import WaitlistCreate, WaitlistResponse, WaitlistCountResponse
5+
from app.models.waitlist import WaitlistCountResponse, WaitlistCreate, WaitlistResponse
66
from app.services.supabase import DuplicateEntryError, PersistenceError, SupabaseService
77

88
router = APIRouter()
@@ -13,7 +13,9 @@
1313
response_model=WaitlistResponse,
1414
status_code=status.HTTP_201_CREATED,
1515
)
16-
def join_waitlist(payload: WaitlistCreate, session: Session = Depends(get_db)) -> WaitlistResponse:
16+
def join_waitlist(
17+
payload: WaitlistCreate, session: Session = Depends(get_db)
18+
) -> WaitlistResponse:
1719
service = SupabaseService(session)
1820
try:
1921
entry = service.add_to_waitlist(payload)
@@ -23,7 +25,9 @@ def join_waitlist(payload: WaitlistCreate, session: Session = Depends(get_db)) -
2325
detail="This email is already on the waitlist.",
2426
)
2527
except PersistenceError as exc:
26-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc))
28+
raise HTTPException(
29+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)
30+
)
2731

2832
return WaitlistResponse.model_validate(entry)
2933

@@ -34,6 +38,8 @@ def get_waitlist_count(session: Session = Depends(get_db)) -> WaitlistCountRespo
3438
try:
3539
count = service.waitlist_count()
3640
except PersistenceError as exc:
37-
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc))
41+
raise HTTPException(
42+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)
43+
)
3844

3945
return WaitlistCountResponse(count=count)

0 commit comments

Comments
 (0)