diff --git a/import.py b/import.py new file mode 100644 index 0000000..eb3f705 --- /dev/null +++ b/import.py @@ -0,0 +1,16 @@ +# Load .env file +from dotenv import load_dotenv +load_dotenv() + +import argparse + +from sqlalchemy.orm import sessionmaker + +from truthinquiry.ext.database.sa import engine +from truthinquiry.ext.database.models import * + +Session = sessionmaker(bind=engine) +session = Session() + +results = session.query(Npc).all() +print(results) diff --git a/truthinquiry/__init__.py b/truthinquiry/__init__.py index 61abb15..b92a387 100644 --- a/truthinquiry/__init__.py +++ b/truthinquiry/__init__.py @@ -6,14 +6,14 @@ from flask_sqlalchemy import SQLAlchemy from truthinquiry.app import TruthInquiryApp -from truthinquiry.ext.database import db +from truthinquiry.ext.database import fsa from truthinquiry.ext.socketio import socket_io from truthinquiry.ext.discord_bot import discord_bot from truthinquiry.routes import routes_api, routes_ui, routes_socketio, handlers def register_extensions(app): - db.init_app(app) + fsa.setup_app_db(app) socket_io.init_app(app) diff --git a/truthinquiry/ext/database/__init__.py b/truthinquiry/ext/database/__init__.py deleted file mode 100644 index 03a4915..0000000 --- a/truthinquiry/ext/database/__init__.py +++ /dev/null @@ -1,167 +0,0 @@ -import os -import random - -from sqlalchemy import engine as eg -from flask_sqlalchemy import SQLAlchemy - -class Database(SQLAlchemy): - def __init__(self): - super().__init__() - - def init_app(self, app): - - db_url = eg.URL.create( - "mariadb+pymysql", - username=os.getenv("DB_USER"), - password=os.getenv("DB_PASSWORD"), - host=os.getenv("DB_HOST"), - port=os.getenv("DB_PORT"), - database=os.getenv("DB_DBNAME") - ) - app.config["SQLALCHEMY_DATABASE_URI"] = db_url - - super().init_app(app) - - with app.app_context(): - self.create_all() - -db = Database() - -class Locale(db.Model): - """ - Stores the different texts needed by the other tables in multiple languages - """ - - __tablename__ = 'T_LOCALE' - TEXT_ID = db.Column(db.Integer, primary_key=True, comment="ID of this text (the other tables references to this with *_LID columns)") - LANG = db.Column(db.VARCHAR(2), primary_key=True, comment="lang ID of the text value in this row, e.g FR, EN, ES") - TEXT = db.Column(db.Text, comment="Actual text stored for that text ID and lang") - - def __init__(self, TEXT_ID, LANG, TEXT): - self.TEXT_ID = TEXT_ID - self.LANG = LANG - self.TEXT = TEXT - - def __str__(self): - return f"{self.TEXT_ID} {self.LANG} {self.TEXT}" - - -class Place(db.Model): - """ - Store litteral places, could be a room in the manor or near it - """ - - __tablename__ = 'T_PLACE' - PLACE_ID = db.Column(db.Integer, primary_key=True, comment="ID of this place") - NAME_LID = db.Column(db.Integer, db.ForeignKey("T_LOCALE.TEXT_ID"), comment="Place name") - LOCALE = db.relationship("Locale") - - def __init__(self, PLACE_ID, NAME_LID): - self.PLACE_ID = PLACE_ID - self.NAME_LID = NAME_LID - - def __str__(self): - return f"{self.PLACE_ID} {self.NAME_LID}" - - -class Question(db.Model): - """ - Stores questions asked by players - """ - - __tablename__ = "T_QUESTION" - QUESTION_ID = db.Column(db.Integer, primary_key=True, comment="ID of this question") - QUESTION_TYPE = db.Column(db.Integer, comment="Question type ID, e.g 'when..', 'where..'") - TEXT_LID = db.Column(db.Integer, db.ForeignKey("T_LOCALE.TEXT_ID"), comment="Question text") - LOCALE = db.relationship("Locale") - - def __init__(self, QUESTION_ID, QUESTION_TYPE, TEXT_LID): - self.QUESTION_ID = QUESTION_ID - self.QUESTION_TYPE = QUESTION_TYPE - self.TEXT_LID = TEXT_LID - - def __str__(self): - return f"{self.QUESTION_ID} {self.QUESTION_TYPE} {self.TEXT_LID}" - - -class Answer(db.Model): - """ - Stores answers given by NPCs - They are relative to the question type ID, and NPC ID - """ - - __tablename__ = "T_ANSWER" - ANSWER_ID = db.Column(db.Integer, primary_key=True, comment="ID of this answer") - QA_TYPE = db.Column(db.Integer, comment="Question type ID") - NPC_ID = db.Column(db.Integer, db.ForeignKey("T_NPC.NPC_ID"), comment="ID of the NPC that will say this answer") - TEXT_LID = db.Column(db.Integer, db.ForeignKey("T_LOCALE.TEXT_ID"), comment="Text of the answer") - LOCALE = db.relationship("Locale") - NPC = db.relationship("Npc") - - def __init__(self, ANSWER_ID, QA_TYPE, NPC_ID, TEXT_LID): - self.ANSWER_ID = ANSWER_ID - self.QA_TYPE = QA_TYPE - self.NPC_ID = NPC_ID - self.TEXT_LID = TEXT_LID - - def __str__(self): - return f"{self.ANSWER_ID} {self.QA_TYPE} {self.NPC_ID} {self.TEXT_LID}" - - -class Npc(db.Model): - """ - Store Npcs - """ - - __tablename__ = "T_NPC" - NPC_ID = db.Column(db.Integer, primary_key=True, comment="ID of this Npc") - NAME_LID = db.Column(db.Integer, db.ForeignKey("T_LOCALE.TEXT_ID"), comment="Name of this Npc") - LOCALE = db.relationship("Locale") - - def __init__(self, NPC_ID, NAME_LID): - self.NPC_ID = NPC_ID - self.NAME_LID = NAME_LID - - def __str__(self) -> str: - return f"{self.NPC_ID} {self.NAME_LID}" - - -class Trait(db.Model): - """ - Store reaction types, e.g 'happy', 'sad', without relation with NPCs - """ - __tablename__ = "T_TRAIT" - TRAIT_ID = db.Column(db.Integer, primary_key=True, comment="ID of this trait") - NAME_LID = db.Column(db.Integer, db.ForeignKey("T_LOCALE.TEXT_ID"), comment="Name of this trait") - DESC_LID = db.Column(db.Integer, db.ForeignKey("T_LOCALE.TEXT_ID"), comment="Description of this trait") - - Name = db.relationship("Locale",foreign_keys=[NAME_LID]) - Desc = db.relationship("Locale",foreign_keys=[DESC_LID]) - - - def __init__(self, TRAIT_ID, NAME_LID): - self.TRAIT_ID = TRAIT_ID - self.NAME_LID = NAME_LID - - def __str__(self) -> str: - return f"{self.TRAIT_ID} {self.NAME_LID}" - - -class Reaction(db.Model): - """ - Relation between a NPC and a Trait - """ - __tablename__ = "T_REACTION" - REACTION_ID = db.Column(db.Integer, primary_key=True, comment="ID of this reaction") - NPC_ID = db.Column(db.Integer, db.ForeignKey("T_NPC.NPC_ID"), primary_key=True, comment="Name of the NPC that will have this reaction") - TRAIT_ID = db.Column(db.Integer, db.ForeignKey("T_TRAIT.TRAIT_ID"), primary_key=True, comment="ID of the trait of this reaction") - NPC = db.relationship("Npc") - TRAIT = db.relationship("Trait") - - def __init__(self, REACTION_ID, NPC_ID, TRAIT_ID): - self.REACTION_ID = REACTION_ID - self.NPC_ID = NPC_ID - self.TRAIT_ID = TRAIT_ID - - def __str__(self) -> str: - return f"{self.REACTION_ID} {self.NPC_ID} {self.TRAIT_ID}" diff --git a/truthinquiry/ext/database/db_url.py b/truthinquiry/ext/database/db_url.py new file mode 100644 index 0000000..9befe11 --- /dev/null +++ b/truthinquiry/ext/database/db_url.py @@ -0,0 +1,13 @@ +import os + +from sqlalchemy import engine as eg + +def get_db_url(): + return eg.URL.create( + "mariadb+pymysql", + username=os.getenv("DB_USER"), + password=os.getenv("DB_PASSWORD"), + host=os.getenv("DB_HOST"), + port=os.getenv("DB_PORT"), + database=os.getenv("DB_DBNAME") + ) \ No newline at end of file diff --git a/truthinquiry/ext/database/dbutils.py b/truthinquiry/ext/database/dbutils.py index 8530bbd..0bafc84 100644 --- a/truthinquiry/ext/database/dbutils.py +++ b/truthinquiry/ext/database/dbutils.py @@ -1,4 +1,7 @@ -from truthinquiry.ext.database import * +import random + +from truthinquiry.ext.database.models import * +from truthinquiry.ext.database.fsa import db def get_text_from_lid(lang: str, lid: int) -> str: """ diff --git a/truthinquiry/ext/database/fsa.py b/truthinquiry/ext/database/fsa.py new file mode 100644 index 0000000..a8895a3 --- /dev/null +++ b/truthinquiry/ext/database/fsa.py @@ -0,0 +1,11 @@ +from flask_sqlalchemy import SQLAlchemy + +from truthinquiry.ext.database.models import Base +from truthinquiry.ext.database.db_url import get_db_url + +db = SQLAlchemy(model_class=Base) + +def setup_app_db(app): + app.config['SQLALCHEMY_DATABASE_URI'] = get_db_url() + app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {"pool_pre_ping": True} # handle disconnections + db.init_app(app) \ No newline at end of file diff --git a/truthinquiry/ext/database/models.py b/truthinquiry/ext/database/models.py new file mode 100644 index 0000000..e030672 --- /dev/null +++ b/truthinquiry/ext/database/models.py @@ -0,0 +1,144 @@ +from sqlalchemy import Column, Integer, VARCHAR, Text, ForeignKey +from sqlalchemy.orm import relationship +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + +class Locale(Base): + """ + Stores the different texts needed by the other tables in multiple languages + """ + + __tablename__ = 'T_LOCALE' + TEXT_ID = Column(Integer, primary_key=True, comment="ID of this text (the other tables references to this with *_LID columns)") + LANG = Column(VARCHAR(2), primary_key=True, comment="lang ID of the text value in this row, e.g FR, EN, ES") + TEXT = Column(Text, comment="Actual text stored for that text ID and lang") + + def __init__(self, TEXT_ID, LANG, TEXT): + self.TEXT_ID = TEXT_ID + self.LANG = LANG + self.TEXT = TEXT + + def __str__(self): + return f"{self.TEXT_ID} {self.LANG} {self.TEXT}" + + +class Place(Base): + """ + Store litteral places, could be a room in the manor or near it + """ + + __tablename__ = 'T_PLACE' + PLACE_ID = Column(Integer, primary_key=True, comment="ID of this place") + NAME_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"), comment="Place name") + LOCALE = relationship("Locale") + + def __init__(self, PLACE_ID, NAME_LID): + self.PLACE_ID = PLACE_ID + self.NAME_LID = NAME_LID + + def __str__(self): + return f"{self.PLACE_ID} {self.NAME_LID}" + + +class Question(Base): + """ + Stores questions asked by players + """ + + __tablename__ = "T_QUESTION" + QUESTION_ID = Column(Integer, primary_key=True, comment="ID of this question") + QUESTION_TYPE = Column(Integer, comment="Question type ID, e.g 'when..', 'where..'") + TEXT_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"), comment="Question text") + LOCALE = relationship("Locale") + + def __init__(self, QUESTION_ID, QUESTION_TYPE, TEXT_LID): + self.QUESTION_ID = QUESTION_ID + self.QUESTION_TYPE = QUESTION_TYPE + self.TEXT_LID = TEXT_LID + + def __str__(self): + return f"{self.QUESTION_ID} {self.QUESTION_TYPE} {self.TEXT_LID}" + + +class Answer(Base): + """ + Stores answers given by NPCs + They are relative to the question type ID, and NPC ID + """ + + __tablename__ = "T_ANSWER" + ANSWER_ID = Column(Integer, primary_key=True, comment="ID of this answer") + QA_TYPE = Column(Integer, comment="Question type ID") + NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"), comment="ID of the NPC that will say this answer") + TEXT_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"), comment="Text of the answer") + LOCALE = relationship("Locale") + NPC = relationship("Npc") + + def __init__(self, ANSWER_ID, QA_TYPE, NPC_ID, TEXT_LID): + self.ANSWER_ID = ANSWER_ID + self.QA_TYPE = QA_TYPE + self.NPC_ID = NPC_ID + self.TEXT_LID = TEXT_LID + + def __str__(self): + return f"{self.ANSWER_ID} {self.QA_TYPE} {self.NPC_ID} {self.TEXT_LID}" + + +class Npc(Base): + """ + Store Npcs + """ + + __tablename__ = "T_NPC" + NPC_ID = Column(Integer, primary_key=True, comment="ID of this Npc") + NAME_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"), comment="Name of this Npc") + LOCALE = relationship("Locale") + + def __init__(self, NPC_ID, NAME_LID): + self.NPC_ID = NPC_ID + self.NAME_LID = NAME_LID + + def __str__(self) -> str: + return f"{self.NPC_ID} {self.NAME_LID}" + + +class Trait(Base): + """ + Store reaction types, e.g 'happy', 'sad', without relation with NPCs + """ + __tablename__ = "T_TRAIT" + TRAIT_ID = Column(Integer, primary_key=True, comment="ID of this trait") + NAME_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"), comment="Name of this trait") + DESC_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"), comment="Description of this trait") + + Name = relationship("Locale",foreign_keys=[NAME_LID]) + Desc = relationship("Locale",foreign_keys=[DESC_LID]) + + + def __init__(self, TRAIT_ID, NAME_LID): + self.TRAIT_ID = TRAIT_ID + self.NAME_LID = NAME_LID + + def __str__(self) -> str: + return f"{self.TRAIT_ID} {self.NAME_LID}" + + +class Reaction(Base): + """ + Relation between a NPC and a Trait + """ + __tablename__ = "T_REACTION" + REACTION_ID = Column(Integer, primary_key=True, comment="ID of this reaction") + NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"), primary_key=True, comment="Name of the NPC that will have this reaction") + TRAIT_ID = Column(Integer, ForeignKey("T_TRAIT.TRAIT_ID"), primary_key=True, comment="ID of the trait of this reaction") + NPC = relationship("Npc") + TRAIT = relationship("Trait") + + def __init__(self, REACTION_ID, NPC_ID, TRAIT_ID): + self.REACTION_ID = REACTION_ID + self.NPC_ID = NPC_ID + self.TRAIT_ID = TRAIT_ID + + def __str__(self) -> str: + return f"{self.REACTION_ID} {self.NPC_ID} {self.TRAIT_ID}" diff --git a/truthinquiry/ext/database/sa.py b/truthinquiry/ext/database/sa.py new file mode 100644 index 0000000..c9c9ab4 --- /dev/null +++ b/truthinquiry/ext/database/sa.py @@ -0,0 +1,6 @@ +from sqlalchemy import create_engine + +from truthinquiry.ext.database.models import Base +from truthinquiry.ext.database.db_url import get_db_url + +engine = create_engine(get_db_url()) diff --git a/truthinquiry/logic/game_logic.py b/truthinquiry/logic/game_logic.py index 1967848..9e7d773 100644 --- a/truthinquiry/logic/game_logic.py +++ b/truthinquiry/logic/game_logic.py @@ -2,7 +2,7 @@ import string import random from typing import Union -from truthinquiry.ext.database import * +from truthinquiry.ext.database.models import * from truthinquiry.ext.database import dbutils games_list = {}