Commit 5a3b1a20 authored by Michal Pavlík's avatar Michal Pavlík

full setup

parent 8d59be9d
## Unix
run bash unix.sh
## Windows
run windows.cmd
\ No newline at end of file
from config import cnx, db
from flask_sqlalchemy import SQLAlchemy
from config import db, cnx
import models
# Create the database tables
with cnx.app.app_context():
db.create_all()
db.create_all()
if __name__ == '__main__':
cnx.add_api('swagger.yml')
cnx.run(debug=True, port=8080)
cnx.add_api('swagger.yml')
cnx.run(debug=True, port=8080)
from errors import WrongCredentials
from models import User
from config import PUBLIC_KEY, db
import bcrypt
import jwt
def basic_auth(username, password, required_scopes):
user = User.query.filter_by(username=username).first()
pswd = bytes(password, encoding='utf-8')
is_pass_correct = bcrypt.checkpw(pswd, user.password)
if not user or not is_pass_correct:
raise WrongCredentials
return {
'sub': user.id,
'username': user.username,
'scope': 'read write'
}
def oauth2(token):
vals = jwt.decode(token, PUBLIC_KEY, algorithms='RS256')
user = User.query.filter_by(uuid=vals['sub']).first()
if not user:
user = User(username=vals['name'], uuid=vals['sub'], password='external')
db.session.add(user)
db.session.commit()
return {
'sub': user.id,
'username': user.username,
'scope': vals['scope']
}
from models import Post
from flask import request, jsonify
from flask import request, escape
from config import db
def post():
data = request.json
def parse_page(data):
return {
'content': [e.json() for e in data.items],
'page': data.page,
'size': data.per_page,
'totalPages': data.pages
}
new_post = Post(message=data['message'], author='Anonymous')
db.session.add(new_post)
db.session.commit()
return new_post.json(), 201
def post(user, token_info):
data = request.json
new_post = Post(message=escape(data['message']), author_id=user)
db.session.add(new_post)
db.session.commit()
def parse_page(data):
return {
'content': [p.json() for p in data.items],
'page': data.page,
'size': data.per_page,
'totalPages': data.pages
}
return new_post.json(), 201
def all(page=1, size=10):
data = Post.query.order_by(Post.created.desc()).paginate(page, size, False)
return parse_page(data)
def all(page=1, size=10):
data = Post.query.order_by(Post.created.desc()).paginate(page, size, False)
return parse_page(data)
import connexion
from flask_sqlalchemy import SQLAlchemy
from errors import OurException
from errors import ProjectException
cnx = connexion.App(__name__, specification_dir='./')
db = SQLAlchemy()
db.init_app(cnx.app)
cnx.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///./data.db'
cnx.app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
cnx.app.config['SQLALCHEMY_ECHO'] = True
cnx.app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///./data.db'
cnx.app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
cnx.app.config["SQLALCHEMY_ECHO"] = True
cnx.app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024
ALLOWED_IMAGE_FILES = ['png', 'jpg', 'jpeg']
@cnx.app.errorhandler(OurException)
PUBLIC_KEY = b"""-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAza5xftTPKTpef9sXgaJD41veGVeSshAEdaK/iRHHVVOsgVxEGxQl6UfCe1CTUV8Xq4NLISk5chNdMHDJBOlyXIc0xuA3F48kEMRKEuVAug9AruEF4xTX87Ya3B5sL38nLF+SkExKLz+05C/JERAsHE00eP3+/UkRIx2Zv+hWC3+bMv9uK6QmGoCBy9829TzDsdRaPFzj9DTTT44K9Ko/KugffnB5kgI49SUSqo/hyohCEZN0Abbho9f38tXNV4d+9dantkbUCNNmj3zGiYbzxBjEokxIMUn2N/57ys9ZhNllLEy5eSAoOF6hp1I0vN8c9uGbAmA0h1TJutsP6f5tEQIDAQAB
-----END PUBLIC KEY-----"""
@cnx.app.errorhandler(ProjectException)
def exception_handler(e):
return {
'msg': e.get_message(),
......
class OurException(Exception):
class ProjectException(Exception):
def get_message(self):
return 'no message'
return 'Unspecified message'
def get_code(self):
return -1
return 0
def get_http_code(self):
return 500
class PostNotFound(OurException):
class PostNotFound(ProjectException):
def __init__(self, post_id):
self.post_id = post_id
def get_message(self):
return f'Post with id {self.post_id} not found.'
return f'Post with id {self.post_id} doesn\'t exist'
def get_code(self):
return 100
def get_http_code(self):
return 404
class UserNotFound(ProjectException):
def __init__(self, user_id):
self.user_id = user_id
def get_message(self):
return f"User with id {self.user_id} doesn't exist."
def get_code(self):
return 200
def get_http_code(self):
return 404
class RegistrationFailed(ProjectException):
def __init__(self, reason):
self.reason = reason
def get_message(self):
return f"Failed to register new user, reason: {self.reason}"
def get_code(self):
return 201
def get_http_code(self):
return 422
class UnsupportedFileType(ProjectException):
def __init__(self, filetype):
self.filetype = filetype
def get_message(self):
return f"Files with the extension {self.filetype} aren't allowed."
def get_code(self):
return 300
def get_http_code(self):
return 412
class WrongCredentials(ProjectException):
def get_message(self):
return "The username or password you provided are incorrect."
def get_code(self):
return 202
def get_http_code(self):
return 401
from config import db
from datetime import datetime
from config import db
from uuid import uuid4
class Post(db.Model):
__tablename__ = 'posts'
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
message = db.Column(db.Text, nullable=False)
author = db.Column(db.String, nullable=False)
author_id = db.Column(db.String(36), db.ForeignKey('users.id'))
created = db.Column(db.DateTime, default=datetime.utcnow)
def json(self):
return {
'id': self.id,
'message': self.message,
'author': self.author,
'author': self.author.username,
'created': self.created
}
def uuid_generator():
return str(uuid4())
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
uuid = db.Column(db.String(36), unique=True, default=uuid_generator)
username = db.Column(db.Text, nullable=False, unique=True)
avatarUrl = db.Column(db.String(1024), nullable=False, default='/static/default_user.png')
password = db.Column(db.String(60), nullable=False)
created = db.Column(db.DateTime, default=datetime.utcnow)
posts = db.relationship("Post", backref='author')
def json(self):
return {
'id': self.id,
'username': self.username,
'avatarUrl': self.avatarUrl,
'created': self.created,
'posts': [p.json() for p in self.posts]
}
from models import Post
from config import db
from models import Post
from errors import PostNotFound
def get(id):
data = Post.query.get(id)
if data:
return data.json()
else:
raise PostNotFound(id)
post = Post.query.get(id)
def delete(id):
data = Post.query.get(id)
if post:
return post.json()
else:
raise PostNotFound(id)
if not data:
raise PostNotFound(id)
db.session.delete(data)
db.session.commit()
def delete(id, user):
post = Post.query.get(id)
if not Post or post.author_id is not user:
raise PostNotFound(id)
db.session.delete(post)
db.session.commit()
......@@ -8,13 +8,12 @@ info:
servers:
- url: 'http://localhost:8080/'
- url: 'https://localhost:8080/'
#security:
# - BasicAuth: []
# - OAuth2:
# - read
# - write
security:
- BasicAuth: []
- OAuth2:
- read
- write
paths:
......@@ -22,20 +21,18 @@ paths:
put:
description: 'Upload an user image as avatar.'
operationId: users.upload_avatar
tags:
tags:
- Users
requestBody:
content:
image/png:
schema:
type: string
format: binary
image/jpg:
multipart/form-data:
schema:
type: string
format: binary
type: object
properties:
avatar:
type: string
format: binary
responses:
200:
description: 'Image uploaded successfully'
......@@ -49,13 +46,15 @@ paths:
tags:
- Users
security: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterUser'
responses:
201:
description: 'Register a new user.'
......@@ -70,12 +69,12 @@ paths:
get:
description: 'Get a single user from the database by his ID.'
operationId: users.get
tags:
tags:
- Users
parameters:
parameters:
- $ref: '#/components/parameters/id'
responses:
200:
description: 'Correctly found a user by ID'
......@@ -85,54 +84,54 @@ paths:
$ref: '#/components/schemas/User'
404:
description: "User with this ID doesn't exist"
/post/{id}:
get:
description: 'Get post detail'
operationId: posts.get
tags:
- Posts
parameters:
parameters:
- $ref: '#/components/parameters/id'
responses:
200:
$ref: '#/components/responses/PostDetail'
404:
description: 'Post not found'
delete:
description: 'Remove Posts'
operationId: posts.delete
tags:
- Posts
parameters:
- $ref: '#/components/parameters/id'
responses:
204:
description: 'Success'
404:
description: 'Post not found'
/board:
get:
description: 'Get all posts paged'
operationId: boards.all
tags:
- Boards
security: []
parameters:
parameters:
- $ref: '#/components/parameters/PageNumber'
- $ref: '#/components/parameters/PageSize'
responses:
200:
description: 'Paged responses here...'
......@@ -140,13 +139,13 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/PostPage'
post:
description: 'Post a new Post'
operationId: boards.post
tags:
- Boards
requestBody:
required: true
content:
......@@ -156,9 +155,9 @@ paths:
properties:
message:
type: string
responses:
201:
$ref: '#/components/responses/PostDetail'
......@@ -166,24 +165,26 @@ paths:
description: 'Bad Request'
422:
description: 'Unprocessable Entity'
components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
x-basicInfoFunc: auth.basic_auth
OAuth2:
x-tokenInfoFunc: auth.oauth2
type: oauth2
flows:
password:
tokenUrl: 'http://localhost:8091/auth/token'
tokenUrl: 'http://192.168.0.2:9998/auth/realms/lh-temp/protocol/openid-connect/token'
scopes:
read: Grants read
write: Grants write
schemas:
Post:
......@@ -196,7 +197,7 @@ components:
created:
type: string
format: date-time
RegisterUser:
type: object
properties:
......@@ -204,7 +205,7 @@ components:
type: string
password:
type: string
User:
type: object
properties:
......@@ -215,7 +216,7 @@ components:
format: date-time
avatarUrl:
type: string
PostPage:
type: object
properties:
......@@ -229,7 +230,7 @@ components:
type: integer
totalPages:
type: integer
parameters:
id:
name: id
......@@ -237,14 +238,14 @@ components:
required: true
schema:
type: integer
PageNumber:
name: page
in: query
required: false
schema:
type: integer
PageSize:
name: size
in: query
......@@ -260,3 +261,6 @@ components:
application/json:
schema:
$ref: '#/components/schemas/Post'
from flask import request, escape
from errors import UserNotFound, RegistrationFailed, UnsupportedFileType
from werkzeug.utils import secure_filename
from models import User
from config import db, ALLOWED_IMAGE_FILES
import bcrypt
import os
import uuid
def get(id):
pass
user = User.query.get(id)
if not user:
raise UserNotFound(id)
return user.json()
def upload_avatar(user=1):
logged_user = User.query.get(user)
avatar = request.files.get('avatar')
ext = avatar.filename.split(".")[-1]
if ext in ALLOWED_IMAGE_FILES:
if "default" not in logged_user.avatarUrl:
os.remove(logged_user.avatarUrl)
url = f'./static/avatar_{uuid.uuid4()}.{ext}'
avatar.save(url)
logged_user.avatarUrl = url
db.session.commit()
else:
raise UnsupportedFileType(ext)
return logged_user.json()
def upload_avatar():
pass
def register():
pass
data = request.json
try:
user = User.query.filter_by(username=data['username']).first()
if user:
raise RegistrationFailed("User with this name already exists.")
salt = bcrypt.gensalt()
pwd = bytes(data['password'], encoding='utf-8')
user = User(
username=escape(data['username']),
password=bcrypt.hashpw(pwd, salt)
)
db.session.add(user)
db.session.commit()
return user.json()
except Exception as e:
raise RegistrationFailed(e)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment