diff --git a/.github/jamstack@2x.png b/.github/jamstack@2x.png deleted file mode 100644 index a8735410..00000000 Binary files a/.github/jamstack@2x.png and /dev/null differ diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 23812d92..b76acd8a 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -21,7 +21,7 @@ jobs: - name: "auth" uses: "google-github-actions/auth@v1" with: - credentials_json: ${{ secrets.GOOGLE_CLOUD_JSON_KEY }} + credentials_json: ${{ secrets.GOOGLE_CREDENTIALS }} - name: Lint with flake8 run: | diff --git a/Makefile b/Makefile index f62ebbb8..e576f403 100644 --- a/Makefile +++ b/Makefile @@ -59,8 +59,9 @@ deploy: .PHONY: test test: env - $(shell . $(VIRTUAL_ENV)/bin/activate) && \ - coverage run -m pytest -vv \ + $(shell . $(VIRTUAL_ENV)/bin/activate) + poetry config virtualenvs.path $(VIRTUAL_ENV) + $(LOCAL_PYTHON) -m coverage run -m pytest -vv \ --disable-pytest-warnings && \ coverage html --title='Coverage Report' -d .reports && \ open .reports/index.html diff --git a/app/accounts/__init__.py b/app/accounts/__init__.py index bb334690..f4e15623 100644 --- a/app/accounts/__init__.py +++ b/app/accounts/__init__.py @@ -4,56 +4,13 @@ from config import settings from database import ghost_db -from database.crud import create_account, get_account +from database.crud import get_account from database.orm import get_db -from database.schemas import NetlifyAccountCreationResponse, NetlifyUserEvent from log import LOGGER router = APIRouter(prefix="/account", tags=["accounts"]) -@router.post( - "/", - summary="Create new account from Netlify", - description="Create user account sourced from Netlify Identity.", - response_model=NetlifyAccountCreationResponse, -) -async def new_account(new_account_event: NetlifyUserEvent, db: Session = Depends(get_db)): - """ - Create user account from Netlify identity signup. - - :param NetlifyUserEvent new_account_event: Newly created user account from Netlify. - :param Session db: ORM Database session. - - :returns: NetlifyAccountCreationResponse - """ - account = new_account_event.user - db_account = get_account(db, account.email) - if db_account: - LOGGER.warning(f"User account already exists for `{account.email}`.") - raise HTTPException( - status_code=400, - detail=f"User account already exists for `{account.email}`.", - ) - create_account(db, account) - db_account_created = get_account(db, account.email) - if db_account_created: - LOGGER.success( - f"Account created: id={account.id} email={account.email}, name={account.user_metadata.full_name}" - ) - return NetlifyAccountCreationResponse( - succeeded=new_account_event, - failed=None, - ) - LOGGER.warning( - f"Account not created: id={account.id} email={account.email}, name={account.user_metadata.full_name}" - ) - return NetlifyAccountCreationResponse( - succeeded=None, - failed=new_account_event, - ) - - @router.get( "/comments/", summary="Get all user comments.", @@ -65,8 +22,10 @@ async def get_comments(): :returns: List[Comment] """ - comments = ghost_db.execute_query_from_file( - f"{settings.BASE_DIR}/database/queries/comments/selects/get_comments.sql" - ).fetchall() + sql_query = "" + with open(f"{settings.BASE_DIR}/database/queries/comments/get_comments.sql", "r", encoding="utf-8") as f: + sql_query = f.read() + comments = ghost_db.execute_query(sql_query).fetchall() + comments = [dict(r._mapping) for r in comments] LOGGER.success(f"Successfully fetched {len(comments)} Ghost comments.") return comments diff --git a/app/posts/test_posts/test_read.py b/app/posts/test_posts/test_read.py index ce6377f8..d9fff166 100644 --- a/app/posts/test_posts/test_read.py +++ b/app/posts/test_posts/test_read.py @@ -1,6 +1,4 @@ """Test reading data directly form SQL databases.""" -from sqlalchemy.engine.cursor import CursorResult - from database.read_sql import collect_sql_queries, fetch_sql_files, parse_sql_batch from database.sql_db import Database from log import LOGGER diff --git a/database/crud.py b/database/crud.py index 69452677..ce7935d2 100644 --- a/database/crud.py +++ b/database/crud.py @@ -6,7 +6,7 @@ from sqlalchemy.orm import Session from database.models import Account, Donation -from database.schemas import NetlifyAccount, NewDonation +from database.schemas import NewDonation from log import LOGGER @@ -67,36 +67,3 @@ def get_account(db: Session, account_email: str) -> Optional[Result]: :returns: Optional[Result] """ return db.query(Account).filter(Account.email == account_email).first() - - -def create_account(db: Session, account: NetlifyAccount) -> NetlifyAccount: - """ - Create new account record sourced from Netlify. - - :param Session db: ORM database session. - :param account: User comment schema object. - :param NetlifyAccount account: User account registered via Netlify. - - :returns: NetlifyAccount - """ - try: - new_account = Account( - id=account.id, - full_name=account.user_metadata.full_name, - avatar_url=account.user_metadata.avatar_url, - email=account.email, - role=account.role, - provider=account.app_metadata.provider, - created_at=datetime.now(), - updated_at=datetime.now(), - ) - db.add(new_account) - db.commit() - LOGGER.success(f"New Netlify account created: `{account.user_metadata.full_name}`") - return account - except IntegrityError as e: - LOGGER.error(f"DB IntegrityError while creating Netlify user account: {e}") - except SQLAlchemyError as e: - LOGGER.error(f"SQLAlchemyError while creating Netlify user account: {e}") - except Exception as e: - LOGGER.error(f"Unexpected error while creating Netlify user account: {e}") diff --git a/database/queries/comments/get_comments.sql b/database/queries/comments/get_comments.sql new file mode 100644 index 00000000..732dc4e7 --- /dev/null +++ b/database/queries/comments/get_comments.sql @@ -0,0 +1,14 @@ +SELECT + id, + post_id, + member_id, + parent_id, + html, + edited_at, + created_at +FROM + comments +WHERE + status = 'published' +ORDER BY + edited_at DESC; \ No newline at end of file diff --git a/database/schemas.py b/database/schemas.py index 0aa83065..b0e453bb 100644 --- a/database/schemas.py +++ b/database/schemas.py @@ -326,49 +326,6 @@ class Config: # fmt: on -class NetlifyUserMetadata(BaseModel): - avatar_url: Optional[str] = Field(None, example="https://example.com/dsfdsf.jpg") - full_name: str = Field(None, example="Fake Name") - roles: Optional[List[str]] = Field(None, example=["admin"]) - - -class NetlifyUserAppMetadata(BaseModel): - provider: str = Field(None, example="google") - - -class NetlifyAccount(BaseModel): - id: str = Field(None, example="4e7c4f1b-e51a-4abb-8a58-105483724713") - aud: str = Field(None, example="") - email: str = Field(None, example="fake@example.com") - role: Optional[str] = Field(None, example="Moderator") - app_metadata: NetlifyUserAppMetadata - user_metadata: NetlifyUserMetadata - created_at: str = Field(None, example="2021-03-06T13:26:56.991731Z") - updated_at: str = Field(None, example="2021-03-06T14:26:56.991731Z") - - class Config: - json_schema_extra = { - "id": "4e7c4f1b-e51a-4abb-8a58-105483724713", - "aud": "", - "email": "fake@example.com", - "role": "Moderator", - "app_metadata": {"provider": "google"}, - "user_metadata": { - "avatar_url": "https://example.com/dsfdsf.jpg", - "full_name": "Fake Name", - "roles": ["admin"], - }, - "created_at": "2021-03-06T14:26:56.991731Z", - "updated_at": "2021-03-06T14:26:56.994492Z", - } - - -class NetlifyUserEvent(BaseModel): - event: str = Field(None, example="signup") - instance_id: str = Field(None, example="725df7e1-94b8-4b0f-8d45-dc710d8d1a47") - user: NetlifyAccount - - class GhostMember(BaseModel): """Ghost Member account.""" @@ -387,11 +344,6 @@ class GhostMember(BaseModel): # fmt: on -class NetlifyAccountCreationResponse(BaseModel): - succeeded: Union[NetlifyUserEvent, None] - failed: Union[NetlifyUserEvent, None] - - class NewsletterSubscriber(BaseModel): """Ghost email subscriber (may not have account).""" diff --git a/database/sql_db.py b/database/sql_db.py index 5c45a4aa..98631d47 100644 --- a/database/sql_db.py +++ b/database/sql_db.py @@ -62,18 +62,18 @@ def execute_query(self, query: str) -> Optional[CursorResult]: except SQLAlchemyError as e: LOGGER.error(f"Failed to execute SQL query {query}: {e}") - def execute_query_from_file(self, sql_file: str) -> Union[Result, str]: + def execute_query_from_file(self, sql_file: str) -> Optional[CursorResult]: """ Execute single SQL query. :param str sql_file: Filepath of SQL query to run. - :returns: Union[Result, str] + :returns: Optional[CursorResult] """ try: with self.db.begin() as conn: with open(sql_file, "r", encoding="utf-8") as query: - return conn.execute(query) + return conn.execute(text(query)) except SQLAlchemyError as e: LOGGER.error(f"SQLAlchemyError while executing SQL `{sql_file}`: {e}") return f"Failed to execute SQL `{sql_file}`: {e}"