diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..995db1f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.8 + +ENV FLASK_APP=app.py + +ENV FLASK_RUN_HOST=0.0.0.0 + +WORKDIR /app + +COPY . . + +# Install packages +RUN pip3 install -r requirements.txt + +RUN rm site.db + +EXPOSE 5000 + +CMD ["python3", "app.py"] \ No newline at end of file diff --git a/README.md b/README.md index 00092ce..a527338 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ ### How to run the project :horse_racing: + + ##### To run locally ```sh * Clone the repository git clone https://github.com/DiptoChakrabarty/flask-online-store.git @@ -46,6 +48,23 @@ (it is preferable if you use something as postman as most are post requests) +``` + +##### To run in docker +```sh + * Set environment variables + cp .env.example .env + +* Fill the required parameters + +* If you have removed site.db then remove the following line in Dockerfile + RUN rm site.db + +* Run using + docker-compose up -d to start as background process + +* Head over to http://localhost:5000 + ``` ## Repository Structure :deciduous_tree: diff --git a/database.conf b/database.conf new file mode 100644 index 0000000..ca9734d --- /dev/null +++ b/database.conf @@ -0,0 +1,5 @@ +POSTGRES_USER=test +POSTGRES_PASSWORD=password +POSTGRES_HOST=db +POSTGRES_PORT=5432 +POSTGRES_DB=flask_online_store \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..5a20247 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,27 @@ +version: '3.8' +services: + db: + image: postgres:latest + env_file: database.conf + ports: + - 5432:5432 + volumes: + - ./db_volume:/var/lib/db + app: + build: + context: . + dockerfile: Dockerfile + env_file: + - .env + volumes: + - ./:/app + environment: + FLASK_ENV: development + FLASK_APP: ./app.py + ports: + - 5000:5000 + restart: always + depends_on: + - db +volumes: + data-volume: \ No newline at end of file diff --git a/model/__pycache__/users.cpython-36.pyc b/model/__pycache__/users.cpython-36.pyc index bfcd406..724ce59 100644 Binary files a/model/__pycache__/users.cpython-36.pyc and b/model/__pycache__/users.cpython-36.pyc differ diff --git a/model/users.py b/model/users.py index 6f26301..ebef18c 100644 --- a/model/users.py +++ b/model/users.py @@ -19,15 +19,17 @@ class UserModel(db.Model): __tablename__="users" id = db.Column(db.Integer,primary_key=True) username = db.Column(db.String(20),nullable=False,unique=True) - password = db.Column(db.String(20)) + password = db.Column(db.String(20),nullable=True) email = db.Column(db.String(40),nullable=False,unique=True) - activated = db.Column(db.Boolean,default=False) #set default as False + activated = db.Column(db.Boolean,default=False) #set default as False , if you do not email verification set as True + seller = db.Column(db.Boolean, default=False) - def __init__(self,username,password,email,activated=True): + def __init__(self,username,password,email,activated=False,seller=False): # if you do not email verification set activated as True self.username=username self.password=password self.email = email self.activated = activated + self.seller = seller def save_to_db(self): db.session.add(self) @@ -37,7 +39,6 @@ def delete_from_db(self): db.session.delete(self) db.session.commit() - def generate_mail(self): serializer = URLSafeTimedSerializer("secrettoken",1800) token = serializer.dumps({"email":self.email},salt="flask-email-confirmation") @@ -63,7 +64,7 @@ def find_by_username(cls,username): @classmethod def find_by_email(cls,email): return cls.query.filter_by(email=email).first() - + @classmethod def check_password(cls,username,password): user=cls.query.filter_by(username=username).first() diff --git a/resource/github_login.py b/resource/github_login.py index 3e76ae4..fba45e0 100644 --- a/resource/github_login.py +++ b/resource/github_login.py @@ -3,6 +3,8 @@ from outh import github from model.users import UserModel from flask_jwt_extended import create_access_token,create_refresh_token +import secrets +import string class Github(Resource): @classmethod @@ -10,6 +12,16 @@ def get(cls): return github.authorize(url_for("github.authorize",_external=True)) class GithubAuthorize(Resource): + + + #generate a sample password for github oauth users + @classmethod + def generate_sample_password(cls): + alpha = string.ascii_letters + string.digits + random = ''.join(secrets.choice(alpha) for i in range(20)) + return random + + @classmethod def get(cls): response = github.authorized_response() @@ -28,9 +40,9 @@ def get(cls): #if UserModel.find_by_username(github_username): # return {"msg": "User with username exists"} - + #add user to database - user = UserModel(username=github_username,password=None,activated=True,email=github_email) + user = UserModel(username=github_username,password=GithubAuthorize.generate_sample_password(),activated=True,email=github_email) user.save_to_db() #create jwt tokens diff --git a/resource/order.py b/resource/order.py index ac6809e..331670c 100644 --- a/resource/order.py +++ b/resource/order.py @@ -15,16 +15,17 @@ class Order(Resource): def post(cls): data= request.get_json() items=[] - item_quantity = Counter(data["items"]) + ordered_list = data['items'] # list of dictionaries - for name,count in item_quantity.most_common(): + for ordered_item in data['items']: + name = ordered_item['name'] + count = ordered_item['qty'] res = ItemModel.find_by_name(name) if not res: return {"msg": "Item not present {}".format(name)},404 items.append(ItemsInOrder(item_id=ItemModel.find_id(name),quantity=count)) print(items) - - + order = OrderModel(items=items,status="pending") order.save_to_db() #save orders to database diff --git a/resource/stores.py b/resource/stores.py index 1c4f274..7e7d257 100644 --- a/resource/stores.py +++ b/resource/stores.py @@ -1,8 +1,9 @@ from flask_restful import Resource from model.store import StoreModel +from model.users import UserModel from flask import request from schemas.stores import StoreSchema -from flask_jwt_extended import jwt_required,fresh_jwt_required +from flask_jwt_extended import jwt_required,fresh_jwt_required, get_jwt_identity store_schema = StoreSchema() store_list_schema = StoreSchema(many=True) @@ -19,10 +20,16 @@ def get(self): @jwt_required def post(self): + user = UserModel.find_by_id(get_jwt_identity()) + + if not user.seller: + return {"msg": "User is not a seller"}, 403 + data=request.get_json() name=data["name"] - + store = StoreModel.find_by_name(name) + if store: return {"msg": "Store exists already"},400 @@ -36,6 +43,11 @@ def post(self): @fresh_jwt_required def delete(self): + user = UserModel.find_by_id(get_jwt_identity()) + + if not user.seller: + return {"msg": "User is not a seller"}, 403 + data=request.get_json() name=data["name"] diff --git a/resource/users.py b/resource/users.py index c7f8c66..6d9096a 100644 --- a/resource/users.py +++ b/resource/users.py @@ -22,6 +22,7 @@ def post(self): username = data.username passwd = data.password email = data.email + seller = data.seller print(username,passwd,email) hashed = bcrypt.hashpw(passwd.encode('utf-8'),bcrypt.gensalt()) @@ -32,7 +33,7 @@ def post(self): if UserModel.find_by_email(email): return {"msg": "user with email id exists"} - user = UserModel(username,hashed,email) + user = UserModel(username,hashed,email,seller=seller) user.save_to_db() user.generate_mail() #send emails to new users diff --git a/site.db b/site.db index ce4a8b8..4d6480d 100644 Binary files a/site.db and b/site.db differ