diff --git a/app/Dockerfile b/app/Dockerfile index 8175c46..bf03d2d 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -1,15 +1,15 @@ # using ubuntu LTS version -FROM ubuntu:20.04 AS builder-image +FROM ubuntu:22.04 AS builder-image # avoid stuck build due to user prompt ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install --no-install-recommends -y python3.9 python3.9-dev python3.9-venv python3-pip python3-wheel build-essential && \ +RUN apt-get update && apt-get install --no-install-recommends -y python3.10 python3.10-dev python3.10-venv python3-pip python3-wheel build-essential && \ apt-get clean && rm -rf /var/lib/apt/lists/* # create and activate virtual environment # using final folder name to avoid path issues with packages -RUN python3.9 -m venv /home/myuser/venv +RUN python3 -m venv /home/myuser/venv ENV PATH="/home/myuser/venv/bin:$PATH" # install requirements @@ -17,18 +17,18 @@ COPY requirements.txt . RUN pip3 install --no-cache-dir wheel RUN pip3 install --no-cache-dir -r requirements.txt -FROM ubuntu:20.04 AS runner-image -RUN apt-get update && apt-get install --no-install-recommends -y python3.9 python3-venv && \ +FROM ubuntu:22.04 AS runner-image +RUN apt-get update && apt-get install --no-install-recommends -y python3.10 python3-venv && \ apt-get clean && rm -rf /var/lib/apt/lists/* RUN useradd --create-home myuser COPY --from=builder-image /home/myuser/venv /home/myuser/venv -USER myuser RUN mkdir /home/myuser/code WORKDIR /home/myuser/code/app COPY . . - +RUN chown -R myuser:myuser /home/myuser +USER myuser EXPOSE 5000 # make sure all messages always reach console @@ -37,7 +37,7 @@ ENV PYTHONUNBUFFERED=1 # activate virtual environment ENV VIRTUAL_ENV=/home/myuser/venv ENV PATH="/home/myuser/venv/bin:$PATH" -ENV FLASK_APP=app:app.py +ENV FLASK_APP=app ENV FLASK_ENV=development ENV FLASK_DEBUG=1 # /dev/shm is mapped to shared memory and should be used for gunicorn heartbeat diff --git a/app/config.py b/app/config.py index 8684c60..a426c61 100644 --- a/app/config.py +++ b/app/config.py @@ -2,12 +2,12 @@ # -*- coding: utf-8 -*- # standard python imports -mssql = {'host': 'dbhost', +mssql = {'host': 'database', 'user': 'dbuser', 'passwd': 'dbPwd', 'db': 'db'} -postgresql = {'host': '0.0.0.0', +postgresql = {'host': 'database', 'user': 'postgres', 'passwd': 'magical_password', 'db': 'db'} diff --git a/app/requirements.txt b/app/requirements.txt index 641f33c..64fe924 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -1,11 +1,11 @@ -Flask==2.0.1 -Flask-RESTful==0.3.9 -Flask-SQLAlchemy==2.5.1 -Jinja2==3.0.1 -Flask-JWT-Extended==4.2.1 -python-dateutil==2.8.1 -pytz==2021.1 -SQLAlchemy==1.4.19 -Werkzeug==2.0.1 +Flask==2.3.2 +Flask-RESTful==0.3.10 +Flask-SQLAlchemy==3.0.5 +Jinja2==3.1.2 +Flask-JWT-Extended==4.5.2 +python-dateutil==2.8.2 +pytz==2023.3 +SQLAlchemy==2.0.19 +Werkzeug==2.3.6 psycopg2-binary -rich \ No newline at end of file +rich==13.4.2 diff --git a/app/resources/user.py b/app/resources/user.py index 03d1e5a..b2ff661 100644 --- a/app/resources/user.py +++ b/app/resources/user.py @@ -2,8 +2,8 @@ # -*- coding: utf-8 -*- # standard python imports -from flask_restful import Resource, reqparse -from flask import jsonify +from flask_restful import Resource +from flask import jsonify, request from flask_jwt_extended import create_access_token, jwt_required from flask_jwt_extended import current_user from app.models.user import UserModel @@ -16,14 +16,9 @@ class User(Resource): def __init__(self): self.logger = create_logger() - parser = reqparse.RequestParser() # only allow price changes, no name changes allowed - parser.add_argument('username', type=str, required=True, - help='This field cannot be left blank') - parser.add_argument('password', type=str, required=True, - help='This field cannot be left blank') def post(self): - data = User.parser.parse_args() + data = request.get_json(force=True) username = data['username'] password = data['password'] @@ -49,14 +44,9 @@ class UserRegister(Resource): def __init__(self): self.logger = create_logger() - parser = reqparse.RequestParser() # only allow price changes, no name changes allowed - parser.add_argument('username', type=str, required=True, - help='This field cannot be left blank') - parser.add_argument('password', type=str, required=True, - help='This field cannot be left blank') def post(self): - data = UserRegister.parser.parse_args() + data = request.get_json(force=True) if UserModel.find_by_username(data['username']): return {'message': 'UserModel has already been created, aborting.'}, 400 diff --git a/docker-compose.yml b/docker-compose.yml index 3e061ff..4356372 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,7 @@ version: '3.7' services: app: + hostname: app build: ./app restart: always ports: @@ -10,6 +11,7 @@ services: - database database: + hostname: database image: postgres:latest # use latest official postgres version env_file: - postgres.env # configure postgres diff --git a/readme.md b/readme.md index 14f8bac..4aa2066 100644 --- a/readme.md +++ b/readme.md @@ -11,13 +11,18 @@ on Udemy. https://www.udemy.com/course/rest-api-flask-and-python/learn/lecture/6 ### Example endpoints #### Add user -`curl -d "username=user1&password=abcd" -X POST http://localhost:5000/register` +`curl -X POST http://localhost:5000/register -H "Content-Type: application/json" -d '{"username": "luna", "password": "badgirl"}'` #### Login ###### _`(Returns Auth Token)`_ -`curl -d "username=user1&password=abcd" -X POST http://localhost:5000/user` +`curl -X POST http://localhost:5000/user -H "Content-Type: application/json" -d '{"username": "luna", "password": "badgirl"}'` -#### Add Item +### Grab token in variable +`export JWT=$(curl -s -X POST http://localhost:5000/user -H "Content-Type: application/json" -d @creds.json | jq .access_token)` + +#### Add Store ###### _`(Replace with Auth Token)`_ -`curl -XGET -d "store_id=1&price=2.309" \ - -H "Authorization: Bearer paste_token_here http://localhost:5000/item/xyz` +`curl -X POST http://localhost:5000/store/xyz -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" -H "Accepts: application/json" ` + +### Add Item +`curl -X POST http://localhost:5000/item/apple -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" -H "Accepts: application/json" -d '{"store_id": 1, "price": "2.40"}'`