Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from app.models.bot_account import BotAccount
from app.models.bot_link_code import BotLinkCode
from app.models.finding import Finding
from app.models.project import Project
from app.models.scan import Scan
from app.models.user import User

__all__: list[str] = ["Finding", "Project", "Scan", "User"]
__all__: list[str] = ["BotAccount", "BotLinkCode", "Finding", "Project", "Scan", "User"]
18 changes: 18 additions & 0 deletions app/models/bot_account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from app.extensions import db
from app.utils import utcnow


class BotAccount(db.Model):
__tablename__ = "bot_accounts"

id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(
db.Integer, db.ForeignKey("users.id"), nullable=False, index=True
)
platform = db.Column(db.String(16), nullable=False)
external_id = db.Column(db.String(16), nullable=False)
created_at = db.Column(db.DateTime(timezone=True), default=utcnow, nullable=False)

__table_args__ = (db.UniqueConstraint("platform", "external_id", "user_id"),)

user = db.relationship("User", back_populates="bot_accounts")
17 changes: 17 additions & 0 deletions app/models/bot_link_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from app.extensions import db
from app.utils import utcnow


class BotLinkCode(db.Model):
__tablename__ = "bot_link_codes"

id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(
db.Integer, db.ForeignKey("users.id"), nullable=False, index=True
)
code_hash = db.Column(db.String(64), unique=True, nullable=False)
expires_at = db.Column(db.DateTime(timezone=True), nullable=False)
used_at = db.Column(db.DateTime(timezone=True), nullable=True)
created_at = db.Column(db.DateTime(timezone=True), default=utcnow, nullable=False)

user = db.relationship("User", back_populates="bot_link_codes")
6 changes: 6 additions & 0 deletions app/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ class User(UserMixin, db.Model):
projects = db.relationship(
"Project", back_populates="owner", cascade="all, delete-orphan"
)
bot_accounts = db.relationship(
"BotAccount", back_populates="user", cascade="all, delete-orphan"
)
bot_link_codes = db.relationship(
"BotLinkCode", back_populates="user", cascade="all, delete-orphan"
)

def __repr__(self) -> str:
return f"<User {self.id}>"
Expand Down
74 changes: 74 additions & 0 deletions migrations/versions/eb5052fa0d5c_bot_accounts_and_link_codes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""bot accounts and link codes

Revision ID: eb5052fa0d5c
Revises: 478f787d33bd
Create Date: 2026-10-01 23:24:27.586102

"""

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "eb5052fa0d5c"
down_revision = "478f787d33bd"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"bot_accounts",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column("platform", sa.String(length=16), nullable=False),
sa.Column("external_id", sa.String(length=16), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("platform", "external_id", "user_id"),
)
with op.batch_alter_table("bot_accounts", schema=None) as batch_op:
batch_op.create_index(
batch_op.f("ix_bot_accounts_user_id"), ["user_id"], unique=False
)

op.create_table(
"bot_link_codes",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column("code_hash", sa.String(length=64), nullable=False),
sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("used_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("code_hash"),
)
with op.batch_alter_table("bot_link_codes", schema=None) as batch_op:
batch_op.create_index(
batch_op.f("ix_bot_link_codes_user_id"), ["user_id"], unique=False
)

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("bot_link_codes", schema=None) as batch_op:
batch_op.drop_index(batch_op.f("ix_bot_link_codes_user_id"))

op.drop_table("bot_link_codes")
with op.batch_alter_table("bot_accounts", schema=None) as batch_op:
batch_op.drop_index(batch_op.f("ix_bot_accounts_user_id"))

op.drop_table("bot_accounts")
# ### end Alembic commands ###
Loading