commit
4287766d7f
18 changed files with 250 additions and 60 deletions
|
@ -3,7 +3,6 @@ from .users.user_endpoint import UserEndpoint
|
||||||
|
|
||||||
api = Blueprint('api', __name__, url_prefix='/api')
|
api = Blueprint('api', __name__, url_prefix='/api')
|
||||||
|
|
||||||
|
|
||||||
@api.route('/home', methods=['GET'])
|
@api.route('/home', methods=['GET'])
|
||||||
def api_home():
|
def api_home():
|
||||||
response = {"message": "home page"}
|
response = {"message": "home page"}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
from models.User import User, user_schema
|
||||||
|
|
||||||
class UserEndpoint(object):
|
class UserEndpoint(object):
|
||||||
def users():
|
def users():
|
||||||
response = {"message": "users page"}
|
user = User.query.first()
|
||||||
|
response = user_schema.dumps(user)
|
||||||
return response
|
return response
|
||||||
|
|
53
app.py
53
app.py
|
@ -1,57 +1,20 @@
|
||||||
import os
|
import os
|
||||||
|
from database import db, ma
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
# ! SQLAlchemy > Marshmallow - these must be imported in this order
|
from configuration.config import DevelopmentConfig
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
from flask_marshmallow import Marshmallow
|
|
||||||
|
|
||||||
from flask_migrate import Migrate
|
|
||||||
|
|
||||||
from flask_bcrypt import Bcrypt
|
from flask_bcrypt import Bcrypt
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
|
||||||
# config database
|
app.config.from_object(DevelopmentConfig)
|
||||||
app_settings = os.getenv(
|
db.init_app(app)
|
||||||
'APP_SETTINGS',
|
ma.init_app(app)
|
||||||
'config.DevelopmentConfig'
|
return app
|
||||||
)
|
|
||||||
|
|
||||||
app.config.from_object(app_settings)
|
bcrypt = Bcrypt(create_app())
|
||||||
|
|
||||||
# init bcrypt
|
|
||||||
bcrypt = Bcrypt(app)
|
|
||||||
|
|
||||||
# init database
|
|
||||||
db = SQLAlchemy(app)
|
|
||||||
|
|
||||||
# init marshmallow
|
|
||||||
ma = Marshmallow(app)
|
|
||||||
|
|
||||||
# init all db models
|
|
||||||
import models
|
|
||||||
|
|
||||||
migrate = Migrate(app, db)
|
|
||||||
|
|
||||||
|
|
||||||
# dev server
|
|
||||||
DEBUG = True
|
|
||||||
PORT = 8000
|
|
||||||
|
|
||||||
# Routes
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def hello_world():
|
|
||||||
return 'Hello World'
|
|
||||||
|
|
||||||
# Blue prints
|
|
||||||
from api.api import api
|
|
||||||
|
|
||||||
app.register_blueprint(api)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(debug=DEBUG, port=PORT)
|
|
0
auth/__init__.py
Normal file
0
auth/__init__.py
Normal file
49
auth/auth.py
Normal file
49
auth/auth.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
from flask import Blueprint, request, jsonify, session
|
||||||
|
|
||||||
|
from database import db
|
||||||
|
from models.User import User
|
||||||
|
|
||||||
|
auth = Blueprint('auth', __name__, url_prefix='/auth')
|
||||||
|
|
||||||
|
@auth.route('/signup', methods=['POST'])
|
||||||
|
def auth_signup():
|
||||||
|
data = request.get_json()
|
||||||
|
user = User.query.filter_by(email=data.get('email')).first()
|
||||||
|
if not user:
|
||||||
|
try:
|
||||||
|
print('getting here 1')
|
||||||
|
user = User(
|
||||||
|
email = data['email'],
|
||||||
|
password = data['password'],
|
||||||
|
)
|
||||||
|
print('getting here 2')
|
||||||
|
db.session.add(user)
|
||||||
|
print('wtf')
|
||||||
|
db.session.commit()
|
||||||
|
print('user')
|
||||||
|
auth_token = user.encode_auth_token(user.id)
|
||||||
|
print('getting here 4')
|
||||||
|
response = {
|
||||||
|
'status': 'success',
|
||||||
|
'message': 'Succesfully registered.',
|
||||||
|
'auth_token': auth_token.decode()
|
||||||
|
}
|
||||||
|
return jsonify(response), 201
|
||||||
|
except Exception as e:
|
||||||
|
print(e.__dict__)
|
||||||
|
response = {
|
||||||
|
'status': 'fail',
|
||||||
|
'message': 'There was an error. Please try again.'
|
||||||
|
}
|
||||||
|
return jsonify(response), 401
|
||||||
|
else:
|
||||||
|
response = {
|
||||||
|
'status': 'fail',
|
||||||
|
'message': 'User already exists. Please login.'
|
||||||
|
}
|
||||||
|
return jsonify(response), 202
|
||||||
|
|
||||||
|
@auth.route('/login', methods=['POST'])
|
||||||
|
def auth_login():
|
||||||
|
response = {"message": "login post"}
|
||||||
|
return jsonify(response)
|
0
configuration/__init__.py
Normal file
0
configuration/__init__.py
Normal file
|
@ -14,6 +14,7 @@ class DevelopmentConfig(BaseConfig):
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
BCRYPT_LOG_ROUNDS = 4
|
BCRYPT_LOG_ROUNDS = 4
|
||||||
SQLALCHEMY_DATABASE_URI = DATABASE
|
SQLALCHEMY_DATABASE_URI = DATABASE
|
||||||
|
PORT = 8000
|
||||||
|
|
||||||
|
|
||||||
class TestingConfig(BaseConfig):
|
class TestingConfig(BaseConfig):
|
7
configuration/models_mount.py
Normal file
7
configuration/models_mount.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from ..models.User import User
|
||||||
|
from ..models.GameRoom import GameRoom
|
||||||
|
from ..models.TimeSettings import TimeSettings
|
||||||
|
from ..models.Game import Game
|
||||||
|
from ..models.Move import Move
|
||||||
|
from ..models.Message import Message
|
10
database.py
Normal file
10
database.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
# ! SQLAlchemy > Marshmallow - these must be imported in this order
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_marshmallow import Marshmallow
|
||||||
|
|
||||||
|
# init database
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
# init marshmallow
|
||||||
|
ma = Marshmallow()
|
11
manage.py
11
manage.py
|
@ -4,11 +4,20 @@ import unittest
|
||||||
from flask_script import Manager
|
from flask_script import Manager
|
||||||
from flask_migrate import Migrate, MigrateCommand
|
from flask_migrate import Migrate, MigrateCommand
|
||||||
|
|
||||||
from app import app, db
|
from database import db
|
||||||
|
from app import create_app
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
migrate = Migrate(app, db)
|
migrate = Migrate(app, db)
|
||||||
manager = Manager(app)
|
manager = Manager(app)
|
||||||
|
|
||||||
|
from models.Game import Game
|
||||||
|
from models.GameRoom import GameRoom
|
||||||
|
from models.Message import Message
|
||||||
|
from models.Move import Move
|
||||||
|
from models.TimeSettings import TimeSettings
|
||||||
|
from models.User import User
|
||||||
|
|
||||||
# migrations
|
# migrations
|
||||||
manager.add_command('db', MigrateCommand)
|
manager.add_command('db', MigrateCommand)
|
||||||
|
|
||||||
|
|
28
migrations/versions/50aab465cf44_.py
Normal file
28
migrations/versions/50aab465cf44_.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 50aab465cf44
|
||||||
|
Revises: bfa4b406e22f
|
||||||
|
Create Date: 2019-10-05 22:37:07.643522
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '50aab465cf44'
|
||||||
|
down_revision = 'bfa4b406e22f'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('users', sa.Column('password', sa.String(length=255), nullable=False))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('users', 'password')
|
||||||
|
# ### end Alembic commands ###
|
|
@ -39,7 +39,7 @@ def upgrade():
|
||||||
op.create_table('users',
|
op.create_table('users',
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
sa.Column('email', sa.String(length=255), nullable=False),
|
sa.Column('email', sa.String(length=255), nullable=False),
|
||||||
sa.Column('password', sa.DateTime(), nullable=False),
|
sa.Column('password', sa.Integer(length=255), nullable=False),
|
||||||
sa.Column('registered_on', sa.DateTime(), nullable=False),
|
sa.Column('registered_on', sa.DateTime(), nullable=False),
|
||||||
sa.Column('admin', sa.Boolean(), nullable=False),
|
sa.Column('admin', sa.Boolean(), nullable=False),
|
||||||
sa.Column('rank', sa.Enum('D7', 'D6', 'D5', 'D4', 'D3', 'D2', 'D1', 'K1', 'K2', 'K3', 'K4', 'K5', 'K6', 'K7', 'K8', 'K9', 'K10', 'K11', 'K12', 'K13', 'K14', 'K15', 'K16', 'K17', 'K18', 'K19', 'K20', 'K21', 'K22', 'K23', 'K24', 'K25', 'K26', 'K27', 'K28', 'K29', 'K30', name='ranks'), nullable=True),
|
sa.Column('rank', sa.Enum('D7', 'D6', 'D5', 'D4', 'D3', 'D2', 'D1', 'K1', 'K2', 'K3', 'K4', 'K5', 'K6', 'K7', 'K8', 'K9', 'K10', 'K11', 'K12', 'K13', 'K14', 'K15', 'K16', 'K17', 'K18', 'K19', 'K20', 'K21', 'K22', 'K23', 'K24', 'K25', 'K26', 'K27', 'K28', 'K29', 'K30', name='ranks'), nullable=True),
|
||||||
|
|
28
migrations/versions/bdc3cd5d7499_.py
Normal file
28
migrations/versions/bdc3cd5d7499_.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: bdc3cd5d7499
|
||||||
|
Revises: 16c70b11242e
|
||||||
|
Create Date: 2019-10-05 22:34:04.358841
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'bdc3cd5d7499'
|
||||||
|
down_revision = '16c70b11242e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('moves', sa.Column('is_pass', sa.Boolean(), nullable=False))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('moves', 'is_pass')
|
||||||
|
# ### end Alembic commands ###
|
28
migrations/versions/bfa4b406e22f_.py
Normal file
28
migrations/versions/bfa4b406e22f_.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: bfa4b406e22f
|
||||||
|
Revises: bdc3cd5d7499
|
||||||
|
Create Date: 2019-10-05 22:36:45.420054
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'bfa4b406e22f'
|
||||||
|
down_revision = 'bdc3cd5d7499'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('users', 'password')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('users', sa.Column('password', postgresql.TIMESTAMP(), autoincrement=False, nullable=False))
|
||||||
|
# ### end Alembic commands ###
|
|
@ -1,6 +0,0 @@
|
||||||
from models.User import User
|
|
||||||
from models.GameRoom import GameRoom
|
|
||||||
from models.TimeSettings import TimeSettings
|
|
||||||
from models.Game import Game
|
|
||||||
from models.Move import Move
|
|
||||||
from models.Message import Message
|
|
|
@ -1,6 +1,9 @@
|
||||||
from app import db, ma, bcrypt
|
from database import db, ma
|
||||||
|
from app import bcrypt
|
||||||
|
from configuration import config
|
||||||
import datetime
|
import datetime
|
||||||
import enum
|
import enum
|
||||||
|
import jwt
|
||||||
|
|
||||||
class Ranks(enum.Enum): # with minimal Elo rating
|
class Ranks(enum.Enum): # with minimal Elo rating
|
||||||
D7 = "Seven Dan" # Elo 2700+
|
D7 = "Seven Dan" # Elo 2700+
|
||||||
|
@ -47,7 +50,7 @@ class User(db.Model):
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
email = db.Column(db.String(255), unique=True, nullable=False)
|
email = db.Column(db.String(255), unique=True, nullable=False)
|
||||||
password = db.Column(db.DateTime, nullable=False)
|
password = db.Column(db.String(255), nullable=False)
|
||||||
registered_on = db.Column(db.DateTime, nullable=False)
|
registered_on = db.Column(db.DateTime, nullable=False)
|
||||||
admin = db.Column(db.Boolean, nullable=False, default=False)
|
admin = db.Column(db.Boolean, nullable=False, default=False)
|
||||||
rank = db.Column(db.Enum(Ranks))
|
rank = db.Column(db.Enum(Ranks))
|
||||||
|
@ -55,9 +58,60 @@ class User(db.Model):
|
||||||
rank_certainty = db.Column(db.Boolean, nullable=False, default=False)
|
rank_certainty = db.Column(db.Boolean, nullable=False, default=False)
|
||||||
|
|
||||||
def __init__(self, email, password, admin=False,):
|
def __init__(self, email, password, admin=False,):
|
||||||
|
print('user init')
|
||||||
self.email = email
|
self.email = email
|
||||||
|
print('user email init')
|
||||||
self.password = bcrypt.generate_password_hash(
|
self.password = bcrypt.generate_password_hash(
|
||||||
password, app.config.get('BCRYPT_LOG_ROUNDS')
|
password, 13
|
||||||
).decode()
|
).decode()
|
||||||
|
print('user password init')
|
||||||
self.registered_on = datetime.datetime.now()
|
self.registered_on = datetime.datetime.now()
|
||||||
self.admin = admin
|
self.admin = admin
|
||||||
|
|
||||||
|
def encode_auth_token(self, user_id):
|
||||||
|
"""
|
||||||
|
Generates the Auth Token
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
payload = {
|
||||||
|
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=5),
|
||||||
|
'iat': datetime.datetime.utcnow(),
|
||||||
|
'sub': user_id
|
||||||
|
}
|
||||||
|
return jwt.encode(
|
||||||
|
payload,
|
||||||
|
app.config.get('SECRET_KEY'),
|
||||||
|
algorithm='HS256'
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return e
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def decode_auth_token(auth_token):
|
||||||
|
"""
|
||||||
|
Decodes the auth token
|
||||||
|
:param auth_token:
|
||||||
|
:return: integer|string
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
payload = jwt.decode(auth_token, app.config.get('SECRET_KEY'))
|
||||||
|
return payload['sub']
|
||||||
|
except jwt.ExpiredSignatureError:
|
||||||
|
return 'Signature expired. Please log in again.'
|
||||||
|
except jwt.InvalidTokenError:
|
||||||
|
return 'Invalid token. Please log in again.'
|
||||||
|
|
||||||
|
class UserSchema(ma.ModelSchema):
|
||||||
|
class Meta:
|
||||||
|
fields = (
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'registered_on',
|
||||||
|
'rank',
|
||||||
|
'rank_certainty',
|
||||||
|
'elo'
|
||||||
|
)
|
||||||
|
|
||||||
|
user_schema = UserSchema()
|
||||||
|
users_schema = UserSchema(many=True)
|
|
@ -23,6 +23,7 @@ mccabe==0.6.1
|
||||||
numpy==1.17.2
|
numpy==1.17.2
|
||||||
psycopg2==2.8.3
|
psycopg2==2.8.3
|
||||||
pycparser==2.19
|
pycparser==2.19
|
||||||
|
PyJWT==1.7.1
|
||||||
pylint==2.4.2
|
pylint==2.4.2
|
||||||
python-dateutil==2.8.0
|
python-dateutil==2.8.0
|
||||||
python-editor==1.0.4
|
python-editor==1.0.4
|
||||||
|
|
17
server.py
Normal file
17
server.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from app import create_app, db
|
||||||
|
|
||||||
|
# Blueprints
|
||||||
|
from api.api import api
|
||||||
|
from auth.auth import auth
|
||||||
|
|
||||||
|
import configuration.models_mount
|
||||||
|
from flask_migrate import Migrate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = create_app()
|
||||||
|
app.register_blueprint(api)
|
||||||
|
app.register_blueprint(auth)
|
||||||
|
migrate = Migrate(app, db)
|
||||||
|
app.run(port=8000, debug=True)
|
Loading…
Reference in a new issue