Skip to content

Commit

Permalink
feat: add holiday check
Browse files Browse the repository at this point in the history
  • Loading branch information
Will413028 committed Feb 1, 2024
1 parent 7d354b9 commit 18643f3
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 7 deletions.
34 changes: 33 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,36 @@ DB_USER=
DB_PASS=
DB_NAME=
WORKDAY_CUT_OFF_TIME=
MINIMUM_WORKING_HOURS=
MINIMUM_WORKING_HOURS=
HOLIDAYS_API_URL=
HOLIDAYS_API_KEY=
COUNTRY=



3. Create a Workload Identity on Google Cloud with gcloud
export GITHUB_REPO=Will413028/attendance-system-fastapi

export PROJECT_ID=evident-airline-412703

export SERVICE_ACCOUNT=github-actions-service-account

export WORKLOAD_IDENTITY_POOL=gh-pool

export WORKLOAD_IDENTITY_PROVIDER=gh-provider


echo $WORKLOAD_IDENTITY_PROVIDER_LOCATION

projects/227244282831/locations/global/workloadIdentityPools/gh-pool/providers/gh-provider


echo $SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

github-actions-service-account@evident-airline-412703.iam.gserviceaccount.com

test
DATABASE_URL=mysql+pymysql://myuser:12345678@localhost:3306/attendance-system

google sql
DATABASE_URL=mysql+pymysql://root:[email protected]:3306/attendance-system
3 changes: 3 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
DB_NAME: ${{ secrets.DB_NAME }}
WORKDAY_CUT_OFF_TIME: ${{ secrets.WORKDAY_CUT_OFF_TIME }}
MINIMUM_WORKING_HOURS: ${{ secrets.MINIMUM_WORKING_HOURS }}
HOLIDAYS_API_URL: ${{ secrets.HOLIDAYS_API_URL }}
HOLIDAYS_API_KEY: ${{ secrets.HOLIDAYS_API_KEY }}
COUNTRY: ${{ secrets.COUNTRY }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand Down
3 changes: 3 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ class Settings(BaseSettings):
db_name: str
workday_cut_off_time: str
minimum_working_hours: int
holidays_api_url: str
holidays_api_key: str
country: str

class Config:
env_file = ".env"
2 changes: 1 addition & 1 deletion database.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from sqlalchemy import create_engine, DateTime, Integer
from sqlalchemy.orm import sessionmaker, DeclarativeBase, mapped_column
from sqlalchemy.sql import func
from google.cloud.sql.connector import Connector
from google.cloud.sql.connector import Connector, create_async_connector

from config import Settings

Expand Down
4 changes: 2 additions & 2 deletions dependencies.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from fastapi import Depends, HTTPException, status
from sqlalchemy.orm import Session

import models, schemas, utils, service
import models, schemas, utils.auth as auth, service
from database import get_db


Expand All @@ -18,6 +18,6 @@ def authenticate_user(data: schemas.LoginInput, db: Session = Depends(get_db)) -

if not db_user:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='User not found')
if not utils.verify_password(data.password, db_user.password):
if not auth.verify_password(data.password, db_user.password):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid password or email')
return db_user
2 changes: 1 addition & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import models
import schemas
import service
import jwt
from utils import jwt
from config import Settings
from database import get_db

Expand Down
30 changes: 28 additions & 2 deletions service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from typing import Optional
from datetime import datetime, date, timedelta
import requests

from fastapi import HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import select, func

import models
import schemas
import utils
from utils import auth
from utils.decorators import cache_holiday_check
from config import Settings


Expand Down Expand Up @@ -48,7 +50,7 @@ def get_all_attendance_records(db: Session, attendance_type: Optional[str] = Non


def create_user(db: Session, user: schemas.UserCreateInput):
user.password = utils.get_password_hash(user.password)
user.password = auth.get_password_hash(user.password)
db_user = models.User(**user.model_dump())

db.add(db_user)
Expand Down Expand Up @@ -100,6 +102,9 @@ def create_attendance(db: Session, user_id: schemas.AttendanceRecordUpdateInput,

workday = get_workday(current_time, config.workday_cut_off_time)

if is_holiday(workday, config.country, config.holidays_api_key, config.holidays_api_url):
raise HTTPException(status_code=400, detail="Cannot record attendance on holidays")

today_attendance_record = get_user_attendance_by_workday(db, user_id, workday)

if today_attendance_record:
Expand Down Expand Up @@ -176,3 +181,24 @@ def is_leave_early(time_in: datetime, minimum_working_hours: int, current_time:
working_hours = (current_time - time_in).total_seconds() / 3600

return working_hours < minimum_working_hours


@cache_holiday_check
def is_holiday(date: date, country: str, holidays_api_key: str, holidays_api_url: str) -> bool:
params = {
"api_key": holidays_api_key,
"country": country,
"year": date.year,
"month": date.month,
"day": date.day,
}
try:
response = requests.get(holidays_api_url, params=params)
response.raise_for_status()
data = response.json()
holidays = data.get('response', {}).get('holidays', [])

return len(holidays) > 0
except requests.RequestException as e:
print(e)
return False
1 change: 1 addition & 0 deletions utils.py → utils/auth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from passlib.context import CryptContext


pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


Expand Down
16 changes: 16 additions & 0 deletions utils/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from functools import wraps


def cache_holiday_check(func):
holiday_cache = {}

@wraps(func)
def wrapper_check_holiday(date, *args, **kwargs):
if date in holiday_cache:
print('has ')

return holiday_cache[date]
is_holiday = func(date, *args, **kwargs)
holiday_cache[date] = is_holiday
return is_holiday
return wrapper_check_holiday
File renamed without changes.

0 comments on commit 18643f3

Please sign in to comment.