8 Commits

7 changed files with 189 additions and 23 deletions
+1
View File
@@ -1 +1,2 @@
__pycache__/
*.env
+4
View File
@@ -13,3 +13,7 @@ docker-compose up
```
That should be enough to get the server up and running.
## Lab3 specifics
Variant for functionality extension: 27 % 3 = 0 => Income accountance
+96 -23
View File
@@ -1,10 +1,61 @@
from flask import Flask, request
from flask import Flask, request, jsonify
import time
import json
from app.local_db import LocalDB
import uuid
from marshmallow import Schema, fields
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
ldb = LocalDB()
app.config.from_pyfile('config.py', silent=True)
db = SQLAlchemy(app)
class UserModel(db.Model):
__tablename__ = "user"
uuid = db.Column(db.String(32), unique=True, primary_key=True, nullable=False)
name = db.Column(db.String(64), nullable=False)
class CategoryModel(db.Model):
__tablename__ = "category"
uuid = db.Column(db.String(32), unique=True, primary_key=True, nullable=False)
name = db.Column(db.String(64), nullable=False)
class RecordModel(db.Model):
__tablename__ = "record"
uuid = db.Column(db.String(32), primary_key=True, nullable=False)
user_uuid = db.Column(db.String(32), db.ForeignKey('user.uuid'))
cat_uuid = db.Column(db.String(32), db.ForeignKey('category.uuid'))
date = db.Column(db.Date)
amount = db.Column(db.Integer)
class UserSchema(Schema):
uuid = fields.Str()
name = fields.Str()
class CategorySchema(Schema):
uuid = fields.Str()
name = fields.Str()
class RecordSchema(Schema):
uuid = fields.Str()
user_uuid = fields.Str()
cat_uuid = fields.Str()
date = fields.Date()
amount = fields.Integer()
user_schema = UserSchema()
users_schema = UserSchema(many = True)
category_schema = CategorySchema()
categories_schema = CategorySchema(many = True)
record_schema = RecordSchema()
records_schema = RecordSchema(many = True)
# "migration"
with app.app_context():
db.create_all()
@app.route("/healthcheck")
def ep_healthcheck():
@@ -15,44 +66,66 @@ def ep_healthcheck():
@app.route("/reset_users_because_postman_is_dumb_like_that")
def ep_reset():
ldb.reset()
return {}
db.session.query(UserModel).delete()
db.session.commit()
return {}, 200
@app.route("/users", methods = ["GET"])
def ep_users_get():
return ldb.get_users()
result = db.session.query(UserModel).all()
return users_schema.dumps(result)
@app.route("/user/<user_id>", methods = ["GET"])
def ep_user_get(user_id):
user = ldb.get_user(user_id)
result = db.session.query(UserModel).filter(UserModel.uuid == user_id).all()
if 'uuid' in user:
return user
if len(result) == 1:
return user_schema.dumps(result[0]), 200
else:
return user, 404
return {}, 404
@app.route("/user", methods = ["POST"])
def ep_user_post():
body = request.json
if 'name' in body:
r = ldb.add_user(body['name'])
if 'uuid' in r:
return r
else:
return r, 403
else:
if not body:
return {}, 403
if 'uuid' in body:
return {}, 403
body.update({'uuid': uuid.uuid4().hex})
try:
_ = user_schema.load(body)
except ValidationError as e:
return {}, 403
u = UserModel(**body)
try:
db.session.add(u)
db.session.commit()
except Exception as e:
db.session.rollback()
return {}, 403
return jsonify(user_schema.load(body)), 200
@app.route("/user/<user_id>", methods = ["DELETE"])
def ep_user_delete(user_id):
r = ldb.del_user(user_id)
try:
result = db.session.query(UserModel).filter(UserModel.uuid == user_id).all()
except Exception as e:
return {}, 403
if 'uuid' in r:
return r
else:
return r, 403
if len(result) == 0:
return {}, 404
db.session.query(UserModel).filter(UserModel.uuid == user_id).delete()
db.session.commit()
return user_schema.dumps(result[0]), 200
@app.route("/category", methods = ["GET"])
def ep_category_get():
+7
View File
@@ -0,0 +1,7 @@
import os
PROPAGATE_EXCEPTIONS = True
SQLALCHEMY_DATABASE_URI = f'postgresql://{os.environ["POSTGRES_USER"]}:{os.environ["POSTGRES_PASSWORD"]}@db:5432/accountance'
SQLALCHEMY_TRACK_MODIFICATIONS = False
API_TITLE = "Finance REST API"
API_VERSION = 'v1'
+10
View File
@@ -12,3 +12,13 @@ services:
- "12402:12402"
volumes:
- ./app:/app/app
env_file:
- db.env
depends_on:
- db
db:
restart: unless-stopped
image: postgres:17.2-alpine3.21
env_file:
- db.env
+13
View File
@@ -1,7 +1,20 @@
alembic==1.14.0
apispec==6.8.0
blinker==1.8.2
click==8.1.7
Flask==3.0.3
Flask-Migrate==4.0.7
flask-smorest==0.45.0
Flask-SQLAlchemy==3.1.1
greenlet==3.1.1
itsdangerous==2.2.0
Jinja2==3.1.4
Mako==1.3.8
MarkupSafe==2.1.5
marshmallow==3.23.2
packaging==24.2
psycopg2-binary==2.9.10
SQLAlchemy==2.0.36
typing_extensions==4.12.2
webargs==8.6.0
Werkzeug==3.0.4
+58
View File
@@ -0,0 +1,58 @@
#!/bin/sh
HOST=$1
if [ -z HOST ]; then
echo "Host not specified, exiting"
exit 1;
fi;
echo -n 'Resetting DB...'
curl -X GET -f -s \
http://$HOST:12402/reset_users_because_postman_is_dumb_like_that > /dev/null
if [ $? -ne 0 ]; then
echo 'Exiting due to previous error'
exit 1
fi
echo ' Done.'
echo -n 'Creating users...'
for i in $(seq 9); do
curl -X POST -f -s \
--data "{\"name\": \"hi$i\"}" \
--header "Content-Type: application/json" \
http://$HOST:12402/user > /dev/null;
if [ $? -ne 0 ]; then
echo 'Exiting due to previous error'
exit 1
fi
done
echo ' Done.'
echo -n 'Getting user UUID to delete...'
DELETION_UUID=$(curl -X GET -f -s \
http://$HOST:12402/users \
| jq .[0].uuid);
if [ $? -ne 0 ]; then
echo 'Exiting due to previous error'
exit 1
fi
DELETION_UUID=${DELETION_UUID#\"}
DELETION_UUID=${DELETION_UUID%\"}
echo " $DELETION_UUID."
echo -n "Deleting user $DELETION_UUID..."
curl -X DELETE -f -s \
http://127.0.0.1:12402/user/$DELETION_UUID > /dev/null
if [ $? -ne 0 ]; then
echo 'Exiting due to previous error'
exit 1
fi
echo ' Done.'