From 727fd6abb921199f187dbe9bffdf68eb4002174b Mon Sep 17 00:00:00 2001 From: pmoharana-cmd Date: Fri, 1 Mar 2024 19:43:31 -0500 Subject: [PATCH] intialize backed project + starter code --- .gitignore | 2 + .vscode/extensions.json | 15 ++++++ .vscode/settings.json | 22 ++++++++ README.md | 80 +++++++++++++++++++++++++++- backend/__init__.py | 0 backend/database.py | 29 ++++++++++ backend/entities/__init__.py | 0 backend/env.py | 21 ++++++++ backend/main.py | 0 backend/models/__init__.py | 0 backend/requirements.txt | 6 +++ backend/services/__init__.py | 0 backend/test/__init__.py | 0 backend/test/services/__init__.py | 0 backend/test/services/conftest.py | 24 +++++++++ backend/test/services/sample_test.py | 9 ++++ docker-compose.yml | 25 +++++++++ 17 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 backend/__init__.py create mode 100644 backend/database.py create mode 100644 backend/entities/__init__.py create mode 100644 backend/env.py create mode 100644 backend/main.py create mode 100644 backend/models/__init__.py create mode 100644 backend/requirements.txt create mode 100644 backend/services/__init__.py create mode 100644 backend/test/__init__.py create mode 100644 backend/test/services/__init__.py create mode 100644 backend/test/services/conftest.py create mode 100644 backend/test/services/sample_test.py create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c303a94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/backend/.env +__pycache__ \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..ec0d050 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,15 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "ecmel.vscode-html-css", + "ms-vscode.vscode-typescript-next", + "esbenp.prettier-vscode", + "bradlc.vscode-tailwindcss", + "vscode-icons-team.vscode-icons", + "tamasfe.even-better-toml", + "ckolkman.vscode-postgres", + "ms-python.python", + "ms-python.vscode-pylance", + "ms-python.autopep8" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c85959b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.analysis.extraPaths": ["/backend/"], + "python.testing.pytestEnabled": true, + "python.testing.unittestEnabled": false, + "python.analysis.diagnosticSeverityOverrides": { + "reportMissingParameterType": "error", + "reportGeneralTypeIssues": "error", + "reportDeprecated": "error", + "reportImportCycles": "error" + } +} diff --git a/README.md b/README.md index 8cc65fc..ac920f3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # 🧭 Compass Center's Internal Resource Management App ## 🛠 Technologies + - Next.js - TailwindCSS - TypeScript - PostgreSQL ## 📁 File Setup + ``` \compass \components // Components organized in folders related to specific pages @@ -18,9 +20,11 @@ ``` ## 🚀 To Start + Follow these steps to set up your local environment: + ``` -\\ Clone this repository +\\ Clone this repository git clone https://github.com/cssgunc/compass.git \\ Go into main folder cd compass @@ -30,6 +34,78 @@ npm install npm run dev ``` +Also add following variables inside of a .env file inside of the backend directory + +``` +\\ .env file contents + +POSTGRES_DB=compass +POSTGRES_USER=postgres +POSTGRES_PASSWORD=admin +POSTGRES_HOST=db +POSTGRES_PORT=5432 +HOST=localhost +``` + +Install necessary python packages + +``` +\\ Change directory from compass into backend directory +cd backend + +\\ Install python dependencies +pip3 install -r requirements.txt +``` + +## Backend Starter + +Follow these steps to start up Postgres database: + +Make sure you have Docker installed! + +``` + +\\ Spins up local postgres database and pgadmin +docker-compose up -d + +\\ Stop and teardown containers +docker-compose down + +\\ Stop and teardown containers + volumes (full reset) +docker-compose down -v +``` + +### Accesing pgAdmin 4 + +- First go to http://localhost:5050/ on your browser +- Log in using the credentials admin@example.com and admin +- Click **Add New Server** +- Fill in the name field with Compass (can be anything) +- Click **Connection** tab and fill in the following: + - Host name/address: db + - Maintence database: compass + - Username: postgres + - Password: admin +- Click **Save** at the bottom to add connection +- Click **Server** dropdown on the left and click through items inside the **Compass** server + +## Testing Backend Code + +- Write tests for any service you create and any function in those services +- Make sure to add docstrings detailing what the file is doing and what each test is doing +- Name all test functions with test\_[testContent]() +- Utitlize dependency injection for commonly used services + +``` +\\ Run all tests by being in the backend directory +pytest + +\\ Run specific tests by passing in file as a parameter +pytest [fileName] +``` + ## 💡 Dev Notes + - For each task, create a branch in the format '[your name]-[ticket number]-[task description]' -- Only commit your work to that branch and then make a git request to '/main' \ No newline at end of file +- Only commit your work to that branch and then make a git request to '/main' +- When creating new files in the backend and code is in python make sure to add a docstring for the file and any function you create ("""[content]"""") diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/database.py b/backend/database.py new file mode 100644 index 0000000..4c5ced7 --- /dev/null +++ b/backend/database.py @@ -0,0 +1,29 @@ +"""SQLAlchemy DB Engine and Session niceties for FastAPI dependency injection.""" + +import sqlalchemy +from sqlalchemy.orm import Session +from .env import getenv + + +def _engine_str(database: str = getenv("POSTGRES_DB")) -> str: + """Helper function for reading settings from environment variables to produce connection string.""" + dialect = "postgresql+psycopg2" + user = getenv("POSTGRES_USER") + password = getenv("POSTGRES_PASSWORD") + host = getenv("POSTGRES_HOST") + port = getenv("POSTGRES_PORT") + return f"{dialect}://{user}:{password}@{host}:{port}/{database}" + + +engine = sqlalchemy.create_engine(_engine_str(), echo=True) +"""Application-level SQLAlchemy database engine.""" + + +def db_session(): + """Generator function offering dependency injection of SQLAlchemy Sessions.""" + print("ran") + session = Session(engine) + try: + yield session + finally: + session.close() diff --git a/backend/entities/__init__.py b/backend/entities/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/env.py b/backend/env.py new file mode 100644 index 0000000..356efb7 --- /dev/null +++ b/backend/env.py @@ -0,0 +1,21 @@ +"""Load environment variables from a .env file or the process' environment.""" + +import os +import dotenv + +# Load envirnment variables from .env file upon module start. +dotenv.load_dotenv(f"{os.path.dirname(__file__)}/.env", verbose=True) + + +def getenv(variable: str) -> str: + """Get value of environment variable or raise an error if undefined. + + Unlike `os.getenv`, our application expects all environment variables it needs to be defined + and we intentionally fast error out with a diagnostic message to avoid scenarios of running + the application when expected environment variables are not set. + """ + value = os.getenv(variable) + if value is not None: + return value + else: + raise NameError(f"Error: {variable} Environment Variable not Defined") diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/models/__init__.py b/backend/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000..5c532a5 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,6 @@ +fastapi[all] >=0.100.0, <0.101.0 +sqlalchemy >=2.0.4, <2.1.0 +psycopg2 >=2.9.5, <2.10.0 +alembic >=1.10.2, <1.11.0 +pytest >=7.2.1, <7.3.0 +python-dotenv >=1.0.0, <1.1.0 \ No newline at end of file diff --git a/backend/services/__init__.py b/backend/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/test/__init__.py b/backend/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/test/services/__init__.py b/backend/test/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/test/services/conftest.py b/backend/test/services/conftest.py new file mode 100644 index 0000000..c06a731 --- /dev/null +++ b/backend/test/services/conftest.py @@ -0,0 +1,24 @@ +"""Shared pytest fixtures for database dependent tests.""" + +import pytest +from sqlalchemy import Engine +from sqlalchemy.orm import Session + +from ...database import db_session + + +@pytest.fixture(scope="session") +def test_engine() -> Engine: + session = db_session() + return session + + +@pytest.fixture(scope="function") +def session(test_engine: Engine): + # entities.EntityBase.metadata.drop_all(test_engine) + # entities.EntityBase.metadata.create_all(test_engine) + session = Session(test_engine) + try: + yield session + finally: + session.close() diff --git a/backend/test/services/sample_test.py b/backend/test/services/sample_test.py new file mode 100644 index 0000000..7d4cfbd --- /dev/null +++ b/backend/test/services/sample_test.py @@ -0,0 +1,9 @@ +"""Sample Test File""" + +import pytest +from sqlalchemy import Engine + + +def test_sample(session: Engine): + print(session) + assert session != None diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f2cabf8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: "3" + +services: + db: + image: "postgres:latest" + ports: + - "5432:5432" + env_file: + - ./backend/.env + volumes: + - compass-center-postgres:/var/lib/postgresql/data + # - ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql:ro + + pgadmin: + image: dpage/pgadmin4:latest + environment: + PGADMIN_DEFAULT_EMAIL: admin@example.com + PGADMIN_DEFAULT_PASSWORD: admin + ports: + - "5050:80" + depends_on: + - db + +volumes: + compass-center-postgres: