aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Chris Lovering <[email protected]>2024-07-09 20:08:44 +0100
committerGravatar Chris Lovering <[email protected]>2024-07-21 13:45:30 +0100
commita439ef0fefe9f171ca1568869820ee159036bdfc (patch)
tree9d20fe840a7fdfd9e80424c99fd2f55ff707fc28
parentAdd alembic boiler plate for migrations (diff)
Add models and migration files for admins & forms
-rw-r--r--backend/models/orm/__init__.py30
-rw-r--r--backend/models/orm/admins.py14
-rw-r--r--backend/models/orm/forms.py61
-rw-r--r--migrations/versions/1721486482-a9ea4b71d23a_add_admins_forms.py93
4 files changed, 198 insertions, 0 deletions
diff --git a/backend/models/orm/__init__.py b/backend/models/orm/__init__.py
index 4c8a6b4..4db39ae 100644
--- a/backend/models/orm/__init__.py
+++ b/backend/models/orm/__init__.py
@@ -1,7 +1,37 @@
"""Database models."""
+from .admins import Admin
from .base import Base
+from .forms import Form, FormEditor, FormFeatures
+from .questions import (
+ FormCheckboxQuestion,
+ FormCodeQuestion,
+ FormCodeQuestionTest,
+ FormQuestion,
+ FormRadioQuestion,
+ FormRangeQuestion,
+ FormSectionQuestion,
+ FormSelectQuestion,
+ FormTextQuestion,
+ FormTimezoneQuestion,
+ FormVoteQuestion,
+)
__all__ = (
+ "Admin",
"Base",
+ "Form",
+ "FormCheckboxQuestion",
+ "FormCodeQuestion",
+ "FormCodeQuestionTest",
+ "FormEditor",
+ "FormFeatures",
+ "FormQuestion",
+ "FormRadioQuestion",
+ "FormRangeQuestion",
+ "FormSectionQuestion",
+ "FormSelectQuestion",
+ "FormTextQuestion",
+ "FormTimezoneQuestion",
+ "FormVoteQuestion",
)
diff --git a/backend/models/orm/admins.py b/backend/models/orm/admins.py
new file mode 100644
index 0000000..7eee008
--- /dev/null
+++ b/backend/models/orm/admins.py
@@ -0,0 +1,14 @@
+"""Discord members who have admin access."""
+
+from sqlalchemy.orm import Mapped, mapped_column
+from sqlalchemy.types import BigInteger
+
+from .base import Base
+
+
+class Admin(Base):
+ """A discord user_id that has admin level access to forms."""
+
+ __tablename__ = "admins"
+
+ user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
diff --git a/backend/models/orm/forms.py b/backend/models/orm/forms.py
new file mode 100644
index 0000000..489b71b
--- /dev/null
+++ b/backend/models/orm/forms.py
@@ -0,0 +1,61 @@
+"""All forms that can have submissions."""
+
+import sqlalchemy.dialects.postgresql as pg
+from sqlalchemy import ForeignKey
+from sqlalchemy.orm import Mapped, mapped_column, relationship
+from sqlalchemy.types import BigInteger, Enum, Text
+
+from backend.constants import FormFeatures
+
+from .base import Base
+
+
+class Form(Base):
+ """A form that users can submit responses to."""
+
+ __tablename__ = "forms"
+
+ form_id: Mapped[int] = mapped_column(primary_key=True)
+
+ short_name: Mapped[str] = mapped_column(Text, nullable=False, index=True)
+ name: Mapped[str] = mapped_column(Text, nullable=False)
+ description: Mapped[str] = mapped_column(Text, nullable=False)
+ submission_text: Mapped[str | None] = mapped_column(Text, nullable=True)
+
+ webhook_url: Mapped[str | None] = mapped_column(Text, nullable=True)
+ webhook_message: Mapped[str | None] = mapped_column(Text, nullable=True)
+
+ discord_role: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
+
+ features: Mapped[list[FormFeatures]] = mapped_column(pg.ARRAY(Enum(FormFeatures), dimensions=1))
+
+ form_response_readers: Mapped[list["FormResponseReader"]] = relationship(
+ cascade="all, delete",
+ passive_deletes=True,
+ )
+ form_editors: Mapped[list["FormEditor"]] = relationship(
+ cascade="all, delete",
+ passive_deletes=True,
+ )
+
+
+class FormResponseReader(Base):
+ """A Discord user that can read a given form."""
+
+ __tablename__ = "form_response_readers"
+
+ form_id: Mapped[int] = mapped_column(
+ ForeignKey("forms.form_id", ondelete="CASCADE"), primary_key=True
+ )
+ user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
+
+
+class FormEditor(Base):
+ """A Discord user that can edit a given form."""
+
+ __tablename__ = "form_editors"
+
+ form_id: Mapped[int] = mapped_column(
+ ForeignKey("forms.form_id", ondelete="CASCADE"), primary_key=True
+ )
+ user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
diff --git a/migrations/versions/1721486482-a9ea4b71d23a_add_admins_forms.py b/migrations/versions/1721486482-a9ea4b71d23a_add_admins_forms.py
new file mode 100644
index 0000000..c61944b
--- /dev/null
+++ b/migrations/versions/1721486482-a9ea4b71d23a_add_admins_forms.py
@@ -0,0 +1,93 @@
+"""
+Add admins & forms.
+
+Revision ID: a9ea4b71d23a
+Revises:
+Create Date: 2024-07-20 14:41:22.166383+00:00
+"""
+
+import sqlalchemy as sa
+from alembic import op
+from sqlalchemy.dialects import postgresql
+
+# revision identifiers, used by Alembic.
+revision = "a9ea4b71d23a"
+down_revision = None
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ """Apply this migration."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table(
+ "admins",
+ sa.Column("user_id", sa.BigInteger(), nullable=False),
+ sa.PrimaryKeyConstraint("user_id", name=op.f("admins_pk")),
+ )
+ op.create_table(
+ "forms",
+ sa.Column("form_id", sa.Integer(), nullable=False),
+ sa.Column("short_name", sa.Text(), nullable=False),
+ sa.Column("name", sa.Text(), nullable=False),
+ sa.Column("description", sa.Text(), nullable=False),
+ sa.Column("submission_text", sa.Text(), nullable=True),
+ sa.Column("webhook_url", sa.Text(), nullable=True),
+ sa.Column("webhook_message", sa.Text(), nullable=True),
+ sa.Column("discord_role", sa.BigInteger(), nullable=True),
+ sa.Column(
+ "features",
+ postgresql.ARRAY(
+ sa.Enum(
+ "DISCOVERABLE",
+ "REQUIRES_LOGIN",
+ "OPEN",
+ "COLLECT_EMAIL",
+ "DISABLE_ANTISPAM",
+ "WEBHOOK_ENABLED",
+ "ASSIGN_ROLE",
+ name="formfeatures",
+ ),
+ dimensions=1,
+ ),
+ nullable=False,
+ ),
+ sa.PrimaryKeyConstraint("form_id", name=op.f("forms_pk")),
+ )
+ op.create_index(op.f("forms_short_name_ix"), "forms", ["short_name"], unique=False)
+ op.create_table(
+ "form_editors",
+ sa.Column("form_id", sa.Integer(), nullable=False),
+ sa.Column("user_id", sa.BigInteger(), nullable=False),
+ sa.ForeignKeyConstraint(
+ ["form_id"],
+ ["forms.form_id"],
+ name=op.f("form_editors_form_id_forms_fk"),
+ ondelete="CASCADE",
+ ),
+ sa.PrimaryKeyConstraint("form_id", "user_id", name=op.f("form_editors_pk")),
+ )
+ op.create_table(
+ "form_response_readers",
+ sa.Column("form_id", sa.Integer(), nullable=False),
+ sa.Column("user_id", sa.BigInteger(), nullable=False),
+ sa.ForeignKeyConstraint(
+ ["form_id"],
+ ["forms.form_id"],
+ name=op.f("form_response_readers_form_id_forms_fk"),
+ ondelete="CASCADE",
+ ),
+ sa.PrimaryKeyConstraint("form_id", "user_id", name=op.f("form_response_readers_pk")),
+ )
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ """Revert this migration."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_table("form_response_readers")
+ op.drop_table("form_editors")
+ op.drop_index(op.f("forms_short_name_ix"), table_name="forms")
+ op.drop_table("forms")
+ op.drop_table("admins")
+ # ### end Alembic commands ###