Skip to content
Merged
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
113 changes: 107 additions & 6 deletions Project1_Simple_REST_API/Python_flask/flask_simple_restapi/app/app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from app_init.app_factory import create_app
from flask import jsonify,current_app,request
from app.models import Users
from app.serializer import UserSchema,UpdateSchema
from app.models import Users,Todo
from app.serializer import UserSchema,UpdateSchema,TodoUpdateSchema,TodoSchema
from flask_jwt_extended import jwt_required,create_access_token,get_jwt_identity,get_jwt_claims,create_refresh_token,jwt_refresh_token_required
from marshmallow import ValidationError
from app.utils import verify_secret
import os
import warnings
from marshmallow import ValidationError

warnings.simplefilter("ignore")

Expand All @@ -26,6 +28,7 @@ def create_user():
return UserSchema().jsonify(user)



@app.route("/api/v1/users/<int:id>",methods=["GET"])
def get_user(id):
user = Users.query.filter_by(id=id).first()
Expand All @@ -44,7 +47,8 @@ def update_user(id):
schema = UpdateSchema()
user_info = schema.load(user_info)
user = user.update(**user_info)
return UserSchema().jsonify(user)

return UserSchema(load_only=['password']).jsonify(user)
except ValidationError as err:
return jsonify(err.messages)

Expand All @@ -54,12 +58,109 @@ def update_user(id):
@app.route("/api/v1/users",methods=["GET"])
def get_users():
users = Users.query.all()
return UserSchema().jsonify(users,many=True)
return UserSchema(load_only=['password']).jsonify(users,many=True)


@app.route("/api/v1/users/<int:id>",methods=["DELETE"])
def delete_user(id):
user = Users.query.get(id)
if user.delete():
return jsonify({"result": True})
return jsonify({'message': "User not found"}),404
return jsonify({'message': "User not found"}),404



@app.route("/api/v1/users/login",methods=["POST"])
def login_user():
user_data = request.get_json()
user = Users.query.filter_by(email=user_data.get("email")).first()

if not user:
return jsonify({'message': "User not found"}),404

if verify_secret(user_data.get("password"),user.password):
schema = UserSchema()
user = schema.dump(user)
access_token = create_access_token(identity=user.get("id"))
refresh_token = create_refresh_token(identity=user.get("id"))
user.update(access_token=access_token,refresh_token=refresh_token)
return jsonify(user)
return jsonify({'message': "User not found"}),404



@app.route("/api/v1/users/todos",methods=["POST"])
@jwt_required
def create_todo():
user_id = get_jwt_identity()
user = Users.query.get(user_id)
if not user:
return jsonify({'message': "User not found"}),404
todo_data = request.get_json()
schema = TodoSchema()
todo = schema.load(todo_data)
todo.user_id = user.id
todo.save_db()


return TodoSchema().jsonify(todo)




@app.route("/api/v1/users/todos",methods=["GET"])
@jwt_required
def get_todos():
user_id = get_jwt_identity()
todos = Todo.query.filter_by(user_id= user_id).all()
return TodoSchema().jsonify(todos,many=True)


@app.route("/api/v1/users/todos/<todo_id>",methods=["GET"])
@jwt_required
def get_todo(todo_id):
user_id = get_jwt_identity()
todos = Todo.query.filter_by(user_id = user_id,id = todo_id).first()
return TodoSchema().jsonify(todos)



@app.route("/api/v1/users/todos/<todo_id>",methods=["PUT"])
@jwt_required
def update_todo(todo_id):
user_id = get_jwt_identity()
todos = Todo.query.filter_by(user_id = user_id,id = todo_id).first()
if not todos:
return jsonify({'message': "Todo not found"}),404

todo = TodoUpdateSchema().load(request.get_json())
todos.update(**todo)
return TodoSchema().jsonify(todos)


@app.route("/api/v1/users/todos/<todo_id>",methods=["DELETE"])
def delete_todo(todo_id):
user_id = get_jwt_identity()
todos = Todo.query.filter_by(user_id = user_id,id = todo_id).first()
user_claims = get_jwt_claims()

if not todos:
return jsonify({'message': "Todo not found"}),404

result = todos.delete()
return jsonify({'message': result})




@app.route("/api/v1/users/token/refresh",methods=["POST"])
@jwt_refresh_token_required
def refresh_user_token():
identity = get_jwt_identity()

user = Users.query.get(identity)
if not user:
return jsonify({"result": "Oops..."}),401

access_token = create_access_token(identity=identity)
return jsonify(access_token=access_token)
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
from extensions.extension import Model,String,Integer,Column,DateTime
from extensions.extension import Model,String,Integer,Column,DateTime,ForeignKey,relationship
from extensions.extension import db
from sqlalchemy.sql import func



class Users(Model):
__tablename__ = "users"

id = Column(Integer(),autoincrement=True,primary_key=True)
first_name = Column(String(),nullable=False)
last_name = Column(String(),nullable=False)
user_name = Column(String(),nullable=False)
email = Column(String(),nullable=False)
email = Column(String(),nullable=False,unique=True)
password = Column(String(),nullable=False)
todos = relationship("Todo")
created = Column(DateTime(timezone=True), default=func.now())
updated = Column(DateTime(timezone=True), onupdate=func.now(),nullable=True)

def save_db(self):
db.session.add(self)
db.session.commit()
return self

def update(self,**kwargs):
for key,val in kwargs.items():
setattr(self,key,val)

return self.save_db()

def delete(self):
db.session.delete(self)
db.session.commit()

return True

class Todo(Model):
__tablename__ = "todos"

id = Column(Integer(),autoincrement=True,primary_key=True)
title = Column(String(),nullable=False)
description = Column(String())
created = Column(DateTime(timezone=True), default=func.now())
updated = Column(DateTime(timezone=True), onupdate=func.now(),nullable=True)
user_id = Column(Integer(),ForeignKey("users.id",use_alter=True,ondelete="SET NULL"))

def save_db(self):
db.session.add(self)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from extensions.extension import ma,fields,validate,validates_schema
from app.models import Users
from app.models import Users,Todo
from app.utils import get_secret_hash

class UserSchema(ma.ModelSchema):
Expand All @@ -8,7 +8,7 @@ class UserSchema(ma.ModelSchema):
last_name = fields.Str(required=True,validate=[validate.Length(min=2,max=250)])
user_name = fields.Str(required=True,validate=[validate.Length(min=2,max=250)])
email = fields.Email(required=True)
password = fields.Str(required=True,validate=[validate.Regexp(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?#&]{8,}$")])
password = fields.Str(load_only=True,required=True,validate=[validate.Regexp(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?#&]{8,}$")])

@validates_schema(skip_on_field_errors=True)
def hash_pass(self,data,**kwargs):
Expand All @@ -17,6 +17,8 @@ def hash_pass(self,data,**kwargs):

class Meta:
model = Users

todos = fields.Nested('TodoSchema', many=True)

class UpdateSchema(ma.Schema):

Expand All @@ -34,4 +36,19 @@ def hash_pass(self,data,**kwargs):




class TodoSchema(ma.ModelSchema):

title = fields.Str(required=True,validate=[validate.Length(min=2,max=250)])
description = fields.Str(validate=[validate.Length(min=2,max=250)])

class Meta:
model = Todo
include_fk = True



class TodoUpdateSchema(ma.Schema):

title = fields.Str(validate=[validate.Length(min=2,max=250)])
description = fields.Str(validate=[validate.Length(min=2,max=250)])
user_id = fields.Int()
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from flask import Flask
import os, logging,sys
from extensions.extension import db,ma,migrate
from extensions.extension import db,ma,migrate,jwt
from logging.config import dictConfig


Expand Down Expand Up @@ -41,5 +41,6 @@ def create_app(settings_name):
db.init_app(app)
ma.init_app(app)
migrate.init_app(app,db)
jwt.init_app(app)

return app
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from marshmallow import validate,fields,validates_schema
from flask_migrate import Migrate
from passlib.context import CryptContext
from flask_jwt_extended import JWTManager

pwd_context = CryptContext(schemes="sha256_crypt")
db = SQLAlchemy()
ma = Marshmallow()
migrate = Migrate()
jwt = JWTManager()

Model,Column,String,Integer,DateTime = db.Model,db.Column,db.String,db.Integer,db.DateTime
Model,Column,String,Integer,DateTime,ForeignKey,relationship = db.Model,db.Column,db.String,db.Integer,db.DateTime,db.ForeignKey,db.relationship
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# A generic, single database configuration.

[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
Loading