init CTFd source
This commit is contained in:
47
migrations/versions/0366ba6575ca_add_table_for_comments.py
Normal file
47
migrations/versions/0366ba6575ca_add_table_for_comments.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""Add table for comments
|
||||
|
||||
Revision ID: 0366ba6575ca
|
||||
Revises: 1093835a1051
|
||||
Create Date: 2020-08-14 00:46:54.161120
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "0366ba6575ca"
|
||||
down_revision = "1093835a1051"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"comments",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("content", sa.Text(), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.Column("author_id", sa.Integer(), nullable=True),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.Column("page_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["author_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(
|
||||
["challenge_id"], ["challenges.id"], ondelete="CASCADE"
|
||||
),
|
||||
sa.ForeignKeyConstraint(["page_id"], ["pages.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("comments")
|
||||
# ### end Alembic commands ###
|
||||
28
migrations/versions/07dfbe5e1edc_add_format_to_pages.py
Normal file
28
migrations/versions/07dfbe5e1edc_add_format_to_pages.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""Add format to Pages
|
||||
|
||||
Revision ID: 07dfbe5e1edc
|
||||
Revises: 75e8ab9a0014
|
||||
Create Date: 2021-06-15 19:57:37.410152
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "07dfbe5e1edc"
|
||||
down_revision = "75e8ab9a0014"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("pages", sa.Column("format", sa.String(length=80), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("pages", "format")
|
||||
# ### end Alembic commands ###
|
||||
34
migrations/versions/080d29b15cd3_add_tokens_table.py
Normal file
34
migrations/versions/080d29b15cd3_add_tokens_table.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""Add Tokens table to store user access tokens
|
||||
|
||||
Revision ID: 080d29b15cd3
|
||||
Revises: b295b033364d
|
||||
Create Date: 2019-11-03 18:21:04.827015
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "080d29b15cd3"
|
||||
down_revision = "b295b033364d"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
"tokens",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("type", sa.String(length=32), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("created", sa.DateTime(), nullable=True),
|
||||
sa.Column("expiration", sa.DateTime(), nullable=True),
|
||||
sa.Column("value", sa.String(length=128), nullable=True),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("value"),
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table("tokens")
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Add language column to Users table
|
||||
|
||||
Revision ID: 0def790057c1
|
||||
Revises: 46a278193a94
|
||||
Create Date: 2023-04-19 00:56:54.592584
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "0def790057c1"
|
||||
down_revision = "46a278193a94"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column("users", sa.Column("language", sa.String(length=32), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("users", "language")
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Add default email templates
|
||||
|
||||
Revision ID: 1093835a1051
|
||||
Revises: a03403986a32
|
||||
Create Date: 2020-02-15 01:32:10.959373
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
from sqlalchemy.sql import column, table
|
||||
|
||||
from CTFd.models import db
|
||||
from CTFd.utils.email import (
|
||||
DEFAULT_PASSWORD_RESET_BODY,
|
||||
DEFAULT_PASSWORD_RESET_SUBJECT,
|
||||
DEFAULT_SUCCESSFUL_REGISTRATION_EMAIL_BODY,
|
||||
DEFAULT_SUCCESSFUL_REGISTRATION_EMAIL_SUBJECT,
|
||||
DEFAULT_USER_CREATION_EMAIL_BODY,
|
||||
DEFAULT_USER_CREATION_EMAIL_SUBJECT,
|
||||
DEFAULT_VERIFICATION_EMAIL_BODY,
|
||||
DEFAULT_VERIFICATION_EMAIL_SUBJECT,
|
||||
)
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "1093835a1051"
|
||||
down_revision = "a03403986a32"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
configs_table = table(
|
||||
"config", column("id", db.Integer), column("key", db.Text), column("value", db.Text)
|
||||
)
|
||||
|
||||
|
||||
def get_config(key):
|
||||
connection = op.get_bind()
|
||||
return connection.execute(
|
||||
configs_table.select().where(configs_table.c.key == key).limit(1)
|
||||
).fetchone()
|
||||
|
||||
|
||||
def set_config(key, value):
|
||||
connection = op.get_bind()
|
||||
connection.execute(configs_table.insert().values(key=key, value=value))
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Only run if this instance already been setup before
|
||||
if bool(get_config("setup")) is True:
|
||||
for k, v in [
|
||||
("password_reset_body", DEFAULT_PASSWORD_RESET_BODY),
|
||||
("password_reset_subject", DEFAULT_PASSWORD_RESET_SUBJECT),
|
||||
(
|
||||
"successful_registration_email_body",
|
||||
DEFAULT_SUCCESSFUL_REGISTRATION_EMAIL_BODY,
|
||||
),
|
||||
(
|
||||
"successful_registration_email_subject",
|
||||
DEFAULT_SUCCESSFUL_REGISTRATION_EMAIL_SUBJECT,
|
||||
),
|
||||
("user_creation_email_body", DEFAULT_USER_CREATION_EMAIL_BODY),
|
||||
("user_creation_email_subject", DEFAULT_USER_CREATION_EMAIL_SUBJECT),
|
||||
("verification_email_body", DEFAULT_VERIFICATION_EMAIL_BODY),
|
||||
("verification_email_subject", DEFAULT_VERIFICATION_EMAIL_SUBJECT),
|
||||
]:
|
||||
if get_config(k) is None:
|
||||
set_config(k, v)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Convert rating values to votes
|
||||
|
||||
Revision ID: 24ad6790bc3c
|
||||
Revises: 55623b100da8
|
||||
Create Date: 2025-09-03 05:19:54.151054
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "24ad6790bc3c"
|
||||
down_revision = "55623b100da8"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Convert 5-star ratings to upvote/downvote system
|
||||
# Values 1-2 become -1 (downvote)
|
||||
# Values 3-5 become 1 (upvote)
|
||||
|
||||
connection = op.get_bind()
|
||||
|
||||
# Update ratings with values 1 or 2 to -1 (downvote)
|
||||
connection.execute(sa.text("UPDATE ratings SET value = -1 WHERE value IN (1, 2)"))
|
||||
|
||||
# Update ratings with values 3, 4, or 5 to 1 (upvote)
|
||||
connection.execute(sa.text("UPDATE ratings SET value = 1 WHERE value IN (3, 4, 5)"))
|
||||
|
||||
|
||||
def downgrade():
|
||||
# This downgrade is not reversible since we lose the original 5-star granularity
|
||||
# We can only convert back to a simplified 5-star system
|
||||
# -1 (downvote) becomes 1 (1 star)
|
||||
# 1 (upvote) becomes 5 (5 stars)
|
||||
|
||||
connection = op.get_bind()
|
||||
|
||||
# Convert downvotes (-1) to 1-star ratings
|
||||
connection.execute(sa.text("UPDATE ratings SET value = 1 WHERE value = -1"))
|
||||
|
||||
# Convert upvotes (1) to 5-star ratings
|
||||
connection.execute(sa.text("UPDATE ratings SET value = 5 WHERE value = 1"))
|
||||
42
migrations/versions/364b4efa1686_add_ratings_table.py
Normal file
42
migrations/versions/364b4efa1686_add_ratings_table.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""Add ratings table
|
||||
|
||||
Revision ID: 364b4efa1686
|
||||
Revises: 662d728ad7da
|
||||
Create Date: 2025-08-17 07:07:41.484323
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "364b4efa1686"
|
||||
down_revision = "662d728ad7da"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"ratings",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("value", sa.Integer(), nullable=True),
|
||||
sa.Column("review", sa.String(length=2000), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["challenge_id"], ["challenges.id"], ondelete="CASCADE"
|
||||
),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("user_id", "challenge_id"),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("ratings")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Enable millisecond precision in MySQL datetime
|
||||
|
||||
Revision ID: 46a278193a94
|
||||
Revises: 4d3c1b59d011
|
||||
Create Date: 2022-11-01 23:27:44.620893
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "46a278193a94"
|
||||
down_revision = "4d3c1b59d011"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
url = str(bind.engine.url)
|
||||
if url.startswith("mysql"):
|
||||
get_columns = "SELECT `TABLE_NAME`, `COLUMN_NAME` FROM `information_schema`.`COLUMNS` WHERE `table_schema`=DATABASE() AND `DATA_TYPE`='datetime' AND `COLUMN_TYPE`='datetime';"
|
||||
conn = op.get_bind()
|
||||
columns = conn.execute(get_columns).fetchall()
|
||||
for table_name, column_name in columns:
|
||||
op.alter_column(
|
||||
table_name=table_name,
|
||||
column_name=column_name,
|
||||
type_=mysql.DATETIME(fsp=6),
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
bind = op.get_bind()
|
||||
url = str(bind.engine.url)
|
||||
if url.startswith("mysql"):
|
||||
get_columns = "SELECT `TABLE_NAME`, `COLUMN_NAME` FROM `information_schema`.`COLUMNS` WHERE `table_schema`=DATABASE() AND `DATA_TYPE`='datetime' AND `COLUMN_TYPE`='datetime(6)';"
|
||||
conn = op.get_bind()
|
||||
columns = conn.execute(get_columns).fetchall()
|
||||
for table_name, column_name in columns:
|
||||
op.alter_column(
|
||||
table_name=table_name,
|
||||
column_name=column_name,
|
||||
type_=mysql.DATETIME(fsp=0),
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Add next_id to Challenges table
|
||||
|
||||
Revision ID: 4d3c1b59d011
|
||||
Revises: 6012fe8de495
|
||||
Create Date: 2022-04-07 03:53:27.554190
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "4d3c1b59d011"
|
||||
down_revision = "6012fe8de495"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("challenges", sa.Column("next_id", sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(
|
||||
None, "challenges", "challenges", ["next_id"], ["id"], ondelete="SET NULL"
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, "challenges", type_="foreignkey")
|
||||
op.drop_column("challenges", "next_id")
|
||||
# ### end Alembic commands ###
|
||||
32
migrations/versions/4e4d5a9ea000_add_type_to_awards.py
Normal file
32
migrations/versions/4e4d5a9ea000_add_type_to_awards.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Add type to awards
|
||||
|
||||
Revision ID: 4e4d5a9ea000
|
||||
Revises: 8369118943a1
|
||||
Create Date: 2019-04-07 19:37:17.872128
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "4e4d5a9ea000"
|
||||
down_revision = "8369118943a1"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column(
|
||||
"awards",
|
||||
sa.Column(
|
||||
"type", sa.String(length=80), nullable=True, server_default="standard"
|
||||
),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("awards", "type")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,24 @@
|
||||
"""Add attribution to Challenges
|
||||
|
||||
Revision ID: 4fe3eeed9a9d
|
||||
Revises: a02c5bf43407
|
||||
Create Date: 2024-09-07 01:02:28.997761
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "4fe3eeed9a9d"
|
||||
down_revision = "a02c5bf43407"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column("challenges", sa.Column("attribution", sa.Text(), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("challenges", "attribution")
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Add target column to Tracking
|
||||
|
||||
Revision ID: 55623b100da8
|
||||
Revises: 5c98d9253f56
|
||||
Create Date: 2025-08-26 23:30:29.170546
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "55623b100da8"
|
||||
down_revision = "5c98d9253f56"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("tracking", sa.Column("target", sa.Integer(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("tracking", "target")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Add sha1sum field to Files
|
||||
|
||||
Revision ID: 5c4996aeb2cb
|
||||
Revises: 9e6f6578ca84
|
||||
Create Date: 2024-01-07 13:09:08.843903
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "5c4996aeb2cb"
|
||||
down_revision = "9e6f6578ca84"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column("files", sa.Column("sha1sum", sa.String(length=40), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("files", "sha1sum")
|
||||
119
migrations/versions/5c98d9253f56_rename_core_beta_to_core.py
Normal file
119
migrations/versions/5c98d9253f56_rename_core_beta_to_core.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""Rename core-beta to core
|
||||
|
||||
Revision ID: 5c98d9253f56
|
||||
Revises: 364b4efa1686
|
||||
Create Date: 2025-08-24 16:23:18.795064
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
from sqlalchemy.sql import column, table
|
||||
|
||||
from CTFd.models import db
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "5c98d9253f56"
|
||||
down_revision = "364b4efa1686"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
configs_table = table(
|
||||
"config", column("id", db.Integer), column("key", db.Text), column("value", db.Text)
|
||||
)
|
||||
|
||||
pages_table = table("pages", column("id", db.Integer), column("content", db.Text))
|
||||
|
||||
|
||||
def upgrade():
|
||||
connection = op.get_bind()
|
||||
|
||||
# Define theme transformations: old_theme -> new_theme
|
||||
theme_transformations = {
|
||||
"core-beta": "core",
|
||||
"hacker-beta-theme": "hacker-theme",
|
||||
"learning-beta-theme": "learning-theme",
|
||||
"learning": "learning-theme",
|
||||
}
|
||||
|
||||
# Find the ctf_theme config entry
|
||||
theme_config = connection.execute(
|
||||
configs_table.select().where(configs_table.c.key == "ctf_theme")
|
||||
).fetchone()
|
||||
|
||||
# Update ctf_theme config
|
||||
if (
|
||||
theme_config
|
||||
and theme_config.value
|
||||
and theme_config.value in theme_transformations
|
||||
):
|
||||
new_value = theme_transformations[theme_config.value]
|
||||
connection.execute(
|
||||
configs_table.update()
|
||||
.where(configs_table.c.id == theme_config.id)
|
||||
.values(value=new_value)
|
||||
)
|
||||
|
||||
# Update pages content for all theme transformations
|
||||
for old_theme, new_theme in theme_transformations.items():
|
||||
old_path = f"themes/{old_theme}/static"
|
||||
new_path = f"themes/{new_theme}/static"
|
||||
|
||||
pages_with_old_theme = connection.execute(
|
||||
pages_table.select().where(pages_table.c.content.like(f"%{old_path}%"))
|
||||
).fetchall()
|
||||
|
||||
for page in pages_with_old_theme:
|
||||
if page.content:
|
||||
new_content = page.content.replace(old_path, new_path)
|
||||
connection.execute(
|
||||
pages_table.update()
|
||||
.where(pages_table.c.id == page.id)
|
||||
.values(content=new_content)
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
connection = op.get_bind()
|
||||
|
||||
# Define reverse theme transformations: new_theme -> old_theme
|
||||
reverse_theme_transformations = {
|
||||
"core": "core-beta",
|
||||
"hacker-theme": "hacker-beta-theme",
|
||||
"learning-theme": "learning-beta-theme",
|
||||
}
|
||||
|
||||
# Find the ctf_theme config entry
|
||||
theme_config = connection.execute(
|
||||
configs_table.select().where(configs_table.c.key == "ctf_theme")
|
||||
).fetchone()
|
||||
|
||||
# Restore ctf_theme config
|
||||
if (
|
||||
theme_config
|
||||
and theme_config.value
|
||||
and theme_config.value in reverse_theme_transformations
|
||||
):
|
||||
new_value = reverse_theme_transformations[theme_config.value]
|
||||
connection.execute(
|
||||
configs_table.update()
|
||||
.where(configs_table.c.id == theme_config.id)
|
||||
.values(value=new_value)
|
||||
)
|
||||
|
||||
# Restore pages content for all theme transformations
|
||||
for new_theme, old_theme in reverse_theme_transformations.items():
|
||||
new_path = f"themes/{new_theme}/static"
|
||||
old_path = f"themes/{old_theme}/static"
|
||||
|
||||
pages_with_new_theme = connection.execute(
|
||||
pages_table.select().where(pages_table.c.content.like(f"%{new_path}%"))
|
||||
).fetchall()
|
||||
|
||||
for page in pages_with_new_theme:
|
||||
if page.content and old_path not in page.content:
|
||||
new_content = page.content.replace(new_path, old_path)
|
||||
connection.execute(
|
||||
pages_table.update()
|
||||
.where(pages_table.c.id == page.id)
|
||||
.values(content=new_content)
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Add connection_info column to Challenges
|
||||
|
||||
Revision ID: 6012fe8de495
|
||||
Revises: ef87d69ec29a
|
||||
Create Date: 2021-07-30 03:50:54.219124
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "6012fe8de495"
|
||||
down_revision = "ef87d69ec29a"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("challenges", sa.Column("connection_info", sa.Text(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("challenges", "connection_info")
|
||||
# ### end Alembic commands ###
|
||||
43
migrations/versions/62bf576b2cd3_add_solutions_table.py
Normal file
43
migrations/versions/62bf576b2cd3_add_solutions_table.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""Add Solutions table
|
||||
|
||||
Revision ID: 62bf576b2cd3
|
||||
Revises: a49ad66aa0f1
|
||||
Create Date: 2025-07-28 20:04:45.082529
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "62bf576b2cd3"
|
||||
down_revision = "a49ad66aa0f1"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"solutions",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("content", sa.Text(), nullable=True),
|
||||
sa.Column("state", sa.String(length=80), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["challenge_id"], ["challenges.id"], ondelete="CASCADE"
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("challenge_id"),
|
||||
)
|
||||
op.add_column("files", sa.Column("solution_id", sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(None, "files", "solutions", ["solution_id"], ["id"])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint(None, "files", type_="foreignkey")
|
||||
op.drop_column("files", "solution_id")
|
||||
op.drop_table("solutions")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Add change_password to Users
|
||||
|
||||
Revision ID: 662d728ad7da
|
||||
Revises: f73a96c97449
|
||||
Create Date: 2025-08-11 16:38:48.891702
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "662d728ad7da"
|
||||
down_revision = "f73a96c97449"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("users", sa.Column("change_password", sa.Boolean(), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("users", "change_password")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Add dynamic scoring columns to Challenges table
|
||||
|
||||
Revision ID: 67ebab6de598
|
||||
Revises: 24ad6790bc3c
|
||||
Create Date: 2025-09-11 08:57:33.156731
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "67ebab6de598"
|
||||
down_revision = "24ad6790bc3c"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("challenges", sa.Column("initial", sa.Integer(), nullable=True))
|
||||
op.add_column("challenges", sa.Column("minimum", sa.Integer(), nullable=True))
|
||||
op.add_column("challenges", sa.Column("decay", sa.Integer(), nullable=True))
|
||||
op.add_column(
|
||||
"challenges", sa.Column("function", sa.String(length=32), nullable=True)
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("challenges", "function")
|
||||
op.drop_column("challenges", "decay")
|
||||
op.drop_column("challenges", "minimum")
|
||||
op.drop_column("challenges", "initial")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Add Fields and FieldEntries tables
|
||||
|
||||
Revision ID: 75e8ab9a0014
|
||||
Revises: 0366ba6575ca
|
||||
Create Date: 2020-08-19 00:36:17.579497
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "75e8ab9a0014"
|
||||
down_revision = "0366ba6575ca"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"fields",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("name", sa.Text(), nullable=True),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("field_type", sa.String(length=80), nullable=True),
|
||||
sa.Column("description", sa.Text(), nullable=True),
|
||||
sa.Column("required", sa.Boolean(), nullable=True),
|
||||
sa.Column("public", sa.Boolean(), nullable=True),
|
||||
sa.Column("editable", sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"field_entries",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("value", sa.JSON(), nullable=True),
|
||||
sa.Column("field_id", sa.Integer(), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["field_id"], ["fields.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("field_entries")
|
||||
op.drop_table("fields")
|
||||
# ### end Alembic commands ###
|
||||
249
migrations/versions/8369118943a1_initial_revision.py
Normal file
249
migrations/versions/8369118943a1_initial_revision.py
Normal file
@@ -0,0 +1,249 @@
|
||||
"""Initial Revision
|
||||
|
||||
Revision ID: 8369118943a1
|
||||
Revises:
|
||||
Create Date: 2018-11-05 01:06:24.495010
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "8369118943a1"
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"challenges",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("name", sa.String(length=80), nullable=True),
|
||||
sa.Column("description", sa.Text(), nullable=True),
|
||||
sa.Column("max_attempts", sa.Integer(), nullable=True),
|
||||
sa.Column("value", sa.Integer(), nullable=True),
|
||||
sa.Column("category", sa.String(length=80), nullable=True),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("state", sa.String(length=80), nullable=False),
|
||||
sa.Column("requirements", sa.JSON(), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"config",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("key", sa.Text(), nullable=True),
|
||||
sa.Column("value", sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"pages",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("title", sa.String(length=80), nullable=True),
|
||||
sa.Column("route", sa.String(length=128), nullable=True),
|
||||
sa.Column("content", sa.Text(), nullable=True),
|
||||
sa.Column("draft", sa.Boolean(), nullable=True),
|
||||
sa.Column("hidden", sa.Boolean(), nullable=True),
|
||||
sa.Column("auth_required", sa.Boolean(), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("route"),
|
||||
)
|
||||
op.create_table(
|
||||
"teams",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("oauth_id", sa.Integer(), nullable=True),
|
||||
sa.Column("name", sa.String(length=128), nullable=True),
|
||||
sa.Column("email", sa.String(length=128), nullable=True),
|
||||
sa.Column("password", sa.String(length=128), nullable=True),
|
||||
sa.Column("secret", sa.String(length=128), nullable=True),
|
||||
sa.Column("website", sa.String(length=128), nullable=True),
|
||||
sa.Column("affiliation", sa.String(length=128), nullable=True),
|
||||
sa.Column("country", sa.String(length=32), nullable=True),
|
||||
sa.Column("bracket", sa.String(length=32), nullable=True),
|
||||
sa.Column("hidden", sa.Boolean(), nullable=True),
|
||||
sa.Column("banned", sa.Boolean(), nullable=True),
|
||||
sa.Column("created", sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("email"),
|
||||
sa.UniqueConstraint("id", "oauth_id"),
|
||||
sa.UniqueConstraint("oauth_id"),
|
||||
)
|
||||
op.create_table(
|
||||
"dynamic_challenge",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("initial", sa.Integer(), nullable=True),
|
||||
sa.Column("minimum", sa.Integer(), nullable=True),
|
||||
sa.Column("decay", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["id"], ["challenges.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"files",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("location", sa.Text(), nullable=True),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("page_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["challenge_id"], ["challenges.id"]),
|
||||
sa.ForeignKeyConstraint(["page_id"], ["pages.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"flags",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("content", sa.Text(), nullable=True),
|
||||
sa.Column("data", sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["challenge_id"], ["challenges.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"hints",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("content", sa.Text(), nullable=True),
|
||||
sa.Column("cost", sa.Integer(), nullable=True),
|
||||
sa.Column("requirements", sa.JSON(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["challenge_id"], ["challenges.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"tags",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("value", sa.String(length=80), nullable=True),
|
||||
sa.ForeignKeyConstraint(["challenge_id"], ["challenges.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"users",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("oauth_id", sa.Integer(), nullable=True),
|
||||
sa.Column("name", sa.String(length=128), nullable=True),
|
||||
sa.Column("password", sa.String(length=128), nullable=True),
|
||||
sa.Column("email", sa.String(length=128), nullable=True),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.Column("secret", sa.String(length=128), nullable=True),
|
||||
sa.Column("website", sa.String(length=128), nullable=True),
|
||||
sa.Column("affiliation", sa.String(length=128), nullable=True),
|
||||
sa.Column("country", sa.String(length=32), nullable=True),
|
||||
sa.Column("bracket", sa.String(length=32), nullable=True),
|
||||
sa.Column("hidden", sa.Boolean(), nullable=True),
|
||||
sa.Column("banned", sa.Boolean(), nullable=True),
|
||||
sa.Column("verified", sa.Boolean(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.Column("created", sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("email"),
|
||||
sa.UniqueConstraint("id", "oauth_id"),
|
||||
sa.UniqueConstraint("oauth_id"),
|
||||
)
|
||||
op.create_table(
|
||||
"awards",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.Column("name", sa.String(length=80), nullable=True),
|
||||
sa.Column("description", sa.Text(), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.Column("value", sa.Integer(), nullable=True),
|
||||
sa.Column("category", sa.String(length=80), nullable=True),
|
||||
sa.Column("icon", sa.Text(), nullable=True),
|
||||
sa.Column("requirements", sa.JSON(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"]),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"notifications",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("title", sa.Text(), nullable=True),
|
||||
sa.Column("content", sa.Text(), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"]),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"submissions",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.Column("ip", sa.String(length=46), nullable=True),
|
||||
sa.Column("provided", sa.Text(), nullable=True),
|
||||
sa.Column("type", sa.String(length=32), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["challenge_id"], ["challenges.id"], ondelete="CASCADE"
|
||||
),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"tracking",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("type", sa.String(length=32), nullable=True),
|
||||
sa.Column("ip", sa.String(length=46), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"unlocks",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.Column("target", sa.Integer(), nullable=True),
|
||||
sa.Column("date", sa.DateTime(), nullable=True),
|
||||
sa.Column("type", sa.String(length=32), nullable=True),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"]),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_table(
|
||||
"solves",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("user_id", sa.Integer(), nullable=True),
|
||||
sa.Column("team_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["challenge_id"], ["challenges.id"], ondelete="CASCADE"
|
||||
),
|
||||
sa.ForeignKeyConstraint(["id"], ["submissions.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["team_id"], ["teams.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("challenge_id", "team_id"),
|
||||
sa.UniqueConstraint("challenge_id", "user_id"),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("solves")
|
||||
op.drop_table("unlocks")
|
||||
op.drop_table("tracking")
|
||||
op.drop_table("submissions")
|
||||
op.drop_table("notifications")
|
||||
op.drop_table("awards")
|
||||
op.drop_table("users")
|
||||
op.drop_table("tags")
|
||||
op.drop_table("hints")
|
||||
op.drop_table("flags")
|
||||
op.drop_table("files")
|
||||
op.drop_table("dynamic_challenge")
|
||||
op.drop_table("teams")
|
||||
op.drop_table("pages")
|
||||
op.drop_table("config")
|
||||
op.drop_table("challenges")
|
||||
# ### end Alembic commands ###
|
||||
51
migrations/versions/9889b8c53673_add_brackets_table.py
Normal file
51
migrations/versions/9889b8c53673_add_brackets_table.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""Add Brackets table
|
||||
|
||||
Revision ID: 9889b8c53673
|
||||
Revises: 5c4996aeb2cb
|
||||
Create Date: 2024-01-25 03:17:52.734753
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "9889b8c53673"
|
||||
down_revision = "5c4996aeb2cb"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
"brackets",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("name", sa.String(length=255), nullable=True),
|
||||
sa.Column("description", sa.Text(), nullable=True),
|
||||
sa.Column("type", sa.String(length=80), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.add_column("teams", sa.Column("bracket_id", sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(
|
||||
None, "teams", "brackets", ["bracket_id"], ["id"], ondelete="SET NULL"
|
||||
)
|
||||
op.drop_column("teams", "bracket")
|
||||
op.add_column("users", sa.Column("bracket_id", sa.Integer(), nullable=True))
|
||||
op.create_foreign_key(
|
||||
None, "users", "brackets", ["bracket_id"], ["id"], ondelete="SET NULL"
|
||||
)
|
||||
op.drop_column("users", "bracket")
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.add_column(
|
||||
"users", sa.Column("bracket", mysql.VARCHAR(length=32), nullable=True)
|
||||
)
|
||||
op.drop_constraint(None, "users", type_="foreignkey")
|
||||
op.drop_column("users", "bracket_id")
|
||||
op.add_column(
|
||||
"teams", sa.Column("bracket", mysql.VARCHAR(length=32), nullable=True)
|
||||
)
|
||||
op.drop_constraint(None, "teams", type_="foreignkey")
|
||||
op.drop_column("teams", "bracket_id")
|
||||
op.drop_table("brackets")
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Add description column to tokens table
|
||||
|
||||
Revision ID: 9e6f6578ca84
|
||||
Revises: 0def790057c1
|
||||
Create Date: 2023-06-21 23:22:34.179636
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "9e6f6578ca84"
|
||||
down_revision = "0def790057c1"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column("tokens", sa.Column("description", sa.Text(), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("tokens", "description")
|
||||
26
migrations/versions/a02c5bf43407_add_link_target_to_pages.py
Normal file
26
migrations/versions/a02c5bf43407_add_link_target_to_pages.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Add link_target to Pages
|
||||
|
||||
Revision ID: a02c5bf43407
|
||||
Revises: 9889b8c53673
|
||||
Create Date: 2024-02-01 13:11:53.076825
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "a02c5bf43407"
|
||||
down_revision = "9889b8c53673"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column(
|
||||
"pages", sa.Column("link_target", sa.String(length=80), nullable=True)
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("pages", "link_target")
|
||||
@@ -0,0 +1,46 @@
|
||||
"""add theme code injections to configs
|
||||
|
||||
Revision ID: a03403986a32
|
||||
Revises: 080d29b15cd3
|
||||
Create Date: 2020-02-13 01:10:16.430424
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
from sqlalchemy.sql import column, table
|
||||
|
||||
from CTFd.models import db
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "a03403986a32"
|
||||
down_revision = "080d29b15cd3"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
configs_table = table(
|
||||
"config", column("id", db.Integer), column("key", db.Text), column("value", db.Text)
|
||||
)
|
||||
|
||||
|
||||
def upgrade():
|
||||
connection = op.get_bind()
|
||||
css = connection.execute(
|
||||
configs_table.select().where(configs_table.c.key == "css").limit(1)
|
||||
).fetchone()
|
||||
|
||||
if css and css.value:
|
||||
new_css = "<style>\n" + css.value + "\n</style>"
|
||||
config = connection.execute(
|
||||
configs_table.select().where(configs_table.c.key == "theme_header").limit(1)
|
||||
).fetchone()
|
||||
if config:
|
||||
# Do not overwrite existing theme_header value
|
||||
pass
|
||||
else:
|
||||
connection.execute(
|
||||
configs_table.insert().values(key="theme_header", value=new_css)
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
||||
23
migrations/versions/a49ad66aa0f1_add_title_to_hint.py
Normal file
23
migrations/versions/a49ad66aa0f1_add_title_to_hint.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""add title to hint
|
||||
|
||||
Revision ID: a49ad66aa0f1
|
||||
Revises: 4fe3eeed9a9d
|
||||
Create Date: 2025-02-10 14:45:00.933880
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "a49ad66aa0f1"
|
||||
down_revision = "4fe3eeed9a9d"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column("hints", sa.Column("title", sa.String(length=80), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_column("hints", "title")
|
||||
@@ -0,0 +1,298 @@
|
||||
"""Add ondelete cascade to foreign keys
|
||||
|
||||
Revision ID: b295b033364d
|
||||
Revises: b5551cd26764
|
||||
Create Date: 2019-05-03 19:26:57.746887
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "b295b033364d"
|
||||
down_revision = "b5551cd26764"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
url = str(bind.engine.url)
|
||||
if url.startswith("mysql"):
|
||||
op.drop_constraint("awards_ibfk_1", "awards", type_="foreignkey")
|
||||
op.drop_constraint("awards_ibfk_2", "awards", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"awards_ibfk_1", "awards", "teams", ["team_id"], ["id"], ondelete="CASCADE"
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"awards_ibfk_2", "awards", "users", ["user_id"], ["id"], ondelete="CASCADE"
|
||||
)
|
||||
|
||||
op.drop_constraint("files_ibfk_1", "files", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"files_ibfk_1",
|
||||
"files",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("flags_ibfk_1", "flags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"flags_ibfk_1",
|
||||
"flags",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("hints_ibfk_1", "hints", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"hints_ibfk_1",
|
||||
"hints",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("tags_ibfk_1", "tags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tags_ibfk_1",
|
||||
"tags",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("team_captain_id", "teams", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"team_captain_id",
|
||||
"teams",
|
||||
"users",
|
||||
["captain_id"],
|
||||
["id"],
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
|
||||
op.drop_constraint("tracking_ibfk_1", "tracking", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tracking_ibfk_1",
|
||||
"tracking",
|
||||
"users",
|
||||
["user_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("unlocks_ibfk_1", "unlocks", type_="foreignkey")
|
||||
op.drop_constraint("unlocks_ibfk_2", "unlocks", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"unlocks_ibfk_1",
|
||||
"unlocks",
|
||||
"teams",
|
||||
["team_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"unlocks_ibfk_2",
|
||||
"unlocks",
|
||||
"users",
|
||||
["user_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
elif url.startswith("postgres"):
|
||||
op.drop_constraint("awards_team_id_fkey", "awards", type_="foreignkey")
|
||||
op.drop_constraint("awards_user_id_fkey", "awards", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"awards_team_id_fkey",
|
||||
"awards",
|
||||
"teams",
|
||||
["team_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"awards_user_id_fkey",
|
||||
"awards",
|
||||
"users",
|
||||
["user_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("files_challenge_id_fkey", "files", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"files_challenge_id_fkey",
|
||||
"files",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("flags_challenge_id_fkey", "flags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"flags_challenge_id_fkey",
|
||||
"flags",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("hints_challenge_id_fkey", "hints", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"hints_challenge_id_fkey",
|
||||
"hints",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("tags_challenge_id_fkey", "tags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tags_challenge_id_fkey",
|
||||
"tags",
|
||||
"challenges",
|
||||
["challenge_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("team_captain_id", "teams", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"team_captain_id",
|
||||
"teams",
|
||||
"users",
|
||||
["captain_id"],
|
||||
["id"],
|
||||
ondelete="SET NULL",
|
||||
)
|
||||
|
||||
op.drop_constraint("tracking_user_id_fkey", "tracking", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tracking_user_id_fkey",
|
||||
"tracking",
|
||||
"users",
|
||||
["user_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
op.drop_constraint("unlocks_team_id_fkey", "unlocks", type_="foreignkey")
|
||||
op.drop_constraint("unlocks_user_id_fkey", "unlocks", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"unlocks_team_id_fkey",
|
||||
"unlocks",
|
||||
"teams",
|
||||
["team_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"unlocks_user_id_fkey",
|
||||
"unlocks",
|
||||
"users",
|
||||
["user_id"],
|
||||
["id"],
|
||||
ondelete="CASCADE",
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
bind = op.get_bind()
|
||||
url = str(bind.engine.url)
|
||||
if url.startswith("mysql"):
|
||||
op.drop_constraint("unlocks_ibfk_1", "unlocks", type_="foreignkey")
|
||||
op.drop_constraint("unlocks_ibfk_2", "unlocks", type_="foreignkey")
|
||||
op.create_foreign_key("unlocks_ibfk_1", "unlocks", "teams", ["team_id"], ["id"])
|
||||
op.create_foreign_key("unlocks_ibfk_2", "unlocks", "users", ["user_id"], ["id"])
|
||||
|
||||
op.drop_constraint("tracking_ibfk_1", "tracking", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tracking_ibfk_1", "tracking", "users", ["user_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("team_captain_id", "teams", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"team_captain_id", "teams", "users", ["captain_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("tags_ibfk_1", "tags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tags_ibfk_1", "tags", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("hints_ibfk_1", "hints", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"hints_ibfk_1", "hints", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("flags_ibfk_1", "flags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"flags_ibfk_1", "flags", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("files_ibfk_1", "files", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"files_ibfk_1", "files", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("awards_ibfk_1", "awards", type_="foreignkey")
|
||||
op.drop_constraint("awards_ibfk_2", "awards", type_="foreignkey")
|
||||
op.create_foreign_key("awards_ibfk_1", "awards", "teams", ["team_id"], ["id"])
|
||||
op.create_foreign_key("awards_ibfk_2", "awards", "users", ["user_id"], ["id"])
|
||||
elif url.startswith("postgres"):
|
||||
op.drop_constraint("unlocks_team_id_fkey", "unlocks", type_="foreignkey")
|
||||
op.drop_constraint("unlocks_user_id_fkey", "unlocks", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"unlocks_team_id_fkey", "unlocks", "teams", ["team_id"], ["id"]
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"unlocks_user_id_fkey", "unlocks", "users", ["user_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("tracking_user_id_fkey", "tracking", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tracking_user_id_fkey", "tracking", "users", ["user_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("team_captain_id", "teams", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"team_captain_id", "teams", "users", ["captain_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("tags_challenge_id_fkey", "tags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"tags_challenge_id_fkey", "tags", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("hints_challenge_id_fkey", "hints", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"hints_challenge_id_fkey", "hints", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("flags_challenge_id_fkey", "flags", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"flags_challenge_id_fkey", "flags", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("files_challenge_id_fkey", "files", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"files_challenge_id_fkey", "files", "challenges", ["challenge_id"], ["id"]
|
||||
)
|
||||
|
||||
op.drop_constraint("awards_team_id_fkey", "awards", type_="foreignkey")
|
||||
op.drop_constraint("awards_user_id_fkey", "awards", type_="foreignkey")
|
||||
op.create_foreign_key(
|
||||
"awards_team_id_fkey", "awards", "teams", ["team_id"], ["id"]
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"awards_user_id_fkey", "awards", "users", ["user_id"], ["id"]
|
||||
)
|
||||
@@ -0,0 +1,57 @@
|
||||
"""Add captain column to Teams
|
||||
|
||||
Revision ID: b5551cd26764
|
||||
Revises: 4e4d5a9ea000
|
||||
Create Date: 2019-04-12 00:29:08.021141
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
from sqlalchemy.sql import column, table
|
||||
|
||||
from CTFd.models import db
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "b5551cd26764"
|
||||
down_revision = "4e4d5a9ea000"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
teams_table = table("teams", column("id", db.Integer), column("captain_id", db.Integer))
|
||||
|
||||
users_table = table("users", column("id", db.Integer), column("team_id", db.Integer))
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("teams", sa.Column("captain_id", sa.Integer(), nullable=True))
|
||||
|
||||
bind = op.get_bind()
|
||||
url = str(bind.engine.url)
|
||||
if url.startswith("sqlite") is False:
|
||||
op.create_foreign_key(
|
||||
"team_captain_id", "teams", "users", ["captain_id"], ["id"]
|
||||
)
|
||||
|
||||
connection = op.get_bind()
|
||||
for team in connection.execute(teams_table.select()):
|
||||
users = connection.execute(
|
||||
users_table.select()
|
||||
.where(users_table.c.team_id == team.id)
|
||||
.order_by(users_table.c.id)
|
||||
.limit(1)
|
||||
)
|
||||
for user in users:
|
||||
connection.execute(
|
||||
teams_table.update()
|
||||
.where(teams_table.c.id == team.id)
|
||||
.values(captain_id=user.id)
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint("team_captain_id", "teams", type_="foreignkey")
|
||||
op.drop_column("teams", "captain_id")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Add topics and challenge_topics tables
|
||||
|
||||
Revision ID: ef87d69ec29a
|
||||
Revises: 07dfbe5e1edc
|
||||
Create Date: 2021-07-29 23:22:39.345426
|
||||
|
||||
"""
|
||||
from alembic import op # noqa: I001
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "ef87d69ec29a"
|
||||
down_revision = "07dfbe5e1edc"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"topics",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("value", sa.String(length=255), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("value"),
|
||||
)
|
||||
op.create_table(
|
||||
"challenge_topics",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("challenge_id", sa.Integer(), nullable=True),
|
||||
sa.Column("topic_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["challenge_id"], ["challenges.id"], ondelete="CASCADE"
|
||||
),
|
||||
sa.ForeignKeyConstraint(["topic_id"], ["topics.id"], ondelete="CASCADE"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table("challenge_topics")
|
||||
op.drop_table("topics")
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,30 @@
|
||||
"""Add logic column to Challenges
|
||||
|
||||
Revision ID: f73a96c97449
|
||||
Revises: 62bf576b2cd3
|
||||
Create Date: 2025-08-08 21:49:23.417694
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "f73a96c97449"
|
||||
down_revision = "62bf576b2cd3"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column(
|
||||
"challenges", sa.Column("logic", sa.String(length=80), nullable=False)
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("challenges", "logic")
|
||||
# ### end Alembic commands ###
|
||||
Reference in New Issue
Block a user