From 68ce9303618306eaf7f7625d38a396a6edbfc793 Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 19:55:41 +0100 Subject: [PATCH 01/10] Create lint.yml --- .github/workflows/lint.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..80242d4 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,28 @@ +name: Lint + +on: push + +jobs: + run-linters: + name: Run linters + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: 3.8 + + - name: Install Python dependencies + run: pip install black flake8 + + - name: Run linters + uses: wearerequired/lint-action@v1 + with: + github_token: ${{ secrets.github_token }} + # Enable linters + black: true + flake8: true From 679b3528ecef0bde7c6dbea8691d3f31f629b3ac Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 19:59:09 +0100 Subject: [PATCH 02/10] Enable auto_fix --- .github/workflows/lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 80242d4..a390845 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,3 +26,4 @@ jobs: # Enable linters black: true flake8: true + auto_fix: true From d6b20cc9afe65a30d30907e4d6746d407e654e8d Mon Sep 17 00:00:00 2001 From: Lint Action Date: Wed, 14 Oct 2020 19:00:11 +0000 Subject: [PATCH 03/10] Fix code style issues with Black --- Exceptions/user_error.py | 10 +- app.py | 41 +++-- connection_events.py | 14 +- create_cards.py | 313 ++++++++++++++++++++--------------- db.py | 5 +- db_models/card.py | 27 ++- db_models/cardtype.py | 10 +- db_models/deckentry.py | 15 +- db_models/defence.py | 23 ++- db_models/discardentry.py | 11 +- db_models/game.py | 45 +++-- db_models/gameround.py | 16 +- db_models/roundbattle.py | 21 +-- globals.py | 28 ++-- logic/battle_logic.py | 14 +- logic/card_logic.py | 24 ++- logic/card_manager.py | 2 +- logic/game_logic.py | 183 ++++++++++++++------ logic/game_manager.py | 23 ++- logic/gameparams.py | 18 +- logic/player_logic.py | 6 +- logic/player_manager.py | 20 ++- logic/round_logic.py | 7 +- mod_game/game_process.py | 45 +++-- mod_game/game_state.py | 2 + mod_game/waitroom.py | 34 ++-- mod_gameselect/controller.py | 65 +++++--- mod_test/test.py | 5 +- session.py | 4 +- utils/conversion.py | 3 +- utils/memoize.py | 1 - utils/socketio_helper.py | 2 +- 32 files changed, 650 insertions(+), 387 deletions(-) diff --git a/Exceptions/user_error.py b/Exceptions/user_error.py index 8ea55d5..6598d64 100644 --- a/Exceptions/user_error.py +++ b/Exceptions/user_error.py @@ -3,11 +3,11 @@ class UserError(Exception): class ErrorType(Enum): - GENERIC_ERROR = 0, - INVALID_NAME = 1, - INVALID_GAME = 2, - INVALID_DELETION = 3, - INVALID_GAME_DELETION = 4, + GENERIC_ERROR = (0,) + INVALID_NAME = (1,) + INVALID_GAME = (2,) + INVALID_DELETION = (3,) + INVALID_GAME_DELETION = (4,) def __init__(self, message, error_type=ErrorType.GENERIC_ERROR): self.message = message diff --git a/app.py b/app.py index bf7bd58..134bb61 100644 --- a/app.py +++ b/app.py @@ -3,38 +3,49 @@ from mod_test.test import mod_test from flask import send_from_directory -if __name__ != '__main__': +if __name__ != "__main__": import sys import os - if os.path.split(sys.argv[0])[1].replace('.py', '') == __name__: - raise ImportError('No. Please do not import app. It will lead too all kinds of ridiculous stuff.') + + if os.path.split(sys.argv[0])[1].replace(".py", "") == __name__: + raise ImportError( + "No. Please do not import app. It will lead too all kinds of ridiculous stuff." + ) import globals + app = globals.app -print('starting...') +print("starting...") -@app.route('/io') +@app.route("/io") def hello_world(): - return render_template('test_io.html') + return render_template("test_io.html") + -@app.route('/favicon.ico') +@app.route("/favicon.ico") def favicon(): import os - return send_from_directory(os.path.join(app.root_path, 'static'), - 'favicon.ico',mimetype='image/vnd.microsoft.icon') -@app.route('/instruction') + return send_from_directory( + os.path.join(app.root_path, "static"), + "favicon.ico", + mimetype="image/vnd.microsoft.icon", + ) + + +@app.route("/instruction") def rules(): - return render_template('instruction.html') + return render_template("instruction.html") + -@app.route('/glossary') +@app.route("/glossary") def glossary(): - return render_template('glossary.html') + return render_template("glossary.html") -if True or __name__ == '__main__': +if True or __name__ == "__main__": # Registering socketio listeners import mod_game.waitroom import mod_game.game_state @@ -49,5 +60,5 @@ def glossary(): app.register_blueprint(mod_game_wr) app.register_blueprint(mod_game_process) app.register_blueprint(mod_test, url_prefix="/test") -if __name__ == '__main__': +if __name__ == "__main__": globals.socketio.run(app) diff --git a/connection_events.py b/connection_events.py index 46ed48e..9935d2d 100644 --- a/connection_events.py +++ b/connection_events.py @@ -10,12 +10,12 @@ from utils.socketio_helper import commit_and_notify_if_dirty -@socketio.on('disconnect') +@socketio.on("disconnect") def on_disconnect(): change_state(False) -@socketio.on('connect') +@socketio.on("connect") def on_connect(): change_state(True) @@ -44,10 +44,16 @@ def change_state(is_online: bool): def change_admin(is_online: bool, player: PlayerLogic): if not is_online and player.model.isAdmin: gm = GameManager(db) - new_adm = next((p.model for p in gm.get_my_game().get_players(True) if (not p.model.isAdmin and p.model.isOnline)), None) + new_adm = next( + ( + p.model + for p in gm.get_my_game().get_players(True) + if (not p.model.isAdmin and p.model.isOnline) + ), + None, + ) if new_adm is not None: new_adm.isAdmin = True player.model.isAdmin = False db.session.commit() gm.get_my_game().notify() - diff --git a/create_cards.py b/create_cards.py index 69d9f1b..f1054b9 100644 --- a/create_cards.py +++ b/create_cards.py @@ -12,85 +12,101 @@ def get_popup_from_json(data: list, name: str) -> str: return [next((i for i in data if i.get("name") == name), None)][0]["popUpText"] + def get_url_from_json(data: list, name: str) -> str: return [next((i for i in data if i.get("name") == name), None)][0]["popUpURL"] def create_offence_type(data: list): - cardTypeOffence = CardType(name='Нападение', color='Red', enumType=CardTypeEnum.OFFENCE) + cardTypeOffence = CardType( + name="Нападение", color="Red", enumType=CardTypeEnum.OFFENCE + ) - cardTypeOffence.cards = [Card( - name='Шифровальщик', - popUpText=get_popup_from_json(data, "Шифровальщик"), - popUpURL=get_url_from_json(data, "Шифровальщик"), - countInDeck=5, - damage=7), + cardTypeOffence.cards = [ + Card( + name="Шифровальщик", + popUpText=get_popup_from_json(data, "Шифровальщик"), + popUpURL=get_url_from_json(data, "Шифровальщик"), + countInDeck=5, + damage=7, + ), Card( - name='Кейлоггер', + name="Кейлоггер", popUpText=get_popup_from_json(data, "Кейлоггер"), popUpURL=get_url_from_json(data, "Кейлоггер"), countInDeck=4, - damage=5), + damage=5, + ), Card( - name='Удаленное выполнение кода', + name="Удаленное выполнение кода", popUpText=get_popup_from_json(data, "Удаленное выполнение кода"), popUpURL=get_url_from_json(data, "Удаленное выполнение кода"), countInDeck=4, - damage=7), + damage=7, + ), Card( - name='Посредственный фишинг', + name="Посредственный фишинг", popUpText=get_popup_from_json(data, "Фишинг"), popUpURL=get_url_from_json(data, "Фишинг"), countInDeck=5, - damage=3), + damage=3, + ), Card( - name='Подготовленный фишинг', + name="Подготовленный фишинг", popUpText=get_popup_from_json(data, "Фишинг"), popUpURL=get_url_from_json(data, "Фишинг"), countInDeck=5, - damage=5), + damage=5, + ), Card( - name='Целенаправленный фишинг', + name="Целенаправленный фишинг", popUpText=get_popup_from_json(data, "Фишинг"), popUpURL=get_url_from_json(data, "Фишинг"), countInDeck=5, - damage=7), + damage=7, + ), Card( - name='Прослушка', + name="Прослушка", popUpText=get_popup_from_json(data, "Прослушка"), popUpURL=get_url_from_json(data, "Прослушка"), countInDeck=4, - damage=4), + damage=4, + ), Card( - name='Перехват пакетов Wi-Fi', + name="Перехват пакетов Wi-Fi", popUpText=get_popup_from_json(data, "Перехват пакетов Wi-Fi"), popUpURL=get_url_from_json(data, "Перехват пакетов Wi-Fi"), countInDeck=4, - damage=4), + damage=4, + ), Card( - name='Выполнение макросов', + name="Выполнение макросов", popUpText=get_popup_from_json(data, "Выполнение макросов"), popUpURL=get_url_from_json(data, "Выполнение макросов"), countInDeck=4, - damage=4), + damage=4, + ), Card( - name='Ваш пароль взломали перебором', + name="Ваш пароль взломали перебором", popUpText=get_popup_from_json(data, "Ваш пароль взломали перебором"), popUpURL=get_url_from_json(data, "Ваш пароль взломали перебором"), countInDeck=5, - damage=4), + damage=4, + ), Card( - name='Устаревшее ПО', + name="Устаревшее ПО", popUpText=get_popup_from_json(data, "Устаревшее ПО"), popUpURL=get_url_from_json(data, "Устаревшее ПО"), countInDeck=4, - damage=4), + damage=4, + ), Card( - name='Вы попали в ботнет', + name="Вы попали в ботнет", popUpText=get_popup_from_json(data, "Вы попали в ботнет"), popUpURL=get_url_from_json(data, "Вы попали в ботнет"), countInDeck=4, - damage=5), + damage=5, + ), ] db.session.add(cardTypeOffence) @@ -98,51 +114,61 @@ def create_offence_type(data: list): def create_accident_type(data: list): - cardTypeAccident = CardType(name='Случайность', color='Blue', enumType=CardTypeEnum.ACCIDENT) + cardTypeAccident = CardType( + name="Случайность", color="Blue", enumType=CardTypeEnum.ACCIDENT + ) - cardTypeAccident.cards = [Card( - name='Уязвимости нулевого дня', - popUpText=get_popup_from_json(data, "Уязвимости нулевого дня"), - popUpURL=get_url_from_json(data, "Уязвимости нулевого дня"), - countInDeck=3, - damage=6), + cardTypeAccident.cards = [ Card( - name='Взлом серверов и утечка паролей', + name="Уязвимости нулевого дня", + popUpText=get_popup_from_json(data, "Уязвимости нулевого дня"), + popUpURL=get_url_from_json(data, "Уязвимости нулевого дня"), + countInDeck=3, + damage=6, + ), + Card( + name="Взлом серверов и утечка паролей", popUpText=get_popup_from_json(data, "Взлом серверов и утечка паролей"), popUpURL=get_url_from_json(data, "Взлом серверов и утечка паролей"), countInDeck=3, - damage=5), + damage=5, + ), Card( - name='Железные бэкдоры', + name="Железные бэкдоры", popUpText=get_popup_from_json(data, "Железные бэкдоры"), popUpURL=get_url_from_json(data, "Железные бэкдоры"), countInDeck=3, - damage=3), + damage=3, + ), Card( - name='Катаклизмы', + name="Катаклизмы", popUpText=get_popup_from_json(data, "Катаклизмы"), popUpURL=get_url_from_json(data, "Катаклизмы"), countInDeck=3, - damage=4), + damage=4, + ), Card( - name='Кража ноутбука', + name="Кража ноутбука", popUpText=get_popup_from_json(data, "Кража ноутбука"), popUpURL=get_url_from_json(data, "Кража ноутбука"), countInDeck=3, - damage=5), + damage=5, + ), Card( - name='Блокировка доступа к ресурсам', + name="Блокировка доступа к ресурсам", popUpText=get_popup_from_json(data, "Блокировка доступа к ресурсам"), popUpURL=get_url_from_json(data, "Блокировка доступа к ресурсам"), countInDeck=3, - damage=3), + damage=3, + ), Card( - name='COVID-19', + name="COVID-19", popUpText=get_popup_from_json(data, "COVID-19"), popUpURL=get_url_from_json(data, "COVID-19"), isCovid=True, countInDeck=3, - damage=0), + damage=0, + ), ] db.session.add(cardTypeAccident) @@ -150,81 +176,96 @@ def create_accident_type(data: list): def create_defence_type(data: list): - cardTypeDefence = CardType(name='Защита', color='Green', enumType=CardTypeEnum.DEFENCE) + cardTypeDefence = CardType( + name="Защита", color="Green", enumType=CardTypeEnum.DEFENCE + ) cardTypeDefence.cards = [ Card( - name='Антивирус', + name="Антивирус", popUpText=get_popup_from_json(data, "Антивирус"), popUpURL=get_url_from_json(data, "Антивирус"), countInDeck=9, - damage=None), + damage=None, + ), Card( - name='Двухфакторная аутентификация', + name="Двухфакторная аутентификация", popUpText=get_popup_from_json(data, "Двухфакторная аутентификация"), popUpURL=get_url_from_json(data, "Двухфакторная аутентификация"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Сложные пароли', + name="Сложные пароли", popUpText=get_popup_from_json(data, "Сложные пароли"), popUpURL=get_url_from_json(data, "Сложные пароли"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Полнодисковое шифрование', + name="Полнодисковое шифрование", popUpText=get_popup_from_json(data, "Полнодисковое шифрование"), popUpURL=get_url_from_json(data, "Полнодисковое шифрование"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Использование VPN', + name="Использование VPN", popUpText=get_popup_from_json(data, "Использование VPN"), popUpURL=get_url_from_json(data, "Использование VPN"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Регулярные обновления', + name="Регулярные обновления", popUpText=get_popup_from_json(data, "Регулярные обновления"), popUpURL=get_url_from_json(data, "Регулярные обновления"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Лицензионное ПО', + name="Лицензионное ПО", popUpText=get_popup_from_json(data, "Лицензионное ПО"), popUpURL=get_url_from_json(data, "Лицензионное ПО"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Надежные мессенджеры', + name="Надежные мессенджеры", popUpText=get_popup_from_json(data, "Надежные мессенджеры"), popUpURL=get_url_from_json(data, "Надежные мессенджеры"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Пользовательская осторожность', + name="Пользовательская осторожность", popUpText=get_popup_from_json(data, "Пользовательская осторожность"), popUpURL=get_url_from_json(data, "Пользовательская осторожность"), countInDeck=9, - damage=None), + damage=None, + ), Card( - name='Использование HTTPS', + name="Использование HTTPS", popUpText=get_popup_from_json(data, "Использование HTTPS"), popUpURL=get_url_from_json(data, "Использование HTTPS"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Регулярные бэкапы', + name="Регулярные бэкапы", popUpText=get_popup_from_json(data, "Регулярные бэкапы"), popUpURL=get_url_from_json(data, "Регулярные бэкапы"), countInDeck=8, - damage=None), + damage=None, + ), Card( - name='Цифровая подпись и шифрование писем', + name="Цифровая подпись и шифрование писем", popUpText=get_popup_from_json(data, "Цифровая подпись и шифрование писем"), popUpURL=get_url_from_json(data, "Цифровая подпись и шифрование писем"), countInDeck=8, - damage=None), ] + damage=None, + ), + ] db.session.add(cardTypeDefence) return cardTypeDefence @@ -234,84 +275,84 @@ def defence(cardTypeDefence, cardTypeOffence, cardTypeAccident): defences = {card.name: card for card in cardTypeDefence.cards} offences = {card.name: card for card in cardTypeOffence.cards} accidents = {card.name: card for card in cardTypeAccident.cards} - defences['Антивирус'].defensiveFrom = [ - Defence(offence=offences['Шифровальщик'], value=3), - Defence(offence=offences['Кейлоггер'], value=3), - Defence(offence=offences['Удаленное выполнение кода'], value=2), - Defence(offence=offences['Выполнение макросов'], value=2), - Defence(offence=offences['Вы попали в ботнет'], value=2), - Defence(offence=offences['Посредственный фишинг'], value=1), - Defence(offence=offences['Подготовленный фишинг'], value=1), - Defence(offence=offences['Целенаправленный фишинг'], value=1), + defences["Антивирус"].defensiveFrom = [ + Defence(offence=offences["Шифровальщик"], value=3), + Defence(offence=offences["Кейлоггер"], value=3), + Defence(offence=offences["Удаленное выполнение кода"], value=2), + Defence(offence=offences["Выполнение макросов"], value=2), + Defence(offence=offences["Вы попали в ботнет"], value=2), + Defence(offence=offences["Посредственный фишинг"], value=1), + Defence(offence=offences["Подготовленный фишинг"], value=1), + Defence(offence=offences["Целенаправленный фишинг"], value=1), ] - defences['Двухфакторная аутентификация'].defensiveFrom = [ - Defence(offence=offences['Посредственный фишинг'], value=3), - Defence(offence=offences['Подготовленный фишинг'], value=3), - Defence(offence=offences['Целенаправленный фишинг'], value=3), - Defence(offence=offences['Ваш пароль взломали перебором'], value=2), - Defence(offence=accidents['Взлом серверов и утечка паролей'], value=2), - Defence(offence=accidents['Кража ноутбука'], value=2), + defences["Двухфакторная аутентификация"].defensiveFrom = [ + Defence(offence=offences["Посредственный фишинг"], value=3), + Defence(offence=offences["Подготовленный фишинг"], value=3), + Defence(offence=offences["Целенаправленный фишинг"], value=3), + Defence(offence=offences["Ваш пароль взломали перебором"], value=2), + Defence(offence=accidents["Взлом серверов и утечка паролей"], value=2), + Defence(offence=accidents["Кража ноутбука"], value=2), ] - defences['Сложные пароли'].defensiveFrom = [ - Defence(offence=offences['Ваш пароль взломали перебором'], value=3), + defences["Сложные пароли"].defensiveFrom = [ + Defence(offence=offences["Ваш пароль взломали перебором"], value=3), ] - defences['Полнодисковое шифрование'].defensiveFrom = [ - Defence(offence=accidents['Кража ноутбука'], value=2), + defences["Полнодисковое шифрование"].defensiveFrom = [ + Defence(offence=accidents["Кража ноутбука"], value=2), ] - defences['Использование VPN'].defensiveFrom = [ - Defence(offence=offences['Перехват пакетов Wi-Fi'], value=3), - Defence(offence=accidents['Блокировка доступа к ресурсам'], value=2), + defences["Использование VPN"].defensiveFrom = [ + Defence(offence=offences["Перехват пакетов Wi-Fi"], value=3), + Defence(offence=accidents["Блокировка доступа к ресурсам"], value=2), ] - defences['Регулярные обновления'].defensiveFrom = [ - Defence(offence=offences['Устаревшее ПО'], value=3), - Defence(offence=offences['Удаленное выполнение кода'], value=2), - Defence(offence=offences['Шифровальщик'], value=1), - Defence(offence=accidents['Уязвимости нулевого дня'], value=2), + defences["Регулярные обновления"].defensiveFrom = [ + Defence(offence=offences["Устаревшее ПО"], value=3), + Defence(offence=offences["Удаленное выполнение кода"], value=2), + Defence(offence=offences["Шифровальщик"], value=1), + Defence(offence=accidents["Уязвимости нулевого дня"], value=2), ] - defences['Лицензионное ПО'].defensiveFrom = [ - Defence(offence=offences['Шифровальщик'], value=2), - Defence(offence=offences['Кейлоггер'], value=2), - Defence(offence=offences['Удаленное выполнение кода'], value=2), - Defence(offence=offences['Вы попали в ботнет'], value=2), - Defence(offence=offences['Устаревшее ПО'], value=1), + defences["Лицензионное ПО"].defensiveFrom = [ + Defence(offence=offences["Шифровальщик"], value=2), + Defence(offence=offences["Кейлоггер"], value=2), + Defence(offence=offences["Удаленное выполнение кода"], value=2), + Defence(offence=offences["Вы попали в ботнет"], value=2), + Defence(offence=offences["Устаревшее ПО"], value=1), ] - defences['Надежные мессенджеры'].defensiveFrom = [ - Defence(offence=offences['Прослушка'], value=3), - Defence(offence=offences['Перехват пакетов Wi-Fi'], value=2), - Defence(offence=accidents['Блокировка доступа к ресурсам'], value=1), + defences["Надежные мессенджеры"].defensiveFrom = [ + Defence(offence=offences["Прослушка"], value=3), + Defence(offence=offences["Перехват пакетов Wi-Fi"], value=2), + Defence(offence=accidents["Блокировка доступа к ресурсам"], value=1), ] - defences['Пользовательская осторожность'].defensiveFrom = [ - Defence(offence=offences['Посредственный фишинг'], value=3), - Defence(offence=offences['Подготовленный фишинг'], value=3), - Defence(offence=offences['Целенаправленный фишинг'], value=3), - Defence(offence=offences['Шифровальщик'], value=2), - Defence(offence=offences['Кейлоггер'], value=2), - Defence(offence=offences['Выполнение макросов'], value=2), - Defence(offence=accidents['Взлом серверов и утечка паролей'], value=1), + defences["Пользовательская осторожность"].defensiveFrom = [ + Defence(offence=offences["Посредственный фишинг"], value=3), + Defence(offence=offences["Подготовленный фишинг"], value=3), + Defence(offence=offences["Целенаправленный фишинг"], value=3), + Defence(offence=offences["Шифровальщик"], value=2), + Defence(offence=offences["Кейлоггер"], value=2), + Defence(offence=offences["Выполнение макросов"], value=2), + Defence(offence=accidents["Взлом серверов и утечка паролей"], value=1), ] - defences['Использование HTTPS'].defensiveFrom = [ - Defence(offence=offences['Прослушка'], value=2), - Defence(offence=offences['Перехват пакетов Wi-Fi'], value=3), + defences["Использование HTTPS"].defensiveFrom = [ + Defence(offence=offences["Прослушка"], value=2), + Defence(offence=offences["Перехват пакетов Wi-Fi"], value=3), ] - defences['Регулярные бэкапы'].defensiveFrom = [ - Defence(offence=offences['Устаревшее ПО'], value=2), - Defence(offence=offences['Шифровальщик'], value=4), - Defence(offence=accidents['Кража ноутбука'], value=3), - Defence(offence=accidents['Уязвимости нулевого дня'], value=1), - Defence(offence=accidents['Катаклизмы'], value=1), + defences["Регулярные бэкапы"].defensiveFrom = [ + Defence(offence=offences["Устаревшее ПО"], value=2), + Defence(offence=offences["Шифровальщик"], value=4), + Defence(offence=accidents["Кража ноутбука"], value=3), + Defence(offence=accidents["Уязвимости нулевого дня"], value=1), + Defence(offence=accidents["Катаклизмы"], value=1), ] - defences['Цифровая подпись и шифрование писем'].defensiveFrom = [ - Defence(offence=offences['Посредственный фишинг'], value=2), - Defence(offence=offences['Подготовленный фишинг'], value=2), - Defence(offence=offences['Целенаправленный фишинг'], value=2), - Defence(offence=offences['Прослушка'], value=2), - Defence(offence=accidents['Кража ноутбука'], value=1), + defences["Цифровая подпись и шифрование писем"].defensiveFrom = [ + Defence(offence=offences["Посредственный фишинг"], value=2), + Defence(offence=offences["Подготовленный фишинг"], value=2), + Defence(offence=offences["Целенаправленный фишинг"], value=2), + Defence(offence=offences["Прослушка"], value=2), + Defence(offence=accidents["Кража ноутбука"], value=1), ] @manager.command def fill(): - with open('descriptions.json') as f: + with open("descriptions.json") as f: data = json.load(f) defenceCards = create_defence_type(data) offenceCards = create_offence_type(data) @@ -321,5 +362,5 @@ def fill(): print("DB data initialized") -if __name__ == '__main__': +if __name__ == "__main__": manager.run() diff --git a/db.py b/db.py index 96740e7..5ed4924 100644 --- a/db.py +++ b/db.py @@ -13,8 +13,7 @@ migrate = Migrate(app, db) manager = Manager(app) -manager.add_command('db', MigrateCommand) +manager.add_command("db", MigrateCommand) -if __name__ == '__main__': +if __name__ == "__main__": manager.run() - diff --git a/db_models/card.py b/db_models/card.py index 3547ea7..80e5c20 100644 --- a/db_models/card.py +++ b/db_models/card.py @@ -3,8 +3,9 @@ from db_models.cardtype import CardType from db_models.defence import Defence + class Card(db.Model): - __tablename__ = 'card' + __tablename__ = "card" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(40), unique=True, nullable=False) text = db.Column(db.Text, nullable=True) @@ -12,16 +13,26 @@ class Card(db.Model): imageURL = db.Column(db.Text, nullable=True) popUpText = db.Column(db.Text, nullable=True) popUpURL = db.Column(db.Text, nullable=True) - typeId = db.Column(db.Integer, db.ForeignKey('cardtype.id'), nullable=False) - type = db.relationship('CardType', back_populates='cards', uselist=False, lazy=False) + typeId = db.Column(db.Integer, db.ForeignKey("cardtype.id"), nullable=False) + type = db.relationship( + "CardType", back_populates="cards", uselist=False, lazy=False + ) isCovid = db.Column(db.Boolean, default=False) damage = db.Column(db.Integer, nullable=True) countInDeck = db.Column(db.Integer, nullable=False) - offensiveAgainst = db.relationship('Defence', foreign_keys='Defence.offenceCardId', back_populates='offence', lazy=False) - defensiveFrom = db.relationship('Defence', foreign_keys='Defence.defenceCardId', back_populates='defence', lazy=False) - + offensiveAgainst = db.relationship( + "Defence", + foreign_keys="Defence.offenceCardId", + back_populates="offence", + lazy=False, + ) + defensiveFrom = db.relationship( + "Defence", + foreign_keys="Defence.defenceCardId", + back_populates="defence", + lazy=False, + ) def __repr__(self): - return ''%self.name - + return "" % self.name diff --git a/db_models/cardtype.py b/db_models/cardtype.py index a9bcd55..4c45819 100644 --- a/db_models/cardtype.py +++ b/db_models/cardtype.py @@ -3,19 +3,21 @@ from flask_sqlalchemy import SQLAlchemy from globals import db + class CardTypeEnum(Enum): UNKNOWN = 0 DEFENCE = 1 OFFENCE = 2 ACCIDENT = 3 + class CardType(db.Model): - __tablename__ = 'cardtype' + __tablename__ = "cardtype" id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(40), unique=True, nullable=False) - color = db.Column(db.String(128), nullable=False) + color = db.Column(db.String(128), nullable=False) enumType = db.Column(db.Enum(CardTypeEnum), nullable=False) - cards = db.relationship('Card', back_populates='type', lazy=True) + cards = db.relationship("Card", back_populates="type", lazy=True) def __repr__(self): - return ''%self.name \ No newline at end of file + return "" % self.name diff --git a/db_models/deckentry.py b/db_models/deckentry.py index caa0e69..560e008 100644 --- a/db_models/deckentry.py +++ b/db_models/deckentry.py @@ -2,13 +2,14 @@ import db_models.game from db_models.card import Card + class DeckEntry(db.Model): - #__table_args__ = {'extend_existing': True} - __tablename__ = 'deckentry' + # __table_args__ = {'extend_existing': True} + __tablename__ = "deckentry" id = db.Column(db.Integer, primary_key=True) # TODO: Undo nullable - cardId = db.Column(db.Integer, db.ForeignKey('card.id'), nullable=True) - gameId = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False) - card = db.relationship('Card', lazy=False) - game = db.relationship('Game', back_populates='deck', lazy=False) - order = db.Column(db.Integer, nullable=False) \ No newline at end of file + cardId = db.Column(db.Integer, db.ForeignKey("card.id"), nullable=True) + gameId = db.Column(db.Integer, db.ForeignKey("game.id"), nullable=False) + card = db.relationship("Card", lazy=False) + game = db.relationship("Game", back_populates="deck", lazy=False) + order = db.Column(db.Integer, nullable=False) diff --git a/db_models/defence.py b/db_models/defence.py index 8e07432..b27438a 100644 --- a/db_models/defence.py +++ b/db_models/defence.py @@ -2,16 +2,27 @@ from globals import db import db_models.card + class Defence(db.Model): - __tablename__ = 'defence' + __tablename__ = "defence" id = db.Column(db.Integer, primary_key=True) - defenceCardId = db.Column(db.Integer, db.ForeignKey('card.id'), nullable=False) - offenceCardId = db.Column(db.Integer, db.ForeignKey('card.id'), nullable=False) + defenceCardId = db.Column(db.Integer, db.ForeignKey("card.id"), nullable=False) + offenceCardId = db.Column(db.Integer, db.ForeignKey("card.id"), nullable=False) value = db.Column(db.Integer, nullable=False) - defence = db.relationship("Card", back_populates='defensiveFrom', foreign_keys=[defenceCardId], uselist=False) - offence = db.relationship("Card", back_populates='offensiveAgainst', foreign_keys=[offenceCardId], uselist=False) + defence = db.relationship( + "Card", + back_populates="defensiveFrom", + foreign_keys=[defenceCardId], + uselist=False, + ) + offence = db.relationship( + "Card", + back_populates="offensiveAgainst", + foreign_keys=[offenceCardId], + uselist=False, + ) def __repr__(self): - return ''%self.value + return "" % self.value diff --git a/db_models/discardentry.py b/db_models/discardentry.py index 57b42da..a417a34 100644 --- a/db_models/discardentry.py +++ b/db_models/discardentry.py @@ -2,10 +2,11 @@ import db_models.game from db_models.card import Card + class DiscardEntry(db.Model): - __tablename__ = 'discardentry' + __tablename__ = "discardentry" id = db.Column(db.Integer, primary_key=True) - cardId = db.Column(db.Integer, db.ForeignKey('card.id'), nullable=False) - gameId = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False) - card = db.relationship('Card', lazy=False) - game = db.relationship('Game', back_populates='discard', lazy=False) + cardId = db.Column(db.Integer, db.ForeignKey("card.id"), nullable=False) + gameId = db.Column(db.Integer, db.ForeignKey("game.id"), nullable=False) + card = db.relationship("Card", lazy=False) + game = db.relationship("Game", back_populates="discard", lazy=False) diff --git a/db_models/game.py b/db_models/game.py index ecc8024..e3def35 100644 --- a/db_models/game.py +++ b/db_models/game.py @@ -4,40 +4,57 @@ import db_models.discardentry import db_models.gameround + class Game(db.Model): - __tablename__ = 'game' + __tablename__ = "game" id = db.Column(db.Integer, primary_key=True) uniqueCode = db.Column(db.String(20), unique=True, nullable=False) params = db.Column(db.Text, nullable=False) roundsCompleted = db.Column(db.Integer, nullable=False) isComplete = db.Column(db.Boolean, default=False) isStarted = db.Column(db.Boolean, default=False) - players = db.relationship('Player', back_populates='game', cascade='all,delete', order_by='asc(Player.id)') - deck = db.relationship('DeckEntry', back_populates='game', cascade='all,delete', lazy=True) - discard = db.relationship('DiscardEntry', back_populates='game', cascade='all,delete', lazy=True) - rounds = db.relationship('GameRound', back_populates='game', cascade='all,delete', order_by='desc(GameRound.roundNo)') + players = db.relationship( + "Player", back_populates="game", cascade="all,delete", order_by="asc(Player.id)" + ) + deck = db.relationship( + "DeckEntry", back_populates="game", cascade="all,delete", lazy=True + ) + discard = db.relationship( + "DiscardEntry", back_populates="game", cascade="all,delete", lazy=True + ) + rounds = db.relationship( + "GameRound", + back_populates="game", + cascade="all,delete", + order_by="desc(GameRound.roundNo)", + ) lastActionAt = db.Column(db.DateTime, nullable=False) def __repr__(self): - return '' % self.uniqueCode + return "" % self.uniqueCode class Player(db.Model): - __tablename__ = 'player' + __tablename__ = "player" id = db.Column(db.Integer, unique=True, primary_key=True) - gameId = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False) - game = db.relationship('Game', back_populates='players') + gameId = db.Column(db.Integer, db.ForeignKey("game.id"), nullable=False) + game = db.relationship("Game", back_populates="players") name = db.Column(db.String(20), nullable=False) money = db.Column(db.Integer, nullable=False) moneyAfterRound = db.Column(db.Integer, nullable=True) hand = db.Column(db.Text, nullable=True) - neighbourId = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True) - neighbourRight = db.relationship('Player', backref='neighbourLeft', remote_side='Player.id', uselist=False, post_update=True) + neighbourId = db.Column(db.Integer, db.ForeignKey("player.id"), nullable=True) + neighbourRight = db.relationship( + "Player", + backref="neighbourLeft", + remote_side="Player.id", + uselist=False, + post_update=True, + ) isAdmin = db.Column(db.Boolean, nullable=False) isOnline = db.Column(db.Boolean, nullable=False) hasLeft = db.Column(db.Boolean, nullable=False, default=False) - __table_args__ = (db.UniqueConstraint('name', 'gameId', name='_name_gameid_uc'), - ) + __table_args__ = (db.UniqueConstraint("name", "gameId", name="_name_gameid_uc"),) def __repr__(self): - return '' % self.name + return "" % self.name diff --git a/db_models/gameround.py b/db_models/gameround.py index 2db35d5..9ce212f 100644 --- a/db_models/gameround.py +++ b/db_models/gameround.py @@ -4,16 +4,18 @@ class GameRound(db.Model): - __tablename__ = 'gameround' + __tablename__ = "gameround" # TODO: Add relationships id = db.Column(db.Integer, primary_key=True) - game_id = db.Column(db.Integer, db.ForeignKey('game.id'), nullable=False) - game = db.relationship('Game', back_populates='rounds') + game_id = db.Column(db.Integer, db.ForeignKey("game.id"), nullable=False) + game = db.relationship("Game", back_populates="rounds") roundNo = db.Column(db.Integer, nullable=False) isComplete = db.Column(db.Boolean, default=False) isAccidentComplete = db.Column(db.Boolean, default=False) - currentPlayerId = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True) - currentPlayer = db.relationship('Player') - battles = db.relationship('RoundBattle', back_populates="round", cascade='all,delete') + currentPlayerId = db.Column(db.Integer, db.ForeignKey("player.id"), nullable=True) + currentPlayer = db.relationship("Player") + battles = db.relationship( + "RoundBattle", back_populates="round", cascade="all,delete" + ) ### stage: is played - #stage = db.Column() + # stage = db.Column() diff --git a/db_models/roundbattle.py b/db_models/roundbattle.py index 98f8b5b..32f458f 100644 --- a/db_models/roundbattle.py +++ b/db_models/roundbattle.py @@ -3,21 +3,22 @@ import db_models.game import db_models.card + class RoundBattle(db.Model): - __tablename__ = 'roundbattle' + __tablename__ = "roundbattle" id = db.Column(db.Integer, primary_key=True) - roundId = db.Column(db.Integer, db.ForeignKey('gameround.id'), nullable=False) - round = db.relationship('GameRound', back_populates="battles") - offendingPlayerId = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True) - offendingPlayer = db.relationship('Player', foreign_keys=[offendingPlayerId]) + roundId = db.Column(db.Integer, db.ForeignKey("gameround.id"), nullable=False) + round = db.relationship("GameRound", back_populates="battles") + offendingPlayerId = db.Column(db.Integer, db.ForeignKey("player.id"), nullable=True) + offendingPlayer = db.relationship("Player", foreign_keys=[offendingPlayerId]) - defendingPlayerId = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True) - defendingPlayer = db.relationship('Player', foreign_keys=[defendingPlayerId]) + defendingPlayerId = db.Column(db.Integer, db.ForeignKey("player.id"), nullable=True) + defendingPlayer = db.relationship("Player", foreign_keys=[defendingPlayerId]) - offensiveCardId = db.Column(db.Integer, db.ForeignKey('card.id'), nullable=True) - offensiveCard = db.relationship('Card') + offensiveCardId = db.Column(db.Integer, db.ForeignKey("card.id"), nullable=True) + offensiveCard = db.relationship("Card") defensiveCards = db.Column(db.Text, nullable=True) isComplete = db.Column(db.Boolean, default=False) - creationOrder = db.Column(db.Integer, nullable=False) \ No newline at end of file + creationOrder = db.Column(db.Integer, nullable=False) diff --git a/globals.py b/globals.py index 2502112..d648a9b 100644 --- a/globals.py +++ b/globals.py @@ -7,30 +7,34 @@ # I utterly hate Python sometimes # https://stackoverflow.com/questions/46622408/flask-socket-io-message-events-in-different-files -local_mode = len(sys.argv) == 2 and sys.argv[1] == 'local' +local_mode = len(sys.argv) == 2 and sys.argv[1] == "local" if not local_mode: - critical_env = ['FLASK_KEY', 'MYSQL_USER', 'MYSQL_PASSWORD'] + critical_env = ["FLASK_KEY", "MYSQL_USER", "MYSQL_PASSWORD"] for env in critical_env: if env not in os.environ or len(os.environ[env]) == 0: raise Exception("Missing critical env " + env) -FLASK_KEY = 'Changeme' if local_mode else os.environ['FLASK_KEY'] -MYSQL_USER = '' if local_mode else os.environ['MYSQL_USER'] -MYSQL_PASSWORD = '' if local_mode else os.environ['MYSQL_PASSWORD'] +FLASK_KEY = "Changeme" if local_mode else os.environ["FLASK_KEY"] +MYSQL_USER = "" if local_mode else os.environ["MYSQL_USER"] +MYSQL_PASSWORD = "" if local_mode else os.environ["MYSQL_PASSWORD"] app = Flask(__name__) -app.config['SECRET_KEY'] = FLASK_KEY -app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 +app.config["SECRET_KEY"] = FLASK_KEY +app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 0 # install libmysqlclient-dev! if not local_mode: - app.config[ - 'SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqldb://' + MYSQL_USER + ':' + \ - MYSQL_PASSWORD + '@localhost/fs?charset=utf8mb4' + app.config["SQLALCHEMY_DATABASE_URI"] = ( + "mysql+mysqldb://" + + MYSQL_USER + + ":" + + MYSQL_PASSWORD + + "@localhost/fs?charset=utf8mb4" + ) else: - app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' -app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///test.db" +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False db = SQLAlchemy(app) socketio = SocketIO(app) diff --git a/logic/battle_logic.py b/logic/battle_logic.py index 80f7a59..bb15a62 100644 --- a/logic/battle_logic.py +++ b/logic/battle_logic.py @@ -17,9 +17,13 @@ def __init__(self, db: SQLAlchemy, model: RoundBattle): def get_defensive_cards(self): if self.model.defensiveCards is None: return [] - return [CardLogic(self.db, card) for card in - [self.db.session.query(Card).filter_by(id=cardId).first() for cardId in - json.loads(self.model.defensiveCards)]] + return [ + CardLogic(self.db, card) + for card in [ + self.db.session.query(Card).filter_by(id=cardId).first() + for cardId in json.loads(self.model.defensiveCards) + ] + ] def add_defensive_card(self, card: CardLogic): lst = [] @@ -45,7 +49,9 @@ def to_ui(self): offender=self.model.offendingPlayerId, defender=self.model.defendingPlayerId, offensive_card=self.model.offensiveCardId, - defensive_cards=None if self.model.defensiveCards is None else json.loads(self.model.defensiveCards), + defensive_cards=None + if self.model.defensiveCards is None + else json.loads(self.model.defensiveCards), damage_remains=self.get_curdamage(), is_complete=self.model.isComplete, creation_order=self.model.creationOrder, diff --git a/logic/card_logic.py b/logic/card_logic.py index a94f763..f3d07a4 100644 --- a/logic/card_logic.py +++ b/logic/card_logic.py @@ -12,7 +12,7 @@ class CardLogic: - def __init__(self, db: SQLAlchemy, model: Card, owner: 'PlayerLogic' = None): + def __init__(self, db: SQLAlchemy, model: Card, owner: "PlayerLogic" = None): self.db = db self.model = model self.owner = owner @@ -21,8 +21,11 @@ def get_defence_from(self, offenciveCard: Card) -> int: if self.model.type.enumType != CardTypeEnum.DEFENCE: return None return first_or_none( - [defence.value for defence in self.model.defensiveFrom if - defence.offence == offenciveCard] + [ + defence.value + for defence in self.model.defensiveFrom + if defence.offence == offenciveCard + ] ) def to_ui(self, extended=False) -> UiCard: @@ -39,10 +42,17 @@ def to_ui(self, extended=False) -> UiCard: pop_up_text=self.model.popUpText if extended else None, pop_up_url=self.model.popUpURL if extended else None, type=card_type, - off_against=None if card_type == UiCardType.Defence else - [CardPairing(o.defenceCardId, o.value) for o in self.model.offensiveAgainst], - def_against=None if card_type != UiCardType.Defence else - [CardPairing(o.offenceCardId, o.value) for o in self.model.defensiveFrom], + off_against=None + if card_type == UiCardType.Defence + else [ + CardPairing(o.defenceCardId, o.value) + for o in self.model.offensiveAgainst + ], + def_against=None + if card_type != UiCardType.Defence + else [ + CardPairing(o.offenceCardId, o.value) for o in self.model.defensiveFrom + ], dealt_by_player=None if self.owner is None else self.owner.model.id, damage=self.model.damage, ) diff --git a/logic/card_manager.py b/logic/card_manager.py index c855ce1..44df49e 100644 --- a/logic/card_manager.py +++ b/logic/card_manager.py @@ -18,4 +18,4 @@ def get_card(self, card_id: int) -> CardLogic: return CardLogic(self.db, self.db.session.query(Card).filter_by(id=card_id)[0]) def get_all_cards(self) -> List[CardLogic]: - return [CardLogic(self.db, c) for c in self.db.session.query(Card)] \ No newline at end of file + return [CardLogic(self.db, c) for c in self.db.session.query(Card)] diff --git a/logic/game_logic.py b/logic/game_logic.py index ff42747..fb16fa6 100644 --- a/logic/game_logic.py +++ b/logic/game_logic.py @@ -52,7 +52,7 @@ def keep_alive(self): self.model.lastActionAt = datetime.now() def notify(self): - socketio.emit('upd', room=self.model.uniqueCode) + socketio.emit("upd", room=self.model.uniqueCode) self.is_dirty_ = False def get_state(self) -> State: @@ -63,17 +63,25 @@ def get_state(self) -> State: return GameLogic.State.WAITROOM def get_old_rounds(self, starting_from: int) -> List[RoundLogic]: - return [RoundLogic(self.db, x) for x in - self.db.session.query(GameRound).filter_by(game=self.model).filter(GameRound.roundNo >= starting_from)] + return [ + RoundLogic(self.db, x) + for x in self.db.session.query(GameRound) + .filter_by(game=self.model) + .filter(GameRound.roundNo >= starting_from) + ] def get_battles(self, includePrevRound=False) -> List[BattleLogic]: if self.model.isComplete: return [] extra = [] if includePrevRound: - prev_round = self.db.session.query(GameRound).filter(GameRound.game == self.model).filter( - GameRound.roundNo == self.cur_round.roundNo - 1).all() - if (len(prev_round) != 0): + prev_round = ( + self.db.session.query(GameRound) + .filter(GameRound.game == self.model) + .filter(GameRound.roundNo == self.cur_round.roundNo - 1) + .all() + ) + if len(prev_round) != 0: extra = prev_round[0].battles return [BattleLogic(self.db, b) for b in extra + self.cur_round.battles] @@ -88,7 +96,10 @@ def is_waitroom(self): def join_player(self, player: PlayerLogic, is_admin: bool) -> None: if self.get_state() != GameLogic.State.WAITROOM: - raise UserError("Невозможно присоединиться к запущенной игре", error_type=UserError.ErrorType.INVALID_GAME) + raise UserError( + "Невозможно присоединиться к запущенной игре", + error_type=UserError.ErrorType.INVALID_GAME, + ) if is_admin: player.make_admin() self.set_dirty() @@ -110,8 +121,16 @@ def can_start(self, player: PlayerLogic): def initialize_player(self, player): player.model.money = self.params.initial_falsics - self.deal(player, self.card_manager.get_type(CardTypeEnum.DEFENCE), self.params.initial_defence_cards) - self.deal(player, self.card_manager.get_type(CardTypeEnum.OFFENCE), self.params.initial_offence_cards) + self.deal( + player, + self.card_manager.get_type(CardTypeEnum.DEFENCE), + self.params.initial_defence_cards, + ) + self.deal( + player, + self.card_manager.get_type(CardTypeEnum.OFFENCE), + self.params.initial_offence_cards, + ) self.set_dirty() def make_deck(self, typ: CardType = None): @@ -129,7 +148,7 @@ def make_deck(self, typ: CardType = None): else: while len(rv) < deck_size: random.shuffle(all_cards_dup) - rv.extend(all_cards_dup[:deck_size - len(rv)]) + rv.extend(all_cards_dup[: deck_size - len(rv)]) for card in rv: de = DeckEntry( cardId=card.id, @@ -147,17 +166,22 @@ def start_battle(self, offendingPlayer: PlayerLogic): self.assert_running() new_battle_no = 0 if any(self.cur_round.battles): - new_battle_no = max(map(lambda x: x.creationOrder, self.cur_round.battles)) + 1 + new_battle_no = ( + max(map(lambda x: x.creationOrder, self.cur_round.battles)) + 1 + ) new_battle = RoundBattle( round=self.cur_round, offendingPlayer=None if offendingPlayer is None else offendingPlayer.model, isComplete=False, - creationOrder=new_battle_no + creationOrder=new_battle_no, ) self.db.session.add(new_battle) self.set_dirty() if not self.params.can_attack_anyone: - self.attack(offendingPlayer, PlayerLogic(self.db, self.get_neighbour(offendingPlayer), game=self)) + self.attack( + offendingPlayer, + PlayerLogic(self.db, self.get_neighbour(offendingPlayer), game=self), + ) return new_battle def on_accident_played(self): @@ -171,10 +195,17 @@ def calculate_battle_falsics(self, battle: BattleLogic): btl_model = battle.model if btl_model.offensiveCard.isCovid: transfer_amount = btl_model.defendingPlayer.money // 2 - PlayerLogic(self.db, self.get_neighbour(PlayerLogic(self.db, btl_model.defendingPlayer))).change_money(transfer_amount) - PlayerLogic(self.db, btl_model.defendingPlayer).change_money(-transfer_amount) + PlayerLogic( + self.db, + self.get_neighbour(PlayerLogic(self.db, btl_model.defendingPlayer)), + ).change_money(transfer_amount) + PlayerLogic(self.db, btl_model.defendingPlayer).change_money( + -transfer_amount + ) else: - PlayerLogic(self.db, btl_model.defendingPlayer).change_money(-battle.get_curdamage()) + PlayerLogic(self.db, btl_model.defendingPlayer).change_money( + -battle.get_curdamage() + ) def get_neighbour(self, player: PlayerLogic): next_player = player.model.neighbourRight @@ -194,12 +225,17 @@ def complete_battle(self, battle: BattleLogic, bypass=False): self.calculate_battle_falsics(battle) btl_model.isComplete = True if self.cur_round.isAccidentComplete: - next_player = self.get_neighbour(PlayerLogic(self.db, btl_model.offendingPlayer)) + next_player = self.get_neighbour( + PlayerLogic(self.db, btl_model.offendingPlayer) + ) if next_player != self.get_players(True)[0].model: self.start_battle(PlayerLogic(self.db, next_player)) if all(map(lambda b: b.model.isComplete, self.get_battles())): - if btl_model.offensiveCard is not None and btl_model.offensiveCard.type.enumType == CardTypeEnum.ACCIDENT: + if ( + btl_model.offensiveCard is not None + and btl_model.offensiveCard.type.enumType == CardTypeEnum.ACCIDENT + ): print("Round", self.cur_round.roundNo, "has accident completed") self.on_accident_played() else: @@ -229,10 +265,7 @@ def new_round(self): self.set_dirty() round_no = 0 if self.cur_round is None else self.cur_round.roundNo + 1 the_round = GameRound( - game=self.model, - roundNo=round_no, - isComplete=False, - currentPlayer=None + game=self.model, roundNo=round_no, isComplete=False, currentPlayer=None ) self.db.session.add(the_round) self.cur_round = the_round @@ -252,10 +285,12 @@ def start(self): self.new_round() def get_from_deck(self, typ: CardType, count: int): - return self.db.session.query(DeckEntry) \ - .filter_by(game=self.model) \ - .filter(DeckEntry.card.has(type=typ)) \ - .order_by(DeckEntry.order)[:count] + return ( + self.db.session.query(DeckEntry) + .filter_by(game=self.model) + .filter(DeckEntry.card.has(type=typ)) + .order_by(DeckEntry.order)[:count] + ) def deal(self, player, typ, count): self.set_dirty() @@ -269,10 +304,17 @@ def deal(self, player, typ, count): def get_player_battle(self, player: PlayerLogic) -> RoundBattle: # There can be at most one btl_model the player belongs to - return first_or_none([x for x in - self.cur_round.battles - if (x.defendingPlayer == player.model or x.offendingPlayer == player.model) - and not x.isComplete]) + return first_or_none( + [ + x + for x in self.cur_round.battles + if ( + x.defendingPlayer == player.model + or x.offendingPlayer == player.model + ) + and not x.isComplete + ] + ) def get_player_battlelogic(self, player: PlayerLogic) -> BattleLogic: # There can be at most one btl_model the player belongs to @@ -339,7 +381,10 @@ def can_play_card(self, card: CardLogic, player: PlayerLogic) -> bool: if cur_damage is None or cur_damage <= 0: # The round is either fully played, or has no offensive card yet return False - return self.params.hardcore_mode or replace_none(card.get_defence_from(my_battle.offensiveCard), 0) > 0 + return ( + self.params.hardcore_mode + or replace_none(card.get_defence_from(my_battle.offensiveCard), 0) > 0 + ) def play_card(self, card: CardLogic, player: PlayerLogic): if not self.can_play_card(card, player): @@ -362,11 +407,26 @@ def end_battle(self, player: PlayerLogic): self.complete_battle(BattleLogic(self.db, battle)) def deal_roundcompleted(self, player: PlayerLogic, avg_spend: int): - player_off_cards_count = len([x for x in player.get_hand() if x.model.type.enumType == CardTypeEnum.OFFENCE]) - self.deal(player, self.card_manager.get_type(CardTypeEnum.OFFENCE), - self.params.initial_offence_cards - player_off_cards_count) + player_off_cards_count = len( + [ + x + for x in player.get_hand() + if x.model.type.enumType == CardTypeEnum.OFFENCE + ] + ) + self.deal( + player, + self.card_manager.get_type(CardTypeEnum.OFFENCE), + self.params.initial_offence_cards - player_off_cards_count, + ) - player_def_cards_count = len([x for x in player.get_hand() if x.model.type.enumType == CardTypeEnum.DEFENCE]) + player_def_cards_count = len( + [ + x + for x in player.get_hand() + if x.model.type.enumType == CardTypeEnum.DEFENCE + ] + ) def_card_count = 0 if self.params.def_card_deal == DefCardDeal.DealFixed: def_card_count = self.params.def_card_deal_size @@ -379,7 +439,9 @@ def deal_roundcompleted(self, player: PlayerLogic, avg_spend: int): elif self.params.def_card_deal == DefCardDeal.DealAverageSpend: def_card_count = avg_spend def_card_count = max(0, def_card_count) - self.deal(player, self.card_manager.get_type(CardTypeEnum.DEFENCE), def_card_count) + self.deal( + player, self.card_manager.get_type(CardTypeEnum.DEFENCE), def_card_count + ) def on_round_completed(self): for player in self.get_players(True): @@ -387,10 +449,19 @@ def on_round_completed(self): num_alive_players = len(self.get_players(True)) if num_alive_players == 0: num_alive_players = 1 # doesn't matter, the game is over anyway - avg_spend = sum( - len([x for x in player.get_hand() if x.model.type.enumType == CardTypeEnum.DEFENCE]) - for player in self.get_players(True) - ) / num_alive_players + avg_spend = ( + sum( + len( + [ + x + for x in player.get_hand() + if x.model.type.enumType == CardTypeEnum.DEFENCE + ] + ) + for player in self.get_players(True) + ) + / num_alive_players + ) for player in self.get_players(True): self.deal_roundcompleted(player, avg_spend) self.complete_game_if_needed() @@ -400,9 +471,15 @@ def should_complete_game(self): n_live_players = len(self.get_players(True)) if n_live_players == 0: return True # Graveyard - if self.params.end_game_deaths == EndGameDeaths.OneDead and n_players != n_live_players: + if ( + self.params.end_game_deaths == EndGameDeaths.OneDead + and n_players != n_live_players + ): return True - if self.params.end_game_deaths == EndGameDeaths.AllButOneDead and n_live_players <= 1: + if ( + self.params.end_game_deaths == EndGameDeaths.AllButOneDead + and n_live_players <= 1 + ): return True if self.params.num_rounds is not None and self.cur_round is not None: return self.cur_round.roundNo + 1 >= self.params.num_rounds @@ -420,23 +497,29 @@ def leave_player(self, player: PlayerLogic): if self.is_running(): player.model.neighbourLeft.neighbourRight = player.model.neighbourRight for battle in self.get_battles(False): - if battle.model.offendingPlayer == player.model or battle.model.defendingPlayer == player.model: + if ( + battle.model.offendingPlayer == player.model + or battle.model.defendingPlayer == player.model + ): self.complete_battle(battle, True) self.db.session.delete(battle.model) def game2redirect(game: GameLogic) -> Optional[str]: - if not (SessionHelper.has(SessionKeys.PLAYER_ID) and SessionHelper.has(SessionKeys.GAME_KEY)): - return '/' + if not ( + SessionHelper.has(SessionKeys.PLAYER_ID) + and SessionHelper.has(SessionKeys.GAME_KEY) + ): + return "/" if game is None: - return '/' + return "/" if game.get_state() == GameLogic.State.WAITROOM: - return '/waitroom' + return "/waitroom" if game.get_state() == GameLogic.State.RUNNING: - return '/game' + return "/game" if game.get_state() == GameLogic.State.FINISHED: - return '/endgame' + return "/endgame" player = PlayerManager(db).get_my_player() if player is None or player.model.game != game.model: - return '/' + return "/" return None diff --git a/logic/game_manager.py b/logic/game_manager.py index f9ac766..7785770 100644 --- a/logic/game_manager.py +++ b/logic/game_manager.py @@ -16,7 +16,7 @@ def get_random_string(length: int) -> str: letters = string.ascii_uppercase + string.ascii_lowercase - result_str = ''.join(random.choice(letters) for i in range(length)) + result_str = "".join(random.choice(letters) for i in range(length)) return result_str @@ -29,8 +29,13 @@ def create_game(self, params: GameParams) -> GameLogic: while retries > 0: # TODO: Make sure this is cryptographically secure game_key = get_random_string(6) - game = Game(uniqueCode=game_key, params=params.to_db(), roundsCompleted=0, isComplete=False, - lastActionAt=datetime.now()) + game = Game( + uniqueCode=game_key, + params=params.to_db(), + roundsCompleted=0, + isComplete=False, + lastActionAt=datetime.now(), + ) try: self.db.session.add(game) self.db.session.commit() @@ -50,14 +55,18 @@ def delete_game(self, game: GameLogic): print("Game deletion problem: " + str(e)) self.db.session.rollback() # TODO: Fix "NOT NULL constraint failed: deckentry.gameId": Cascade delete? - raise UserError("Не удалось удалить игру. По идее, вы не должны видеть эту ошибку", - UserError.ErrorType.INVALID_GAME_DELETION) + raise UserError( + "Не удалось удалить игру. По идее, вы не должны видеть эту ошибку", + UserError.ErrorType.INVALID_GAME_DELETION, + ) def get_game(self, game_key: str, optional=False) -> GameLogic: game = Game.query.filter_by(uniqueCode=game_key).first() if game is None and not optional: - raise UserError("К сожалению, такая игра не найдена. Проверьте уникальный код.", - UserError.ErrorType.INVALID_GAME) + raise UserError( + "К сожалению, такая игра не найдена. Проверьте уникальный код.", + UserError.ErrorType.INVALID_GAME, + ) if game is None: return None return GameLogic(self.db, game) diff --git a/logic/gameparams.py b/logic/gameparams.py index b9aaf1e..8c5ab54 100644 --- a/logic/gameparams.py +++ b/logic/gameparams.py @@ -18,9 +18,21 @@ class DefCardDeal(Enum): class GameParams: - def __init__(self, initial_falsics, initial_defence_cards, initial_offence_cards, accident_probability, - end_game_deaths, deck_size, num_rounds, only_admin_starts, can_attack_anyone, def_card_deal, - def_card_deal_size, hardcore_mode): + def __init__( + self, + initial_falsics, + initial_defence_cards, + initial_offence_cards, + accident_probability, + end_game_deaths, + deck_size, + num_rounds, + only_admin_starts, + can_attack_anyone, + def_card_deal, + def_card_deal_size, + hardcore_mode, + ): self.initial_falsics = initial_falsics self.initial_defence_cards = initial_defence_cards self.initial_offence_cards = initial_offence_cards diff --git a/logic/player_logic.py b/logic/player_logic.py index 9a6176d..fb950d2 100644 --- a/logic/player_logic.py +++ b/logic/player_logic.py @@ -11,11 +11,13 @@ class PlayerLogic: - def __init__(self, db: SQLAlchemy, model: Player, game: 'GameLogic' = None): + def __init__(self, db: SQLAlchemy, model: Player, game: "GameLogic" = None): self.db = db self.model = model self.game = game - self.hand: List[int] = [] if self.model.hand is None else json.loads(self.model.hand) + self.hand: List[int] = ( + [] if self.model.hand is None else json.loads(self.model.hand) + ) def make_admin(self): self.model.isAdmin = True diff --git a/logic/player_manager.py b/logic/player_manager.py index ebbbd70..e2ea28c 100644 --- a/logic/player_manager.py +++ b/logic/player_manager.py @@ -18,16 +18,20 @@ class PlayerManager: def __init__(self, db: SQLAlchemy): self.db = db - def create_player(self, name: str, game: 'GameLogic') -> PlayerLogic: - player = Player(name=name, game=game.model, money=0, isAdmin=False, isOnline=False) + def create_player(self, name: str, game: "GameLogic") -> PlayerLogic: + player = Player( + name=name, game=game.model, money=0, isAdmin=False, isOnline=False + ) self.db.session.add(player) try: self.db.session.commit() except IntegrityError as e: print("Player creation problem: " + str(e)) self.db.session.rollback() - raise UserError("Игрок с таким именем уже существует. Пожалуйста, измените имя.", - UserError.ErrorType.INVALID_NAME) + raise UserError( + "Игрок с таким именем уже существует. Пожалуйста, измените имя.", + UserError.ErrorType.INVALID_NAME, + ) return PlayerLogic(self.db, player) def delete_player(self, player: PlayerLogic): @@ -38,8 +42,10 @@ def delete_player(self, player: PlayerLogic): except IntegrityError as e: print("Player deletion problem: " + str(e)) self.db.session.rollback() - raise UserError("Не удалось удалить игрока из игры. По идее, вы не должны видеть эту ошибку", - UserError.ErrorType.INVALID_DELITION) + raise UserError( + "Не удалось удалить игрока из игры. По идее, вы не должны видеть эту ошибку", + UserError.ErrorType.INVALID_DELITION, + ) def get_player(self, id: int) -> PlayerLogic: player = Player.query.filter_by(id=id).first() @@ -53,7 +59,7 @@ def get_my_player(self) -> PlayerLogic: return None return player - def seat_game_players(self, game: 'GameLogic'): + def seat_game_players(self, game: "GameLogic"): all_players = game.get_players(False) neighbours = all_players[1:] + [all_players[0]] for player, neighbour in zip(all_players, neighbours): diff --git a/logic/round_logic.py b/logic/round_logic.py index 1be2bf1..1b70a3f 100644 --- a/logic/round_logic.py +++ b/logic/round_logic.py @@ -8,15 +8,14 @@ class RoundLogic(object): - def __init__(self, db:SQLAlchemy, model: GameRound): + def __init__(self, db: SQLAlchemy, model: GameRound): self.db = db self.model = model - def get_battles(self)->List[BattleLogic]: + def get_battles(self) -> List[BattleLogic]: return [BattleLogic(self.db, x) for x in self.model.battles] def to_ui(self) -> UiRound: return UiRound( - round_no=self.model.roundNo, - battles=[x.to_ui() for x in self.get_battles()] + round_no=self.model.roundNo, battles=[x.to_ui() for x in self.get_battles()] ) diff --git a/mod_game/game_process.py b/mod_game/game_process.py index fe95b55..c0a7aca 100644 --- a/mod_game/game_process.py +++ b/mod_game/game_process.py @@ -21,7 +21,7 @@ from globals import socketio from utils.socketio_helper import wrapped_socketio -mod_game_process = Blueprint('game_process', __name__) +mod_game_process = Blueprint("game_process", __name__) @dataclass @@ -41,22 +41,22 @@ def subscribe(): join_room(g.game.model.uniqueCode) -@wrapped_socketio('state', 'state') +@wrapped_socketio("state", "state") def get_state(): keep_alive() game = g.game redirect_url = game2redirect(game) - if redirect_url is not None and redirect_url != '/game': + if redirect_url is not None and redirect_url != "/game": return GameState(redirect_to=redirect_url) return prepare_state(game) -@wrapped_socketio('endgame_state', 'endgame_state') +@wrapped_socketio("endgame_state", "endgame_state") def get_endgame_state(): keep_alive() game = g.game redirect_url = game2redirect(game) - if redirect_url is not None and redirect_url != '/endgame': + if redirect_url is not None and redirect_url != "/endgame": return GameState(redirect_to=redirect_url) return prepare_state(game) @@ -81,7 +81,8 @@ def prepare_state(game: GameLogic): neighbour_right=p.model.neighbourId, can_attack=game.can_attack(player, p), money=p.get_money(), - ) for p in players + ) + for p in players ], hand=map_opt(lambda c: make_ui(c, game, player), player.get_hand()), current_battles=[battle.to_ui() for battle in game.get_battles(True)], @@ -89,10 +90,7 @@ def prepare_state(game: GameLogic): is_complete=game.is_complete(), ) - return GameState( - redirect_to='', - game=ui_game - ) + return GameState(redirect_to="", game=ui_game) def assert_has_game(): @@ -105,24 +103,23 @@ def keep_alive(): g.game.keep_alive() -@wrapped_socketio('log', 'log') +@wrapped_socketio("log", "log") def log(starting_from): assert_has_game() keep_alive() return [x.to_ui() for x in g.game.get_old_rounds(starting_from)] -@wrapped_socketio('attack', 'attack') +@wrapped_socketio("attack", "attack") def attack(player_id): assert_has_game() keep_alive() g.game.attack( - get_player_manager().get_my_player(), - get_player_manager().get_player(player_id) + get_player_manager().get_my_player(), get_player_manager().get_player(player_id) ) -@wrapped_socketio('play', 'play') +@wrapped_socketio("play", "play") def play_card(card_ids): assert_has_game() keep_alive() @@ -132,19 +129,19 @@ def play_card(card_ids): return True -@wrapped_socketio('done_def', 'done_def') +@wrapped_socketio("done_def", "done_def") def done_defending(): assert_has_game() keep_alive() g.game.end_battle(get_player_manager().get_my_player()) -@wrapped_socketio('card', 'card') +@wrapped_socketio("card", "card") def get_card(card_id): return get_card_manager().get_card(card_id).to_ui(True) -@wrapped_socketio('cards', 'cards') +@wrapped_socketio("cards", "cards") def get_cards(): return [c.to_ui() for c in get_card_manager().get_all_cards()] @@ -164,23 +161,23 @@ def get_card_manager(): return CardManager(db) -@mod_game_process.route('/game') +@mod_game_process.route("/game") def game(): set_current_player() try: game = get_game_manager().get_my_game() player = get_player_manager().get_my_player() except UserError: - return redirect(url_for('gameselect.index')) - return render_template('game.html', form=ExitForm()) + return redirect(url_for("gameselect.index")) + return render_template("game.html", form=ExitForm()) -@mod_game_process.route('/endgame') +@mod_game_process.route("/endgame") def endgame(): set_current_player() try: game = get_game_manager().get_my_game() player = get_player_manager().get_my_player() except UserError: - return redirect(url_for('gameselect.index')) - return render_template('endgame.html', form=ExitForm()) + return redirect(url_for("gameselect.index")) + return render_template("endgame.html", form=ExitForm()) diff --git a/mod_game/game_state.py b/mod_game/game_state.py index d2f4b86..8da93b8 100644 --- a/mod_game/game_state.py +++ b/mod_game/game_state.py @@ -3,6 +3,7 @@ from dataclasses import dataclass + class UiCardType(Enum): Defence = 0 Offence = 1 @@ -67,6 +68,7 @@ class UiGame: round_no: int is_complete: bool + @dataclass class UiRound: round_no: int diff --git a/mod_game/waitroom.py b/mod_game/waitroom.py index 947b141..fd578a1 100644 --- a/mod_game/waitroom.py +++ b/mod_game/waitroom.py @@ -17,7 +17,7 @@ from globals import socketio from utils.socketio_helper import wrapped_socketio -mod_game_wr = Blueprint('game_wr', __name__) +mod_game_wr = Blueprint("game_wr", __name__) @dataclass @@ -31,31 +31,38 @@ class WaitroomResponse: current_player: str = None - def get_state(): gm = GameManager(db) pm = PlayerManager(db) game = gm.get_my_game(optional=True) redirect_url = game2redirect(game) - if redirect_url is not None and redirect_url != '/waitroom': + if redirect_url is not None and redirect_url != "/waitroom": return WaitroomResponse(redirect_to=redirect_url) return WaitroomResponse( game_name=game.model.uniqueCode, current_player=pm.get_my_player().model.name, - players=[{'name': x.model.name, 'is_admin': x.model.isAdmin, 'is_online': x.model.isOnline} for x in game.get_players(False)], + players=[ + { + "name": x.model.name, + "is_admin": x.model.isAdmin, + "is_online": x.model.isOnline, + } + for x in game.get_players(False) + ], can_start=game.can_start(pm.get_my_player()), - game_link='?k=' + game.model.uniqueCode, + game_link="?k=" + game.model.uniqueCode, ) -@wrapped_socketio('waitroom', 'waitroom') +@wrapped_socketio("waitroom", "waitroom") def waitroom(): result = get_state() if result.game_name is not None: join_room(result.game_name) return result -@wrapped_socketio('start', 'start') + +@wrapped_socketio("start", "start") def start_game(): gm = get_game_manager() pm = get_player_manager() @@ -63,10 +70,13 @@ def start_game(): if not game.is_waitroom(): raise UserError("Игра не может быть начата без комнаты ожидания!") if not game.can_start(pm.get_my_player()): - raise HackAttemptError("Попытка начать игру игроком, который не может этого делать!") + raise HackAttemptError( + "Попытка начать игру игроком, который не может этого делать!" + ) game.start() return True + @Memoize def get_game_manager(): return GameManager(db) @@ -77,13 +87,13 @@ def get_player_manager(): return PlayerManager(db) -@mod_game_wr.route('/waitroom') +@mod_game_wr.route("/waitroom") def wr(): set_current_player() try: game = get_game_manager().get_my_game() player = get_player_manager().get_my_player() except UserError: - return redirect(url_for('gameselect.index')) - #TODO move ExitForm to different file - return render_template('waitroom.html', form=ExitForm()) + return redirect(url_for("gameselect.index")) + # TODO move ExitForm to different file + return render_template("waitroom.html", form=ExitForm()) diff --git a/mod_gameselect/controller.py b/mod_gameselect/controller.py index 8c5fa5f..ad35548 100644 --- a/mod_gameselect/controller.py +++ b/mod_gameselect/controller.py @@ -1,5 +1,4 @@ -from flask import request, render_template, \ - flash, g, session, redirect, url_for +from flask import request, render_template, flash, g, session, redirect, url_for from flask import Blueprint from sqlalchemy.exc import IntegrityError @@ -27,7 +26,7 @@ from utils.g_helper import set_current_player from utils.memoize import Memoize -mod_gameselect = Blueprint('gameselect', __name__) +mod_gameselect = Blueprint("gameselect", __name__) @Memoize @@ -76,30 +75,41 @@ def on_join(form): SessionHelper.set(SessionKeys.GAME_KEY, form.game_key.data) SessionHelper.set(SessionKeys.PLAYER_ID, player.model.id) - return redirect('/waitroom') + return redirect("/waitroom") def on_exit(form): pm = get_player_manager() player = pm.get_my_player() if player is None: - return redirect('/') + return redirect("/") game = get_game_manager().get_my_game() game.leave_player(player) db.session.commit() game.notify() - if first_or_none(filter(lambda x: not x.model.hasLeft and x.model.isOnline, game.get_players(False))) is None: + if ( + first_or_none( + filter( + lambda x: not x.model.hasLeft and x.model.isOnline, + game.get_players(False), + ) + ) + is None + ): get_game_manager().delete_game(game) SessionHelper.delete(SessionKeys.GAME_KEY) SessionHelper.delete(SessionKeys.PLAYER_ID) - return redirect('/') + return redirect("/") def rejoin() -> bool: player = get_player_manager().get_my_player() try: - if player is not None and player.model.game.id == get_game_manager().get_my_game().model.id: + if ( + player is not None + and player.model.game.id == get_game_manager().get_my_game().model.id + ): print("this player is already in this game with name", player.model.name) return True except BaseException as e: @@ -114,7 +124,7 @@ def on_create(form): 0: EndGameDeaths.NotEnabled, 1: EndGameDeaths.NotEnabled, 2: EndGameDeaths.OneDead, - 3: EndGameDeaths.AllButOneDead + 3: EndGameDeaths.AllButOneDead, } def_card_deal_map = { 0: DefCardDeal.DealFixed, @@ -123,11 +133,20 @@ def on_create(form): 3: DefCardDeal.DealAverageSpend, 4: DefCardDeal.RemainingPlusFixed, } - params = GameParams(form.b_falsics.data, form.b_defence.data, - form.b_offence.data, form.acc_prob.data / 100.0, - endgame_map[form.endgame.data], form.deck_size.data, form.num_rounds.data, - form.only_admin_starts.data, form.can_attack_anyone.data, def_card_deal_map[form.def_card_deal.data], - form.def_card_deal_size.data, form.hardcore_mode.data) + params = GameParams( + form.b_falsics.data, + form.b_defence.data, + form.b_offence.data, + form.acc_prob.data / 100.0, + endgame_map[form.endgame.data], + form.deck_size.data, + form.num_rounds.data, + form.only_admin_starts.data, + form.can_attack_anyone.data, + def_card_deal_map[form.def_card_deal.data], + form.def_card_deal_size.data, + form.hardcore_mode.data, + ) game = get_game_manager().create_game(params) # TODO: wipe the old player, if set in session player = get_player_manager().create_player(form.player_name.data, game) @@ -135,18 +154,18 @@ def on_create(form): db.session.commit() SessionHelper.set(SessionKeys.GAME_KEY, game.model.uniqueCode) SessionHelper.set(SessionKeys.PLAYER_ID, player.model.id) - return redirect('/waitroom') + return redirect("/waitroom") -@mod_gameselect.route('/logout', methods=['POST']) +@mod_gameselect.route("/logout", methods=["POST"]) def logout(): exit_form = ExitForm() if exit_form.validate_on_submit(): return on_exit(exit_form) - return redirect('/') + return redirect("/") -@mod_gameselect.route('/', methods=['GET', 'POST']) +@mod_gameselect.route("/", methods=["GET", "POST"]) def index(): set_current_player() join_form = JoinForm() @@ -168,12 +187,12 @@ def index(): g.error_game = e.message else: raise - return render_template('index.html', form=form) - game_key = SessionHelper.get(SessionKeys.GAME_KEY, '') - if 'k' in request.args: - if not request.args['k'].isalpha(): + return render_template("index.html", form=form) + game_key = SessionHelper.get(SessionKeys.GAME_KEY, "") + if "k" in request.args: + if not request.args["k"].isalpha(): raise HackAttemptError("Некорректный ключ игры") - game_key = request.args['k'] + game_key = request.args["k"] g.game_key = game_key return render_template("index.html", form=create_form) diff --git a/mod_test/test.py b/mod_test/test.py index 7b25f4b..ba7b7ed 100644 --- a/mod_test/test.py +++ b/mod_test/test.py @@ -1,7 +1,8 @@ from flask import Blueprint, render_template -mod_test = Blueprint('test', __name__) +mod_test = Blueprint("test", __name__) + @mod_test.route("/") def index(): - return render_template("test.html") \ No newline at end of file + return render_template("test.html") diff --git a/session.py b/session.py index 0770bbc..af1f6a5 100644 --- a/session.py +++ b/session.py @@ -3,8 +3,8 @@ class SessionKeys: - PLAYER_ID = 'player' - GAME_KEY = 'game' + PLAYER_ID = "player" + GAME_KEY = "game" class SessionHelper: diff --git a/utils/conversion.py b/utils/conversion.py index 51aa074..4ff63cc 100644 --- a/utils/conversion.py +++ b/utils/conversion.py @@ -7,7 +7,8 @@ def map_opt(callable, iterable): def first_or_none(iterable): return next(iter(iterable), None) + def replace_none(value, default): if value is None: return default - return value \ No newline at end of file + return value diff --git a/utils/memoize.py b/utils/memoize.py index 3a4247b..20636d4 100644 --- a/utils/memoize.py +++ b/utils/memoize.py @@ -1,5 +1,4 @@ class Memoize: - def __init__(self, fn): self.fn = fn self.memo = {} diff --git a/utils/socketio_helper.py b/utils/socketio_helper.py index 7bd5958..ce0493e 100644 --- a/utils/socketio_helper.py +++ b/utils/socketio_helper.py @@ -40,7 +40,7 @@ def thehandler(*args): if response_message is not None: emit(response_message, rv) else: - if not rv['ok']: + if not rv["ok"]: print("NOT OK Response:", rv.message) return socketio.on(message)(thehandler) From dfd49a443a067b7511ec5391432c14c311e94115 Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 20:09:04 +0100 Subject: [PATCH 04/10] Disable flake8, enable mypy --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a390845..679997a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,5 +25,5 @@ jobs: github_token: ${{ secrets.github_token }} # Enable linters black: true - flake8: true + mypy: true auto_fix: true From 29be2ee165985f4c398ff9a63072e882cb1e3e2b Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 20:10:15 +0100 Subject: [PATCH 05/10] Actually install mypy before using it --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 679997a..7085a23 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: python-version: 3.8 - name: Install Python dependencies - run: pip install black flake8 + run: pip install black mypy - name: Run linters uses: wearerequired/lint-action@v1 From e67e5e4c0d850f3fddaffb5a51057f5bacd9ee00 Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 20:16:22 +0100 Subject: [PATCH 06/10] Install requirements --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7085a23..62e4a7c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: python-version: 3.8 - name: Install Python dependencies - run: pip install black mypy + run: pip install black mypy && ls && pip install -r requirements.txt - name: Run linters uses: wearerequired/lint-action@v1 From 89eec29a16088c85da4f97aa9c114a1f1a86b4ab Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 20:24:02 +0100 Subject: [PATCH 07/10] Make everything packages --- Exceptions/__init__.py | 0 db_models/__init__.py | 0 logic/__init__.py | 0 mod_game/__init__.py | 0 mod_test/__init__.py | 0 utils/__init__.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Exceptions/__init__.py create mode 100644 db_models/__init__.py create mode 100644 logic/__init__.py create mode 100644 mod_game/__init__.py create mode 100644 mod_test/__init__.py create mode 100644 utils/__init__.py diff --git a/Exceptions/__init__.py b/Exceptions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/db_models/__init__.py b/db_models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/logic/__init__.py b/logic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mod_game/__init__.py b/mod_game/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mod_test/__init__.py b/mod_test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 From a03630bdf26513b665fc0ba4b992d3ceda9f8c11 Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 20:28:06 +0100 Subject: [PATCH 08/10] Ignore unknown mypy types --- .github/workflows/lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 62e4a7c..2479659 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,3 +27,4 @@ jobs: black: true mypy: true auto_fix: true + mypy_args: "--ignore-missing-imports" From 535030212864b8a47e2540aa1409617d1cc76258 Mon Sep 17 00:00:00 2001 From: gurux13 Date: Wed, 14 Oct 2020 20:40:57 +0100 Subject: [PATCH 09/10] Fix some lint issues --- logic/battle_logic.py | 3 ++- logic/card_logic.py | 4 ++-- logic/game_logic.py | 6 +++--- logic/game_manager.py | 5 +++-- logic/player_logic.py | 3 +-- mod_game/game_state.py | 8 ++++---- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/logic/battle_logic.py b/logic/battle_logic.py index bb15a62..0948b6f 100644 --- a/logic/battle_logic.py +++ b/logic/battle_logic.py @@ -1,4 +1,5 @@ import json +from typing import Optional from flask_sqlalchemy import SQLAlchemy @@ -32,7 +33,7 @@ def add_defensive_card(self, card: CardLogic): lst.append(card.model.id) self.model.defensiveCards = json.dumps(lst) - def get_curdamage(self) -> int: + def get_curdamage(self) -> Optional[int]: if self.model.offensiveCard is None: return None if self.model.defensiveCards is None: diff --git a/logic/card_logic.py b/logic/card_logic.py index f3d07a4..5cc0f4b 100644 --- a/logic/card_logic.py +++ b/logic/card_logic.py @@ -1,7 +1,7 @@ from flask_sqlalchemy import SQLAlchemy from db_models.card import Card -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional from db_models.cardtype import CardTypeEnum from utils.conversion import first_or_none @@ -17,7 +17,7 @@ def __init__(self, db: SQLAlchemy, model: Card, owner: "PlayerLogic" = None): self.model = model self.owner = owner - def get_defence_from(self, offenciveCard: Card) -> int: + def get_defence_from(self, offenciveCard: Card) -> Optional[int]: if self.model.type.enumType != CardTypeEnum.DEFENCE: return None return first_or_none( diff --git a/logic/game_logic.py b/logic/game_logic.py index fb16fa6..ad157bd 100644 --- a/logic/game_logic.py +++ b/logic/game_logic.py @@ -39,7 +39,7 @@ def __init__(self, db: SQLAlchemy, model: Game): self.params = GameParams.from_db(model.params) self.card_manager = CardManager(self.db) self.player_manager = PlayerManager(self.db) - self.cur_round: GameRound = next(iter(self.model.rounds), None) + self.cur_round: Optional[GameRound] = next(iter(self.model.rounds), None) self.is_dirty_ = False def is_dirty(self): @@ -105,7 +105,7 @@ def join_player(self, player: PlayerLogic, is_admin: bool) -> None: self.set_dirty() def get_players(self, only_live): - all_players = [PlayerLogic(self.db, x, self) for x in self.model.players] + all_players = [PlayerLogic(self.db, x) for x in self.model.players] if only_live: return [p for p in all_players if p.is_alive()] else: @@ -180,7 +180,7 @@ def start_battle(self, offendingPlayer: PlayerLogic): if not self.params.can_attack_anyone: self.attack( offendingPlayer, - PlayerLogic(self.db, self.get_neighbour(offendingPlayer), game=self), + PlayerLogic(self.db, self.get_neighbour(offendingPlayer)) ) return new_battle diff --git a/logic/game_manager.py b/logic/game_manager.py index 7785770..5ef6969 100644 --- a/logic/game_manager.py +++ b/logic/game_manager.py @@ -1,4 +1,5 @@ from datetime import datetime +from typing import Optional from flask_sqlalchemy import SQLAlchemy @@ -60,7 +61,7 @@ def delete_game(self, game: GameLogic): UserError.ErrorType.INVALID_GAME_DELETION, ) - def get_game(self, game_key: str, optional=False) -> GameLogic: + def get_game(self, game_key: str, optional=False) -> Optional[GameLogic]: game = Game.query.filter_by(uniqueCode=game_key).first() if game is None and not optional: raise UserError( @@ -71,5 +72,5 @@ def get_game(self, game_key: str, optional=False) -> GameLogic: return None return GameLogic(self.db, game) - def get_my_game(self, optional=False) -> GameLogic: + def get_my_game(self, optional=False) -> Optional[GameLogic]: return self.get_game(SessionHelper.get(SessionKeys.GAME_KEY), optional) diff --git a/logic/player_logic.py b/logic/player_logic.py index fb950d2..b2e5455 100644 --- a/logic/player_logic.py +++ b/logic/player_logic.py @@ -11,10 +11,9 @@ class PlayerLogic: - def __init__(self, db: SQLAlchemy, model: Player, game: "GameLogic" = None): + def __init__(self, db: SQLAlchemy, model: Player): self.db = db self.model = model - self.game = game self.hand: List[int] = ( [] if self.model.hand is None else json.loads(self.model.hand) ) diff --git a/mod_game/game_state.py b/mod_game/game_state.py index 8da93b8..0c56e23 100644 --- a/mod_game/game_state.py +++ b/mod_game/game_state.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import List +from typing import List, Optional from dataclasses import dataclass @@ -37,9 +37,9 @@ class UiCard: text: str type: UiCardType damage: int - def_against: List[CardPairing] - off_against: List[CardPairing] - dealt_by_player: int + def_against: Optional[List[CardPairing]] + off_against: Optional[List[CardPairing]] + dealt_by_player: Optional[int] can_play: bool = None pop_up_text: str = None pop_up_url: str = None From 1086ff5cddeeee66d6d5547c9a5566bd7427d964 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Wed, 14 Oct 2020 19:42:04 +0000 Subject: [PATCH 10/10] Fix code style issues with Black --- logic/game_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/game_logic.py b/logic/game_logic.py index ad157bd..a0eafbd 100644 --- a/logic/game_logic.py +++ b/logic/game_logic.py @@ -180,7 +180,7 @@ def start_battle(self, offendingPlayer: PlayerLogic): if not self.params.can_attack_anyone: self.attack( offendingPlayer, - PlayerLogic(self.db, self.get_neighbour(offendingPlayer)) + PlayerLogic(self.db, self.get_neighbour(offendingPlayer)), ) return new_battle