Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
DATABASE_URL = "postgres://localhost:5432/feeling"
PGUSER = "postgres"
API_URL = "http://localhost:3000"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pip-delete-this-directory.txt
# Virtual Environment
venv

# pytest
.pytest_cache

# JavaScript
node_modules

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,9 @@ npm run develop
```bash
npm run stop-database
```

6. To stop the database when you're finished:

```bash
npm run stop-database
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"develop": "sls offline start",
"migrate": "alembic revision -m",
"upgrade": "alembic upgrade",
"test": "pytest",
"start-database": "docker-compose up -d",
"stop-database": "docker-compose down"
},
Expand Down
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
black
pylint
pytest
SQLAlchemy==1.2.15
psycopg2-binary==2.7.6.1
python-dotenv==0.10.1
alembic==1.0.5
argon2-cffi==18.3.0
jsonschema==2.6.0
jsonschema==2.6.0
requests==2.22.0
6 changes: 3 additions & 3 deletions serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ functions:
method: delete
cors: true

put_settings:
handler: src/functions/settings.put
post_settings:
handler: src/functions/settings.post
events:
- http:
path: /settings
method: put
method: post
cors: true

get_settings:
Expand Down
Empty file added src/__init__.py
Empty file.
4 changes: 2 additions & 2 deletions src/functions/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ def get(event, context, session):
@database
@token_required
@validate(schema)
def put(event, context, session):
def post(event, context, session):
body = event["body"]
user_id = event["user_id"]

# Update settings in database
settings = Settings(user_id, body)
session.add(settings)
session.merge(settings)
session.commit()

return {"statusCode": 200}
3 changes: 3 additions & 0 deletions src/models/Settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ def __init__(self, user_id, settings):
self.user_id = user_id
self.settings = settings

def toJson(self):
return {"id": self.id, "user_id": self.user_id, "settings": self.settings}

def __repr__(self):
return "<Settings(id='{}', user_id='{}' settings='{}', created_at='{}', updated_at='{}')>".format(
self.id, self.user_id, self.settings, self.created_at, self.updated_at
Expand Down
2 changes: 1 addition & 1 deletion src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# Create tables if they do not exist
Base.metadata.create_all(database)

# create a Session
# Create a Session
Session = sessionmaker(bind=database)
session = Session()

Expand Down
2 changes: 1 addition & 1 deletion src/utils/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def wrap_function(*args):


def token_required(function):
"""Decorator handle access tokens"""
"""Decorator to handle access tokens"""

def wrap_function(*args):
event = args[0]
Expand Down
Empty file added tests/__init__.py
Empty file.
50 changes: 50 additions & 0 deletions tests/test_quote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import requests
from dotenv import load_dotenv
from pytest import fixture

from src.consts import Emotion
from src.models import Quote

from .utils import base_url, session, token


@fixture
def quote(session):
"""Adds a temporary quote to the database"""

quote = Quote(
"To escape criticism: do nothing, say nothing, be nothing.",
"Elbert Hubbard",
Emotion.UPSET,
)
session.add(quote)
session.commit()

yield quote

session.query(Quote).filter(Quote.id == quote.id).delete()
session.commit()


def test_get_a_quote(base_url, token, quote):
"""Fetch a random quote"""

emotion = quote.emotion.name.lower()

url = f"{base_url}/quote/{emotion}"
response = requests.get(url)
json = response.json()

assert response.status_code == 200
assert json["emotion"].lower() == emotion


def test_get_a_quote_with_unknown_emotion(base_url, token, quote):
"""Attempt to fetch a quote but emotion is not valid"""

emotion = "meh"

url = f"{base_url}/quote/{emotion}"
response = requests.get(url)

assert response.status_code == 400
50 changes: 50 additions & 0 deletions tests/test_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import requests
from dotenv import load_dotenv
from pytest import fixture

from src.models import Settings

from .utils import base_url, session, token


@fixture
def settings(session, user):
settings = Settings(
user.id,
{"daily_reminder": {"enabled": True, "time": {"hour": 20, "minute": 00}}},
)
session.add(settings)
session.commit()

yield settings

session.query(Settings).filter(Settings.id == settings.id).delete()
session.commit()


def test_get_settings(base_url, token, settings):
"""Fetch a user's settings"""

url = f"{base_url}/settings"
response = requests.get(url, headers={"Authorization": f"Bearer {token}"})
json = response.json()

assert response.status_code == 200
assert json.settings == settings.toJson()


def test_update_settings(base_url, token, settings):
"""Update a user's settings"""

new_settings = {
"daily_reminder": {"enabled": False, "time": {"hour": 21, "minute": 30}}
}

url = f"{base_url}/settings"
response = requests.post(
url, headers={"Authorization": f"Bearer {token}"}, data=new_settings
)
json = response.json()

assert response.status_code == 200
assert json.settings == new_settings
51 changes: 51 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import os

from pytest import fixture
from dotenv import load_dotenv
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from src.models import User


@fixture()
def base_url():
load_dotenv()
return os.getenv("API_URL")


@fixture()
def session():
"""Create a SQLAlchemy database session"""

# Set environment variables from .env
load_dotenv()

# Connect to database
database_url = os.getenv("DATABASE_URL")
database = create_engine(database_url)

# Create a session
SessionMaker = sessionmaker(bind=database)
created_session = SessionMaker()

yield created_session

created_session.close()


@fixture
def user(session):
user = User("Michael", "Lee", "michael_lee@gmail.com", "password")
session.add(user)
session.commit()

yield user

session.query(User).filter(User.id == user.id).delete()
session.commit()


@fixture
def token(session):
return None