diff --git a/backend/textsouls/__init__.py b/backend/textsouls/__init__.py index 985ad78..aa61b3c 100644 --- a/backend/textsouls/__init__.py +++ b/backend/textsouls/__init__.py @@ -1,14 +1,14 @@ import json from flask import Flask +from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_admin import Admin -from textsouls.models import db - app = Flask( "__name__", ) +db = SQLAlchemy() migrate = Migrate(app, db, compare_type=True) admin = Admin(name="TextSouls") @@ -25,10 +25,14 @@ app.config.update(db_settings) admin.init_app(app) db.init_app(app) -from .admin import ts_admin as ts_admin_blueprint +from textsouls.actions.api import bp -app.register_blueprint(ts_admin_blueprint) +app.register_blueprint(bp) -from .main import main as main_blueprint +from textsouls.characters.api import bp -app.register_blueprint(main_blueprint) +app.register_blueprint(bp) + +from textsouls.users.api import bp + +app.register_blueprint(bp) diff --git a/backend/textsouls/actions/__init__.py b/backend/textsouls/actions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/textsouls/actions/api.py b/backend/textsouls/actions/api.py new file mode 100644 index 0000000..4248c1f --- /dev/null +++ b/backend/textsouls/actions/api.py @@ -0,0 +1,19 @@ +from flask import Blueprint + +from textsouls import db +from textsouls import admin + +from textsouls.common.api import register_api +from textsouls.common.api import CommonAdminView + +from textsouls.actions.models import DuelParticipant +from textsouls.actions.models import Duel + + +bp = Blueprint("actions", __name__) + +register_api(bp, DuelParticipant, "duels_participant") +register_api(bp, Duel, "duels") + +admin.add_view(CommonAdminView(DuelParticipant, db.session)) +admin.add_view(CommonAdminView(Duel, db.session)) diff --git a/backend/textsouls/actions/models.py b/backend/textsouls/actions/models.py new file mode 100644 index 0000000..8996147 --- /dev/null +++ b/backend/textsouls/actions/models.py @@ -0,0 +1,108 @@ +import datetime +from random import randint + +from sqlalchemy.orm import backref +from sqlalchemy_serializer import SerializerMixin + +from textsouls import db + +from textsouls.characters.models import Character + + +class DuelParticipant(db.Model, SerializerMixin): + + __tablename__ = "duels_participants" + + id = db.Column(db.Integer, primary_key=True) + participant_id = db.Column( + db.Integer, + db.ForeignKey("characters.id", ondelete="CASCADE"), + ) + turn_order = db.Column(db.Integer, nullable=False) + duel_id = db.Column( + db.Integer, + db.ForeignKey("duels.id", ondelete="CASCADE"), + ) + + def __str__(self): + return f"{self.duel_id}: {self.participant_id}" + + +class Duel(db.Model, SerializerMixin): + + __tablename__ = "duels" + + id = db.Column(db.Integer, primary_key=True) + created_on = db.Column( + db.DateTime, nullable=False, default=datetime.datetime.now() + ) + participants = db.relationship( + "DuelParticipant", + backref=backref("duel", order_by="DuelParticipant.turn_order.asc()"), + lazy="dynamic", + ) + + def attack(self, attacked_character, defensive_character): + defensive_character_endurance = ( + defensive_character.endurance_base + - attacked_character.battle_stats["attack_power"] + ) + + return defensive_character_endurance + + def defence(self, defensive_character): + procced = False + if ( + randint( + int(10 * defensive_character.battle_stats["defence_chance"]), + 50, + ) + == 50 + ): + procced is True + + return procced + + def dodge(self, defensive_character): + procced = False + if ( + randint( + int(10 * defensive_character.battle_stats["dodge_chance"]), 50 + ) + == 50 + ): + procced is True + + return procced + + def duel_one_to_one(self): + + character_first = Character.query.get( + self.participants[0].participant_id + ) + character_second = Character.query.get( + self.participants[1].participant_id + ) + + while ( + character_first.endurance_base > 0 + and character_second.endurance_base > 0 + ): + if not self.defence(character_second) or not self.dodge( + character_second + ): + character_second.endurance_base = self.attack( + character_first, character_second + ) + if not self.defence(character_first) or not self.dodge( + character_first + ): + character_first.endurance_base = self.attack( + character_second, character_first + ) + if character_first.endurance_base > 0: + return character_first.name + elif character_second.endurance_base > 0: + return character_second.name + else: + return "Ничья" diff --git a/backend/textsouls/admin.py b/backend/textsouls/admin.py deleted file mode 100644 index d749f43..0000000 --- a/backend/textsouls/admin.py +++ /dev/null @@ -1,41 +0,0 @@ -from flask import Blueprint -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 CharacterState -from textsouls.models import Character - -from textsouls.models import DuelParticipant -from textsouls.models import Duel - -ts_admin = Blueprint("ts_admin", __name__) - - -class AdminView(ModelView): - def __init__(self, model, *args, **kwargs): - self.column_list = [c.key for c in model.__table__.columns] - self.form_columns = self.column_list - 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(CharacterState, db.session)) -admin.add_view(CommonView(Character, db.session)) - -admin.add_view(CommonView(DuelParticipant, db.session)) -admin.add_view(CommonView(Duel, db.session)) diff --git a/backend/textsouls/characters/__init__.py b/backend/textsouls/characters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/textsouls/characters/api.py b/backend/textsouls/characters/api.py new file mode 100644 index 0000000..1fb77cf --- /dev/null +++ b/backend/textsouls/characters/api.py @@ -0,0 +1,25 @@ +from flask import Blueprint + +from textsouls import db +from textsouls import admin + +from textsouls.common.api import register_api +from textsouls.common.api import CommonAdminView + +from textsouls.characters.models import CharacterRace +from textsouls.characters.models import CharacterClass +from textsouls.characters.models import CharacterState +from textsouls.characters.models import Character + + +bp = Blueprint("characters", __name__) + +register_api(bp, CharacterRace, "character_races") +register_api(bp, CharacterClass, "character_classes") +register_api(bp, CharacterState, "character_states") +register_api(bp, Character, "characters", "owner") + +admin.add_view(CommonAdminView(CharacterRace, db.session)) +admin.add_view(CommonAdminView(CharacterClass, db.session)) +admin.add_view(CommonAdminView(CharacterState, db.session)) +admin.add_view(CommonAdminView(Character, db.session)) diff --git a/backend/textsouls/models.py b/backend/textsouls/characters/models.py similarity index 56% rename from backend/textsouls/models.py rename to backend/textsouls/characters/models.py index 956208e..83b3c48 100644 --- a/backend/textsouls/models.py +++ b/backend/textsouls/characters/models.py @@ -1,34 +1,8 @@ import datetime -from random import randint - -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy.orm import backref from sqlalchemy_serializer import SerializerMixin - -db = SQLAlchemy() - - -class User(db.Model, SerializerMixin): - - __tablename__ = "users" - - serialize_rules = ("-character",) - - id = db.Column(db.BigInteger, primary_key=True, autoincrement=False) - chat_id = db.Column(db.BigInteger, nullable=False, unique=True) - first_name = db.Column(db.String(255), nullable=True) - last_name = db.Column(db.String(255), nullable=True) - username = db.Column(db.String(255), nullable=False) - registered_on = db.Column( - db.DateTime, nullable=False, default=datetime.datetime.now() - ) - is_admin = db.Column(db.Boolean, nullable=False, default=False) - characters = db.relationship("Character", backref="user", lazy="dynamic") - - def __str__(self): - return f"{self.id}: {self.username}" +from textsouls import db class CharacterRace(db.Model, SerializerMixin): @@ -174,102 +148,3 @@ class Character(db.Model, SerializerMixin): "defence_chance": defence_chance, "dodge_chance": dodge_chance, } - - -class DuelParticipant(db.Model, SerializerMixin): - - __tablename__ = "duels_participants" - - id = db.Column(db.Integer, primary_key=True) - participant_id = db.Column( - db.Integer, - db.ForeignKey("characters.id", ondelete="CASCADE"), - ) - turn_order = db.Column(db.Integer, nullable=False) - duel_id = db.Column( - db.Integer, - db.ForeignKey("duels.id", ondelete="CASCADE"), - ) - - def __str__(self): - return f"{self.duel_id}: {self.participant_id}" - - -class Duel(db.Model, SerializerMixin): - - __tablename__ = "duels" - - id = db.Column(db.Integer, primary_key=True) - created_on = db.Column( - db.DateTime, nullable=False, default=datetime.datetime.now() - ) - participants = db.relationship( - "DuelParticipant", - backref=backref("duel", order_by="DuelParticipant.turn_order.asc()"), - lazy="dynamic", - ) - - def attack(self, attacked_character, defensive_character): - defensive_character_endurance = ( - defensive_character.endurance_base - - attacked_character.battle_stats["attack_power"] - ) - - return defensive_character_endurance - - def defence(self, defensive_character): - procced = False - if ( - randint( - int(10 * defensive_character.battle_stats["defence_chance"]), - 50, - ) - == 50 - ): - procced is True - - return procced - - def dodge(self, defensive_character): - procced = False - if ( - randint( - int(10 * defensive_character.battle_stats["dodge_chance"]), 50 - ) - == 50 - ): - procced is True - - return procced - - def duel_one_to_one(self): - - character_first = Character.query.get( - self.participants[0].participant_id - ) - character_second = Character.query.get( - self.participants[1].participant_id - ) - - while ( - character_first.endurance_base > 0 - and character_second.endurance_base > 0 - ): - if not self.defence(character_second) or not self.dodge( - character_second - ): - character_second.endurance_base = self.attack( - character_first, character_second - ) - if not self.defence(character_first) or not self.dodge( - character_first - ): - character_first.endurance_base = self.attack( - character_second, character_first - ) - if character_first.endurance_base > 0: - return character_first.name - elif character_second.endurance_base > 0: - return character_second.name - else: - return "Ничья" diff --git a/backend/textsouls/common/__init__.py b/backend/textsouls/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/textsouls/common/views.py b/backend/textsouls/common/api.py similarity index 85% rename from backend/textsouls/common/views.py rename to backend/textsouls/common/api.py index 4c7bc79..c103c85 100644 --- a/backend/textsouls/common/views.py +++ b/backend/textsouls/common/api.py @@ -1,8 +1,16 @@ -from .. import db - from flask import request from flask.views import MethodView +from flask_admin.contrib.sqla import ModelView + +from textsouls import db + + +class CommonAdminView(ModelView): + def __init__(self, model, *args, **kwargs): + self.column_list = [c.key for c in model.__table__.columns] + super(CommonAdminView, self).__init__(model, *args, **kwargs) + class ItemAPI(MethodView): init_every_request = False diff --git a/backend/textsouls/main.py b/backend/textsouls/main.py deleted file mode 100644 index ca46a3a..0000000 --- a/backend/textsouls/main.py +++ /dev/null @@ -1,25 +0,0 @@ -from flask import Blueprint - -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 CharacterState -from textsouls.models import Character - -from textsouls.models import DuelParticipant -from textsouls.models import Duel - -main = Blueprint("main", __name__) - -register_api(main, User, "users") - -register_api(main, CharacterRace, "character_races") -register_api(main, CharacterClass, "character_classes") -register_api(main, CharacterState, "character_states") -register_api(main, Character, "characters", "owner") - - -register_api(main, DuelParticipant, "duels_participant") -register_api(main, Duel, "duels") diff --git a/backend/textsouls/users/__init__.py b/backend/textsouls/users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/textsouls/users/api.py b/backend/textsouls/users/api.py new file mode 100644 index 0000000..9f8957b --- /dev/null +++ b/backend/textsouls/users/api.py @@ -0,0 +1,24 @@ +from flask import Blueprint + +from flask_admin.contrib.sqla import ModelView + +from textsouls import db +from textsouls import admin + +from textsouls.common.api import register_api + +from textsouls.users.models import User + + +class UserAdminView(ModelView): + def __init__(self, model, *args, **kwargs): + self.column_list = [c.key for c in model.__table__.columns] + self.form_columns = self.column_list + super(UserAdminView, self).__init__(model, *args, **kwargs) + + +bp = Blueprint("users", __name__) + +register_api(bp, User, "users") + +admin.add_view(UserAdminView(User, db.session)) diff --git a/backend/textsouls/users/models.py b/backend/textsouls/users/models.py new file mode 100644 index 0000000..f7ac2f9 --- /dev/null +++ b/backend/textsouls/users/models.py @@ -0,0 +1,26 @@ +import datetime + +from sqlalchemy_serializer import SerializerMixin + +from textsouls import db + + +class User(db.Model, SerializerMixin): + + __tablename__ = "users" + + serialize_rules = ("-character",) + + id = db.Column(db.BigInteger, primary_key=True, autoincrement=False) + chat_id = db.Column(db.BigInteger, nullable=False, unique=True) + first_name = db.Column(db.String(255), nullable=True) + last_name = db.Column(db.String(255), nullable=True) + username = db.Column(db.String(255), nullable=False) + registered_on = db.Column( + db.DateTime, nullable=False, default=datetime.datetime.now() + ) + is_admin = db.Column(db.Boolean, nullable=False, default=False) + characters = db.relationship("Character", backref="user", lazy="dynamic") + + def __str__(self): + return f"{self.id}: {self.username}"