Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit 6485fd6

Browse files
authored
feat: add black & flake8 auto format config for vscode (#70)
* feat: add black & flake8 auto format config for vscode * chore: update README.md for auto formatting by vscode extention
1 parent 28c7326 commit 6485fd6

File tree

7 files changed

+168
-103
lines changed

7 files changed

+168
-103
lines changed

.vscode/extensions.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"recommendations": [
3+
"ms-python.python",
4+
"ms-python.flake8",
5+
"ms-python.black-formatter"
6+
]
7+
}

.vscode/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"[python]": {
4+
"editor.defaultFormatter": "ms-python.black-formatter"
5+
},
6+
"flake8.args": ["--max-line-length=88", "--ignore=E203,W503,W504"]
7+
}

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ You can clone the front-end template from:
6161

6262
## Note
6363

64+
### How to enable Python code formatter (black) and linter (flake8) with VSCode extension
65+
66+
If you're [VS Code](https://code.visualstudio.com/) user, you can easily setup Python code formatter (black) and linter (flake8) by simply installing the extensions.
67+
68+
Automatic formatting settings have already been defined here:
69+
70+
`.vscode/settings.json`
71+
72+
Just install following:
73+
74+
- [Black Formatter](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter)
75+
- [Flake8](https://marketplace.visualstudio.com/items?itemName=ms-python.flake8)
76+
6477
### How to check the DB tables in container
6578

6679
You can check the DB data by actually executing a query using the following command:

api/database/query.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
from pathlib import Path
21
import os
32
import pymysql.cursors
43
from pymysql import converters
54

65

76
converions = converters.conversions
8-
converions[pymysql.FIELD_TYPE.BIT] = lambda x: False if x == b'\x00' else True
7+
converions[pymysql.FIELD_TYPE.BIT] = lambda x: False if x == b"\x00" else True
98

109

1110
def init_connection():
12-
connection = pymysql.connect(host=os.getenv("DATABASE_HOST"),
13-
port=3306,
14-
user=os.environ.get("DATABASE_USERNAME"),
15-
password=os.environ.get("DATABASE_PASSWORD"),
16-
database=os.environ.get("DATABASE"),
17-
cursorclass=pymysql.cursors.DictCursor,
18-
conv=converions)
11+
connection = pymysql.connect(
12+
host=os.getenv("DATABASE_HOST"),
13+
port=3306,
14+
user=os.environ.get("DATABASE_USERNAME"),
15+
password=os.environ.get("DATABASE_PASSWORD"),
16+
database=os.environ.get("DATABASE"),
17+
cursorclass=pymysql.cursors.DictCursor,
18+
conv=converions,
19+
)
1920
return connection
2021

2122

api/main.py

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
from fastapi import FastAPI, HTTPException, Security
1+
from fastapi import FastAPI, Security
22
from fastapi.middleware.cors import CORSMiddleware
3-
from database.query import query_get, query_put, query_update
43
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
54
from fastapi.responses import JSONResponse
65
from fastapi.encoders import jsonable_encoder
7-
from user import Auth, SignInRequestModel, SignUpRequestModel, UserAuthResponseModel, UserUpdateRequestModel, UserResponseModel, register_user, signin_user, update_user, get_all_users, get_user_by_id
6+
from user import (
7+
Auth,
8+
SignInRequestModel,
9+
SignUpRequestModel,
10+
UserAuthResponseModel,
11+
UserUpdateRequestModel,
12+
UserResponseModel,
13+
register_user,
14+
signin_user,
15+
update_user,
16+
get_all_users,
17+
get_user_by_id,
18+
)
819

920
app = FastAPI()
1021

@@ -14,7 +25,7 @@
1425
"http://localhost:3000",
1526
"http://localhost:3001",
1627
"http://localhost:4000",
17-
"http://localhost:19006"
28+
"http://localhost:19006",
1829
]
1930
app.add_middleware(
2031
CORSMiddleware,
@@ -28,98 +39,124 @@
2839
auth_handler = Auth()
2940

3041

42+
"""
3143
###############################
3244
########## Auth APIs ##########
3345
###############################
46+
"""
47+
3448

35-
@app.post('/v1/signup', response_model=UserAuthResponseModel)
49+
@app.post("/v1/signup", response_model=UserAuthResponseModel)
3650
def signup_api(user_details: SignUpRequestModel):
3751
"""
3852
This sign-up API allow you to register your account, and return access token.
3953
"""
4054
user = register_user(user_details)
4155
access_token = auth_handler.encode_token(user_details.email)
4256
refresh_token = auth_handler.encode_refresh_token(user_details.email)
43-
return JSONResponse(status_code=200, content={'token': {'access_token': access_token, 'refresh_token': refresh_token}, 'user': user})
57+
return JSONResponse(
58+
status_code=200,
59+
content={
60+
"token": {"access_token": access_token, "refresh_token": refresh_token},
61+
"user": user,
62+
},
63+
)
4464

4565

46-
@app.post('/v1/signin', response_model=UserAuthResponseModel)
66+
@app.post("/v1/signin", response_model=UserAuthResponseModel)
4767
def signin_api(user_details: SignInRequestModel):
4868
"""
4969
This sign-in API allow you to obtain your access token.
5070
"""
5171
user = signin_user(user_details.email, user_details.password)
52-
access_token = auth_handler.encode_token(user['email'])
53-
refresh_token = auth_handler.encode_refresh_token(user['email'])
54-
return JSONResponse(status_code=200, content={'token': {'access_token': access_token, 'refresh_token': refresh_token}, 'user': user})
55-
56-
57-
@app.get('/v1/refresh-token')
72+
access_token = auth_handler.encode_token(user["email"])
73+
refresh_token = auth_handler.encode_refresh_token(user["email"])
74+
return JSONResponse(
75+
status_code=200,
76+
content={
77+
"token": {"access_token": access_token, "refresh_token": refresh_token},
78+
"user": user,
79+
},
80+
)
81+
82+
83+
@app.get("/v1/refresh-token")
5884
def refresh_token_api(refresh_token: str):
5985
"""
6086
This refresh-token API allow you to obtain new access token.
6187
"""
6288
new_token = auth_handler.refresh_token(refresh_token)
63-
return {'access_token': new_token}
89+
return {"access_token": new_token}
6490

6591

92+
"""
6693
################################
6794
########## Users APIs ##########
6895
################################
96+
"""
97+
6998

7099
@app.get("/v1/users", response_model=list[UserResponseModel])
71100
def get_all_users_api(credentials: HTTPAuthorizationCredentials = Security(security)):
72101
"""
73102
This users get API allow you to fetch all user data.
74103
"""
75104
token = credentials.credentials
76-
if (auth_handler.decode_token(token)):
105+
if auth_handler.decode_token(token):
77106
user = get_all_users()
78107
return JSONResponse(status_code=200, content=jsonable_encoder(user))
79-
return JSONResponse(status_code=401, content={'error': 'Faild to authorize'})
108+
return JSONResponse(status_code=401, content={"error": "Faild to authorize"})
80109

81110

82111
@app.get("/v1/user/{user_id}", response_model=UserResponseModel)
83-
def get_user_api(user_id: int, credentials: HTTPAuthorizationCredentials = Security(security)):
112+
def get_user_api(
113+
user_id: int, credentials: HTTPAuthorizationCredentials = Security(security)
114+
):
84115
"""
85116
This user API allow you to fetch specific user data.
86117
"""
87118
token = credentials.credentials
88-
if (auth_handler.decode_token(token)):
119+
if auth_handler.decode_token(token):
89120
user = get_user_by_id(user_id)
90121
return JSONResponse(status_code=200, content=jsonable_encoder(user))
91-
return JSONResponse(status_code=401, content={'error': 'Faild to authorize'})
122+
return JSONResponse(status_code=401, content={"error": "Faild to authorize"})
92123

93124

94125
@app.post("/v1/user/update", response_model=UserResponseModel)
95-
def update_user_api(user_details: UserUpdateRequestModel, credentials: HTTPAuthorizationCredentials = Security(security)):
126+
def update_user_api(
127+
user_details: UserUpdateRequestModel,
128+
credentials: HTTPAuthorizationCredentials = Security(security),
129+
):
96130
"""
97131
This user update API allow you to update user data.
98132
"""
99133
token = credentials.credentials
100-
if (auth_handler.decode_token(token)):
134+
if auth_handler.decode_token(token):
101135
user = update_user(user_details)
102136
return JSONResponse(status_code=200, content=jsonable_encoder(user))
103-
return JSONResponse(status_code=401, content={'error': 'Faild to authorize'})
137+
return JSONResponse(status_code=401, content={"error": "Faild to authorize"})
104138

105139

140+
"""
106141
###############################
107142
########## Test APIs ##########
108143
###############################
144+
"""
145+
109146

110-
@app.get('/secret')
147+
@app.get("/secret")
111148
def secret_data_api(credentials: HTTPAuthorizationCredentials = Security(security)):
112149
"""
113150
This secret API is just for testing. Need access token to access this API.
114151
"""
115152
token = credentials.credentials
116-
if (auth_handler.decode_token(token)):
117-
return 'Top Secret data only authorized users can access this info'
153+
if auth_handler.decode_token(token):
154+
return "Top Secret data only authorized users can access this info"
118155

119156

120-
@app.get('/not-secret')
157+
@app.get("/not-secret")
121158
def not_secret_data_api():
122159
"""
123160
This not-secret API is just for testing.
124161
"""
125-
return 'Not secret data'
162+
return "Not secret data"

api/user/auth.py

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import jwt # used for encoding and decoding jwt tokens
33
from fastapi import HTTPException # used to handle error handling
44
from passlib.context import CryptContext # used for hashing the password
5+
56
# used to handle expiry time for tokens
67
from datetime import datetime, timedelta
78

89

9-
class Auth():
10-
hasher = CryptContext(schemes=['bcrypt'])
10+
class Auth:
11+
hasher = CryptContext(schemes=["bcrypt"])
1112
secret = os.getenv("APP_SECRET_STRING")
1213

1314
def encode_password(self, password):
@@ -18,55 +19,44 @@ def verify_password(self, password, encoded_password):
1819

1920
def encode_token(self, email):
2021
payload = {
21-
'exp': datetime.utcnow() + timedelta(days=0, minutes=30),
22-
'iat': datetime.utcnow(),
23-
'scope': 'access_token',
24-
'sub': email
22+
"exp": datetime.utcnow() + timedelta(days=0, minutes=30),
23+
"iat": datetime.utcnow(),
24+
"scope": "access_token",
25+
"sub": email,
2526
}
26-
return jwt.encode(
27-
payload,
28-
self.secret,
29-
algorithm='HS256'
30-
)
27+
return jwt.encode(payload, self.secret, algorithm="HS256")
3128

3229
def decode_token(self, token):
3330
try:
34-
payload = jwt.decode(token, self.secret, algorithms=['HS256'])
35-
if (payload['scope'] == 'access_token'):
36-
return payload['sub']
31+
payload = jwt.decode(token, self.secret, algorithms=["HS256"])
32+
if payload["scope"] == "access_token":
33+
return payload["sub"]
3734
raise HTTPException(
38-
status_code=401, detail='Scope for the token is invalid')
35+
status_code=401, detail="Scope for the token is invalid"
36+
)
3937
except jwt.ExpiredSignatureError:
40-
raise HTTPException(status_code=401, detail='Token expired')
38+
raise HTTPException(status_code=401, detail="Token expired")
4139
except jwt.InvalidTokenError:
42-
raise HTTPException(status_code=401, detail='Invalid token')
40+
raise HTTPException(status_code=401, detail="Invalid token")
4341

4442
def encode_refresh_token(self, email):
4543
payload = {
46-
'exp': datetime.utcnow() + timedelta(days=0, hours=10),
47-
'iat': datetime.utcnow(),
48-
'scope': 'refresh_token',
49-
'sub': email
44+
"exp": datetime.utcnow() + timedelta(days=0, hours=10),
45+
"iat": datetime.utcnow(),
46+
"scope": "refresh_token",
47+
"sub": email,
5048
}
51-
return jwt.encode(
52-
payload,
53-
self.secret,
54-
algorithm='HS256'
55-
)
49+
return jwt.encode(payload, self.secret, algorithm="HS256")
5650

5751
def refresh_token(self, refresh_token):
5852
try:
59-
payload = jwt.decode(
60-
refresh_token, self.secret, algorithms=['HS256'])
61-
if (payload['scope'] == 'refresh_token'):
62-
email = payload['sub']
53+
payload = jwt.decode(refresh_token, self.secret, algorithms=["HS256"])
54+
if payload["scope"] == "refresh_token":
55+
email = payload["sub"]
6356
new_token = self.encode_token(email)
6457
return new_token
65-
raise HTTPException(
66-
status_code=401, detail='Invalid scope for token')
58+
raise HTTPException(status_code=401, detail="Invalid scope for token")
6759
except jwt.ExpiredSignatureError:
68-
raise HTTPException(
69-
status_code=401, detail='Refresh token expired')
60+
raise HTTPException(status_code=401, detail="Refresh token expired")
7061
except jwt.InvalidTokenError:
71-
raise HTTPException(
72-
status_code=401, detail='Invalid refresh token')
62+
raise HTTPException(status_code=401, detail="Invalid refresh token")

0 commit comments

Comments
 (0)