diff --git a/.env.example b/.env.example index 9dddec0..200a7ff 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ MAIL_USERNAME=xxxx MAIL_PASSWORD=xxxx SUPPRESS_SEND=xxxx +DATABASE_URI=xxxx diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 43e76d0..f6da36e 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -119,6 +119,9 @@ jobs: runs-on: "ubuntu-18.04" steps: - uses: actions/checkout@v2 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha }} - name: "Prepare test data directory" env: diff --git a/config/settings.py b/config/settings.py index 0ad8198..c588f21 100644 --- a/config/settings.py +++ b/config/settings.py @@ -17,3 +17,7 @@ TEMPLATE_FOLDER="templates", SUPPRESS_SEND=getenv("SUPPRESS_SEND", 0), ) + + +class AppConfig: + SQLALCHEMY_DATABASE_URL = getenv("DATABASE_URI") diff --git a/docker-compose.yml b/docker-compose.yml index 4afeaf0..fddd70e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,3 +21,19 @@ services: - 8000:8000 volumes: - .:/usr/src/app + + postgres: + image: postgres:13.3-alpine + environment: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_DB: postgres + networks: + - backend + volumes: + - gambley_data:/var/lib/postgresql/data + + +volumes: + gambley_data: + name: gambley_data diff --git a/requirements/prod.txt b/requirements/prod.txt index 257fc94..29f329c 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -17,3 +17,7 @@ requests==2.25.1 # Dependencies for emails fastapi-mail==0.4.0 + +# Dependency for database +SQLAlchemy==1.4.21 +psycopg2-binary==2.9.1 diff --git a/src/dependencies.py b/src/dependencies.py index 59a4923..0d24a54 100644 --- a/src/dependencies.py +++ b/src/dependencies.py @@ -1,6 +1,21 @@ from fastapi_mail import FastMail +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from config.settings import AppConfig from config.settings import mail_config +def db_factory(): + _engine = create_engine(AppConfig.SQLALCHEMY_DATABASE_URL) + SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=_engine) + + db = SessionLocal() + + try: + yield db + finally: + db.close() + + fast_mail = FastMail(mail_config) diff --git a/src/routers/email/routes.py b/src/routers/email/routes.py index 0cf3b42..d781691 100644 --- a/src/routers/email/routes.py +++ b/src/routers/email/routes.py @@ -4,14 +4,14 @@ from fastapi_mail import MessageSchema from ...dependencies import fast_mail -from .models import Email +from .schema import EmailSchema router = APIRouter() @router.post("/new", response_class=UJSONResponse, status_code=202) -async def send_email(background_task: BackgroundTasks, email: Email) -> UJSONResponse: +async def send_email(background_task: BackgroundTasks, email: EmailSchema) -> UJSONResponse: request_body = email.dict() message = MessageSchema( diff --git a/src/routers/email/models.py b/src/routers/email/schema.py similarity index 85% rename from src/routers/email/models.py rename to src/routers/email/schema.py index d42f9df..08b8dd1 100644 --- a/src/routers/email/models.py +++ b/src/routers/email/schema.py @@ -4,7 +4,7 @@ from pydantic import EmailStr -class Email(BaseModel): +class EmailSchema(BaseModel): receiver: List[EmailStr] subject: str template_name: str diff --git a/src/routers/user/__init__.py b/src/routers/user/__init__.py new file mode 100644 index 0000000..3a27ef1 --- /dev/null +++ b/src/routers/user/__init__.py @@ -0,0 +1 @@ +from .routes import router diff --git a/src/routers/user/models.py b/src/routers/user/models.py new file mode 100644 index 0000000..c24c477 --- /dev/null +++ b/src/routers/user/models.py @@ -0,0 +1,20 @@ +from sqlalchemy import Boolean +from sqlalchemy import Column +from sqlalchemy import Integer +from sqlalchemy import String +from sqlalchemy.ext.declarative import declarative_base + +from .utils import AnalyticsMixin +from .utils import UpdatesMixin + + +Base = declarative_base() + + +class User(Base, AnalyticsMixin, UpdatesMixin): + __tablename__ = "users" + + id = Column(Integer, primary_key=True, index=True) + is_active = Column(Boolean, default=True) + username = Column(String, unique=True) + email = Column(String, unique=True) diff --git a/src/routers/user/utils.py b/src/routers/user/utils.py new file mode 100644 index 0000000..9ff5240 --- /dev/null +++ b/src/routers/user/utils.py @@ -0,0 +1,21 @@ +from datetime import datetime + +from sqlalchemy import Column +from sqlalchemy import DateTime +from sqlalchemy import String +from sqlalchemy.ext.declarative import declarative_base + + +Base = declarative_base() + + +class AnalyticsMixin(Base): + current_sign_in_on = Column(DateTime, default=datetime.utcnow) + last_sign_in_on = Column(DateTime, default=datetime.utcnow) + current_sign_in_ip = Column(String) + last_sign_in_ip = Column(String) + + +class UpdatesMixin(Base): + created_on = Column(DateTime, default=datetime.utcnow) + updated_on = Column(DateTime, default=datetime.utcnow)