From 5a5ee71a157a38685c648131b5475b03dc245bab Mon Sep 17 00:00:00 2001 From: Llloooggg Date: Fri, 18 Nov 2022 19:38:15 +0300 Subject: [PATCH] =?UTF-8?q?backend:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2=D1=8B=D0=B5?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D0=BA=D0=BB=D0=B0?= =?UTF-8?q?=D1=81=D1=81=D0=BE=D0=B2,=20=D1=80=D0=B0=D1=81=D1=81=20=D0=B8?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D1=81=D0=BE=D0=BD=D0=B0=D0=B6=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/migrations/versions/4126152c5668_.py | 51 +++++++++++++ backend/migrations/versions/5aef83a8a42f_.py | 54 ++++++++++++++ backend/textsouls/admin.py | 15 ++++ backend/textsouls/common/views.py | 68 +++++++++++++++++ backend/textsouls/main.py | 77 +++----------------- backend/textsouls/models.py | 57 +++++++++++++++ 6 files changed, 254 insertions(+), 68 deletions(-) create mode 100644 backend/migrations/versions/4126152c5668_.py create mode 100644 backend/migrations/versions/5aef83a8a42f_.py create mode 100644 backend/textsouls/common/views.py diff --git a/backend/migrations/versions/4126152c5668_.py b/backend/migrations/versions/4126152c5668_.py new file mode 100644 index 0000000..eb5a0cb --- /dev/null +++ b/backend/migrations/versions/4126152c5668_.py @@ -0,0 +1,51 @@ +"""empty message + +Revision ID: 4126152c5668 +Revises: 8f02337dbef0 +Create Date: 2022-11-18 18:46:52.576544 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4126152c5668' +down_revision = '8f02337dbef0' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('character_classes', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('character_races', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('characters', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('owner', sa.Integer(), nullable=True), + sa.Column('name', sa.String(length=255), nullable=True), + sa.Column('character_race', sa.Integer(), nullable=True), + sa.Column('character_class', sa.Integer(), nullable=True), + sa.Column('created_on', sa.DateTime(), nullable=False), + sa.ForeignKeyConstraint(['character_class'], ['character_classes.id'], ), + sa.ForeignKeyConstraint(['character_race'], ['character_races.id'], ), + sa.ForeignKeyConstraint(['owner'], ['users.id'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('characters') + op.drop_table('character_races') + op.drop_table('character_classes') + # ### end Alembic commands ### diff --git a/backend/migrations/versions/5aef83a8a42f_.py b/backend/migrations/versions/5aef83a8a42f_.py new file mode 100644 index 0000000..8ff8fac --- /dev/null +++ b/backend/migrations/versions/5aef83a8a42f_.py @@ -0,0 +1,54 @@ +"""empty message + +Revision ID: 5aef83a8a42f +Revises: 4126152c5668 +Create Date: 2022-11-18 19:18:39.496655 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import mysql + +# revision identifiers, used by Alembic. +revision = '5aef83a8a42f' +down_revision = '4126152c5668' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('characters', schema=None) as batch_op: + batch_op.alter_column('owner', + existing_type=mysql.INTEGER(), + nullable=False) + batch_op.alter_column('name', + existing_type=mysql.VARCHAR(length=255), + nullable=False) + batch_op.alter_column('character_race', + existing_type=mysql.INTEGER(), + nullable=False) + batch_op.alter_column('character_class', + existing_type=mysql.INTEGER(), + nullable=False) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('characters', schema=None) as batch_op: + batch_op.alter_column('character_class', + existing_type=mysql.INTEGER(), + nullable=True) + batch_op.alter_column('character_race', + existing_type=mysql.INTEGER(), + nullable=True) + batch_op.alter_column('name', + existing_type=mysql.VARCHAR(length=255), + nullable=True) + batch_op.alter_column('owner', + existing_type=mysql.INTEGER(), + nullable=True) + + # ### end Alembic commands ### diff --git a/backend/textsouls/admin.py b/backend/textsouls/admin.py index 688176c..0384aa6 100644 --- a/backend/textsouls/admin.py +++ b/backend/textsouls/admin.py @@ -3,8 +3,13 @@ from flask_admin.contrib.sqla import ModelView from . import admin from textsouls.models import db + from textsouls.models import User +from textsouls.models import CharacterRace +from textsouls.models import CharacterClass +from textsouls.models import Character + ts_admin = Blueprint("ts_admin", __name__) @@ -15,4 +20,14 @@ class AdminView(ModelView): super(AdminView, self).__init__(model, *args, **kwargs) +class CommonView(ModelView): + def __init__(self, model, *args, **kwargs): + self.column_list = [c.key for c in model.__table__.columns] + super(CommonView, self).__init__(model, *args, **kwargs) + + admin.add_view(AdminView(User, db.session)) + +admin.add_view(CommonView(CharacterRace, db.session)) +admin.add_view(CommonView(CharacterClass, db.session)) +admin.add_view(CommonView(Character, db.session)) diff --git a/backend/textsouls/common/views.py b/backend/textsouls/common/views.py new file mode 100644 index 0000000..45bf457 --- /dev/null +++ b/backend/textsouls/common/views.py @@ -0,0 +1,68 @@ +from .. import db + +from flask import request +from flask import jsonify +from flask.views import MethodView + + +class ItemAPI(MethodView): + init_every_request = False + + def __init__(self, model): + self.model = model + + def _get_item(self, id): + return self.model.query.get_or_404(id) + + def get(self, id): + item = self._get_item(id) + return item.to_dict() + + def patch(self, id): + item = self._get_item(id) + errors = self.validator.validate(item, request.json) + + if errors: + return jsonify(errors), 400 + + item.update_from_json(request.json) + db.session.commit() + return item.to_dict() + + def delete(self, id): + item = self._get_item(id) + db.session.delete(item) + db.session.commit() + return "", 200 + + +class ListAPI(MethodView): + init_every_request = False + + def __init__(self, model): + self.model = model + + def _get_item(self, id): + return self.model.query.filter_by(id=id).first() + + def get(self): + items = self.model.query.all() + return jsonify([item.to_dict() for item in items]) + + def post(self): + + item = self._get_item(request.json["id"]) + + if item: + return "Already exists!", 400 + + db.session.add(self.model(**request.json)) + db.session.commit() + return "", 200 + + +def register_api(app, model, name): + item = ItemAPI.as_view(f"{name}-item", model) + group = ListAPI.as_view(f"{name}-list", model) + app.add_url_rule(f"/{name}/", view_func=item) + app.add_url_rule(f"/{name}/", view_func=group) diff --git a/backend/textsouls/main.py b/backend/textsouls/main.py index 83dd8c3..9848e23 100644 --- a/backend/textsouls/main.py +++ b/backend/textsouls/main.py @@ -1,75 +1,16 @@ from flask import Blueprint -from flask import request -from flask import jsonify -from flask.views import MethodView -from . import db +from textsouls.common.views import register_api from textsouls.models import User +from textsouls.models import CharacterRace +from textsouls.models import CharacterClass +from textsouls.models import Character + main = Blueprint("main", __name__) - -class ItemAPI(MethodView): - init_every_request = False - - def __init__(self, model): - self.model = model - - def _get_item(self, id): - return self.model.query.get_or_404(id) - - def get(self, id): - item = self._get_item(id) - return item.to_dict() - - def patch(self, id): - item = self._get_item(id) - errors = self.validator.validate(item, request.json) - - if errors: - return jsonify(errors), 400 - - item.update_from_json(request.json) - db.session.commit() - return item.to_dict() - - def delete(self, id): - item = self._get_item(id) - db.session.delete(item) - db.session.commit() - return "", 200 - - -class ListAPI(MethodView): - init_every_request = False - - def __init__(self, model): - self.model = model - - def _get_item(self, id): - return self.model.query.filter_by(id=id).first() - - def get(self): - items = self.model.query.all() - return jsonify([item.to_dict() for item in items]) - - def post(self): - - item = self._get_item(request.json["id"]) - - if item: - return "Already exists!", 400 - - db.session.add(self.model(**request.json)) - db.session.commit() - return "", 200 - - -def register_api(app, model, name): - item = ItemAPI.as_view(f"{name}-item", model) - group = ListAPI.as_view(f"{name}-list", model) - app.add_url_rule(f"/{name}/", view_func=item) - app.add_url_rule(f"/{name}/", view_func=group) - - register_api(main, User, "users") + +register_api(main, CharacterRace, "charachter-races") +register_api(main, CharacterClass, "charachter-classes") +register_api(main, Character, "character") diff --git a/backend/textsouls/models.py b/backend/textsouls/models.py index 588e98d..bdba1e6 100644 --- a/backend/textsouls/models.py +++ b/backend/textsouls/models.py @@ -19,3 +19,60 @@ class User(db.Model, SerializerMixin): db.DateTime, nullable=False, default=datetime.datetime.now() ) is_admin = db.Column(db.Boolean, nullable=False, default=False) + character = db.relationship("Character", backref="user", lazy="dynamic") + + def __str__(self): + return f"{self.id}: {self.username}" + + +class CharacterRace(db.Model, SerializerMixin): + + __tablename__ = "character_races" + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(255), nullable=True) + character = db.relationship("Character", backref="race", lazy="dynamic") + + def __str__(self): + return self.name + + +class CharacterClass(db.Model, SerializerMixin): + + __tablename__ = "character_classes" + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(255), nullable=True) + character = db.relationship("Character", backref="class", lazy="dynamic") + + def __str__(self): + return self.name + + +class Character(db.Model, SerializerMixin): + + __tablename__ = "characters" + + id = db.Column(db.Integer, primary_key=True) + owner = db.Column( + db.Integer, + db.ForeignKey("users.id"), + nullable=False, + ) + name = db.Column(db.String(255), nullable=False) + character_race = db.Column( + db.Integer, + db.ForeignKey("character_races.id"), + nullable=False, + ) + character_class = db.Column( + db.Integer, + db.ForeignKey("character_classes.id"), + nullable=False, + ) + created_on = db.Column( + db.DateTime, nullable=False, default=datetime.datetime.now() + ) + + def __str__(self): + return self.name