From 9dcc1f12a85c45255f62ce628755423d043d29fb Mon Sep 17 00:00:00 2001 From: edu Date: Tue, 9 Jun 2026 09:30:15 -0300 Subject: [PATCH 1/7] feat: estrutura inicial do ambiente de testes da US6 --- app/database.py | 1 + docker-compose.yml | 57 ++++++++------------ requirements_lock.txt | 123 ++++++++++++------------------------------ tests/test_all.py | 4 +- 4 files changed, 60 insertions(+), 125 deletions(-) diff --git a/app/database.py b/app/database.py index 8388a6d..9962aec 100644 --- a/app/database.py +++ b/app/database.py @@ -4,6 +4,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from .settings import settings +from app import models SQLALCHEMY_DATABASE_URL = ( diff --git a/docker-compose.yml b/docker-compose.yml index 37f003f..3880bcf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,46 +1,31 @@ +version: '3.8' + services: stars-api: build: . container_name: stars-api env_file: - .env - - # ports: - # - '8000:80' - # COMENTADO: Volumes podem esconder o código da imagem se não sincronizados - # volumes: - # - ./:/code/ + ports: + - '8000:80' restart: on-failure - # Em produção, não usamos --reload para evitar overhead e problemas com sistemas de arquivos command: uvicorn app.main:app --host 0.0.0.0 --port 80 - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - # depends_on: - # mysql_database: - # condition: service_healthy + depends_on: + - mysql_database - # mysql_database: - # image: mysql:8.3 - # restart: unless-stopped - # command: --default-authentication-plugin=caching_sha2_password - # environment: - # MYSQL_DATABASE: 'db' - # MYSQL_USER: 'mysql' - # MYSQL_PASSWORD: 'mysql' - # MYSQL_ROOT_PASSWORD: 'mysql' - # ports: - # - '3307:3306' - # volumes: - # - mysql_database:/var/lib/mysql - # healthcheck: - # test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] - # timeout: 20s - # retries: 10 + mysql_database: + image: mysql:8.3 + container_name: mysql_stars + restart: unless-stopped + command: --default-authentication-plugin=caching_sha2_password + environment: + MYSQL_DATABASE: 'stars' + MYSQL_ROOT_PASSWORD: 'root' # Define a senha diretamente para o usuário root padrão + ports: + - '3306:3306' + volumes: + - mysql_database:/var/lib/mysql -# volumes: -# mysql_database: -# name: mysql_database +volumes: + mysql_database: + name: mysql_database \ No newline at end of file diff --git a/requirements_lock.txt b/requirements_lock.txt index e29c563..925fb89 100644 --- a/requirements_lock.txt +++ b/requirements_lock.txt @@ -1,90 +1,37 @@ -asn1crypto==1.5.1 -autocommand==2.2.2 -bcc==0.30.0 -bcrypt==4.2.0 -beautifulsoup4==4.13.3 -blinker==1.9.0 -certifi==2025.1.31 -chardet==5.2.0 -click==8.1.8 -command-not-found==0.3 -cryptography==43.0.0 -cssselect==1.3.0 -cupshelpers==1.0 -dbus-python==1.3.2 -distro==1.9.0 -distro-info==1.13 -fuse-python==1.0.9 -gyp-next==0.16.2 -html5lib-modern==1.2 -httplib2==0.22.0 +alembic==1.13.3 +annotated-types==0.7.0 +anyio==4.6.2.post1 +asgiref==3.8.1 +certifi==2024.8.30 +click==8.1.7 +ecdsa==0.19.0 +fastapi==0.115.2 +greenlet==3.1.1 +h11==0.14.0 idna==3.10 -importlib_metadata==8.6.1 -inflect==7.3.1 -jaraco.classes==3.4.0 -jaraco.context==6.0.1 -jaraco.functools==4.1.0 -jeepney==0.8.0 -keyring==25.6.0 -language-selector==0.1 -launchpadlib==2.1.0 -lazr.restfulclient==0.14.6 -lazr.uri==1.0.6 -lxml==5.3.2 -markdown-it-py==3.0.0 -mdurl==0.1.2 -mechanize==0.4.10 -more-itertools==10.6.0 -mutagen==1.47.0 -netaddr==1.3.0 -netifaces==0.11.0 -numpy==2.2.3 -oauthlib==3.2.2 -olefile==0.47 -osc==1.12.1 -packaging==24.2 -pexpect==4.9.0 -pillow==11.1.0 -psutil==5.9.8 -ptyprocess==0.7.0 -pycairo==1.27.0 -pycryptodomex==3.20.0 -pycups==2.0.4 -Pygments==2.18.0 -PyGObject==3.50.0 -PyJWT==2.10.1 -pylibacl==0.7.2 -pyparsing==3.1.2 -PyQt6==6.8.1 -PyQt6_sip==13.10.0 -python-apt==3.0.0 -python-debian==1.0.1+ubuntu1 -pyxattr==0.8.1 -PyYAML==6.0.2 -requests==2.32.3 -rich==13.9.4 -rpm==4.20.1 -ruamel.yaml==0.18.10 -ruamel.yaml.clib==0.2.12 -scour==0.38.2 -SecretStorage==3.3.3 -sentry-sdk==2.18.0 -soupsieve==2.6 -systemd-python==235 -tornado==6.4.2 -typeguard==4.4.2 +Mako==1.3.5 +MarkupSafe==3.0.1 +mysql-connector-python==9.0.0 +passlib==1.7.4 +pyasn1==0.6.1 +pydantic==2.9.2 +pydantic-settings==2.5.2 +pydantic_core==2.23.4 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +python-jose==3.3.0 +python-multipart==0.0.12 +rsa==4.9 +setuptools==75.1.0 +sib-api-v3-sdk==7.6.0 +six==1.16.0 +sniffio==1.3.1 +SQLAlchemy==2.0.35 +starlette==0.39.2 typing_extensions==4.12.2 -ubuntu-drivers-common==0.0.0 -ubuntu-pro-client==8001 -ufw==0.36.2 -unattended-upgrades==0.1 -urllib3==2.3.0 -usb-creator==0.3.16 -wadllib==2.0.0 -webencodings==0.5.1 -websocket-client==1.8.0 -websockets==14.1 -wheel==0.45.1 -xkit==0.0.0 -yt-dlp==2025.3.27 -zipp==3.21.0 +urllib3==2.2.3 +uvicorn==0.31.1 +wheel==0.44.0 +pytest +httpx + diff --git a/tests/test_all.py b/tests/test_all.py index 080085b..b5753e7 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -4,7 +4,9 @@ from sqlalchemy.orm import sessionmaker from app.main import app from app.database import Base, get_db -from app.models import User +from app import models +from alembic import command +from alembic.config import Config # Configuração do banco de dados de teste em memória SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" From fcfcca42395298c12e22bd771881b72d9fb52b9e Mon Sep 17 00:00:00 2001 From: edu Date: Fri, 12 Jun 2026 17:13:35 -0300 Subject: [PATCH 2/7] feat: add referral information and terms acceptance fields to volunteer model --- .../03fa6dddb4dc_add_project_model.py | 30 --- ...9a228ec6ed_add_discord_role_id_to_squad.py | 30 --- .../versions/1a8b326c7c3d_add_squad_model.py | 46 ---- .../versions/280bfcafaea7_add_user_roles.py | 30 --- .../42f35efc471b_add_github_to_volunteer.py | 32 --- ...292839_add_volunteer_status_and_history.py | 61 ----- ...0fbad971fbc_add_created_at_to_volunteer.py | 44 ---- ...6f_add_discord_invite_sent_to_volunteer.py | 30 --- .../794a393796c0_create_baseline_tables.py | 247 ++++++++++++++++++ .../7cf65bf6bf3f_add_volunteer_types.py | 64 ----- ...8af0da9402_create_a_baseline_migrations.py | 73 ------ .../842ae7994682_add_discord_to_volunteer.py | 30 --- .../versions/885ee5c8b30c_add_badges_model.py | 30 --- .../8fb47fe0135f_add_is_apoiase_supporter.py | 30 --- ...d5955758_add_initial_volunteer_statuses.py | 45 ---- .../9d6e1bd86f06_add_description_to_squad.py | 30 --- ...1e488_add_referral_and_terms_fields_to_.py | 40 +++ ...74a653cbf11_add_volunteer_edit_tracking.py | 38 --- ...0610f_add_password_reset_fields_to_user.py | 34 --- .../acafbc8a9999_add_feedback_model.py | 30 --- .../b48a3d6f234e_add_phone_to_volunteer.py | 30 --- .../b891cb556342_add_certificate_model.py | 30 --- ...4b6a5_add_jobopening_and_jobapplication.py | 30 --- ...3ebe5b56_add_mentor_mentee_relationship.py | 36 --- .../f88261e5dc27_add_vertical_model.py | 30 --- ...e37356bc2ec_add_order_to_volunteer_type.py | 30 --- app/database.py | 1 - app/models.py | 6 + 28 files changed, 293 insertions(+), 894 deletions(-) delete mode 100755 alembic/versions/03fa6dddb4dc_add_project_model.py delete mode 100644 alembic/versions/079a228ec6ed_add_discord_role_id_to_squad.py delete mode 100755 alembic/versions/1a8b326c7c3d_add_squad_model.py delete mode 100644 alembic/versions/280bfcafaea7_add_user_roles.py delete mode 100644 alembic/versions/42f35efc471b_add_github_to_volunteer.py delete mode 100755 alembic/versions/468e7b292839_add_volunteer_status_and_history.py delete mode 100755 alembic/versions/50fbad971fbc_add_created_at_to_volunteer.py delete mode 100644 alembic/versions/544f4a8a3a6f_add_discord_invite_sent_to_volunteer.py create mode 100644 alembic/versions/794a393796c0_create_baseline_tables.py delete mode 100755 alembic/versions/7cf65bf6bf3f_add_volunteer_types.py delete mode 100755 alembic/versions/838af0da9402_create_a_baseline_migrations.py delete mode 100755 alembic/versions/842ae7994682_add_discord_to_volunteer.py delete mode 100644 alembic/versions/885ee5c8b30c_add_badges_model.py delete mode 100644 alembic/versions/8fb47fe0135f_add_is_apoiase_supporter.py delete mode 100755 alembic/versions/9c3cd5955758_add_initial_volunteer_statuses.py delete mode 100644 alembic/versions/9d6e1bd86f06_add_description_to_squad.py create mode 100644 alembic/versions/a48937e1e488_add_referral_and_terms_fields_to_.py delete mode 100755 alembic/versions/a74a653cbf11_add_volunteer_edit_tracking.py delete mode 100644 alembic/versions/a879d6c0610f_add_password_reset_fields_to_user.py delete mode 100644 alembic/versions/acafbc8a9999_add_feedback_model.py delete mode 100755 alembic/versions/b48a3d6f234e_add_phone_to_volunteer.py delete mode 100644 alembic/versions/b891cb556342_add_certificate_model.py delete mode 100644 alembic/versions/df42d3b4b6a5_add_jobopening_and_jobapplication.py delete mode 100644 alembic/versions/e9463ebe5b56_add_mentor_mentee_relationship.py delete mode 100644 alembic/versions/f88261e5dc27_add_vertical_model.py delete mode 100644 alembic/versions/fe37356bc2ec_add_order_to_volunteer_type.py diff --git a/alembic/versions/03fa6dddb4dc_add_project_model.py b/alembic/versions/03fa6dddb4dc_add_project_model.py deleted file mode 100755 index ead20e3..0000000 --- a/alembic/versions/03fa6dddb4dc_add_project_model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Add Project model - -Revision ID: 03fa6dddb4dc -Revises: a74a653cbf11 -Create Date: 2025-12-14 17:30:04.508365 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '03fa6dddb4dc' -down_revision: Union[str, None] = 'a74a653cbf11' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/alembic/versions/079a228ec6ed_add_discord_role_id_to_squad.py b/alembic/versions/079a228ec6ed_add_discord_role_id_to_squad.py deleted file mode 100644 index 884bd5b..0000000 --- a/alembic/versions/079a228ec6ed_add_discord_role_id_to_squad.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add discord role id to squad - -Revision ID: 079a228ec6ed -Revises: df42d3b4b6a5 -Create Date: 2026-02-02 14:52:00.940076 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '079a228ec6ed' -down_revision: Union[str, None] = 'df42d3b4b6a5' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('squad', sa.Column('discord_role_id', sa.String(length=255), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('squad', 'discord_role_id') - # ### end Alembic commands ### diff --git a/alembic/versions/1a8b326c7c3d_add_squad_model.py b/alembic/versions/1a8b326c7c3d_add_squad_model.py deleted file mode 100755 index 00f4062..0000000 --- a/alembic/versions/1a8b326c7c3d_add_squad_model.py +++ /dev/null @@ -1,46 +0,0 @@ -"""add_squad_model - -Revision ID: 1a8b326c7c3d -Revises: b48a3d6f234e -Create Date: 2025-12-09 14:44:55.019816 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision: str = '1a8b326c7c3d' -down_revision: Union[str, None] = 'b48a3d6f234e' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.alter_column('volunteer', 'name', - existing_type=mysql.VARCHAR(charset='utf8mb4', collation='utf8mb4_0900_ai_ci', length=100), - type_=sa.String(length=255), - existing_nullable=True) - op.alter_column('volunteer', 'email', - existing_type=mysql.VARCHAR(length=320), - type_=sa.String(length=255), - existing_nullable=True) - op.create_foreign_key(None, 'volunteer', 'squad', ['squad_id'], ['id']) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, 'volunteer', type_='foreignkey') - op.alter_column('volunteer', 'email', - existing_type=sa.String(length=255), - type_=mysql.VARCHAR(length=320), - existing_nullable=True) - op.alter_column('volunteer', 'name', - existing_type=sa.String(length=255), - type_=mysql.VARCHAR(charset='utf8mb4', collation='utf8mb4_0900_ai_ci', length=100), - existing_nullable=True) - # ### end Alembic commands ### diff --git a/alembic/versions/280bfcafaea7_add_user_roles.py b/alembic/versions/280bfcafaea7_add_user_roles.py deleted file mode 100644 index cae9f43..0000000 --- a/alembic/versions/280bfcafaea7_add_user_roles.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add_user_roles - -Revision ID: 280bfcafaea7 -Revises: b891cb556342 -Create Date: 2026-02-18 19:22:53.135246 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '280bfcafaea7' -down_revision: Union[str, None] = 'b891cb556342' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('users', sa.Column('role', sa.Enum('ADMIN', 'HEAD', 'MENTOR', name='userrole'), nullable=False)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('users', 'role') - # ### end Alembic commands ### diff --git a/alembic/versions/42f35efc471b_add_github_to_volunteer.py b/alembic/versions/42f35efc471b_add_github_to_volunteer.py deleted file mode 100644 index 30d3598..0000000 --- a/alembic/versions/42f35efc471b_add_github_to_volunteer.py +++ /dev/null @@ -1,32 +0,0 @@ -"""add github to volunteer - -Revision ID: 42f35efc471b -Revises: 079a228ec6ed -Create Date: 2026-02-06 13:40:57.794524 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '42f35efc471b' -down_revision: Union[str, None] = '079a228ec6ed' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('volunteer', sa.Column('github', sa.String(length=255), nullable=True)) - op.create_index(op.f('ix_volunteer_github'), 'volunteer', ['github'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_volunteer_github'), table_name='volunteer') - op.drop_column('volunteer', 'github') - # ### end Alembic commands ### diff --git a/alembic/versions/468e7b292839_add_volunteer_status_and_history.py b/alembic/versions/468e7b292839_add_volunteer_status_and_history.py deleted file mode 100755 index 9950832..0000000 --- a/alembic/versions/468e7b292839_add_volunteer_status_and_history.py +++ /dev/null @@ -1,61 +0,0 @@ -"""add volunteer status and history - -Revision ID: 468e7b292839 -Revises: 50fbad971fbc -Create Date: 2025-11-25 00:27:48.564919 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision: str = '468e7b292839' -down_revision: Union[str, None] = '50fbad971fbc' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('volunteer_status', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('name', sa.String(length=50), nullable=True), - sa.Column('description', sa.String(length=255), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_index(op.f('ix_volunteer_status_name'), 'volunteer_status', ['name'], unique=True) - op.create_table('volunteer_status_history', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('volunteer_id', sa.Integer(), nullable=True), - sa.Column('status_id', sa.Integer(), nullable=True), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), - sa.ForeignKeyConstraint(['status_id'], ['volunteer_status.id'], ), - sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.alter_column('items', 'description', - existing_type=mysql.TEXT(), - type_=sa.String(length=300), - existing_nullable=True) - op.create_index(op.f('ix_items_title'), 'items', ['title'], unique=False) - op.add_column('volunteer', sa.Column('status_id', sa.Integer(), nullable=True)) - op.create_foreign_key(None, 'volunteer', 'volunteer_status', ['status_id'], ['id']) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, 'volunteer', type_='foreignkey') - op.drop_column('volunteer', 'status_id') - op.drop_index(op.f('ix_items_title'), table_name='items') - op.alter_column('items', 'description', - existing_type=sa.String(length=300), - type_=mysql.TEXT(), - existing_nullable=True) - op.drop_table('volunteer_status_history') - op.drop_index(op.f('ix_volunteer_status_name'), table_name='volunteer_status') - op.drop_table('volunteer_status') - # ### end Alembic commands ### diff --git a/alembic/versions/50fbad971fbc_add_created_at_to_volunteer.py b/alembic/versions/50fbad971fbc_add_created_at_to_volunteer.py deleted file mode 100755 index 1f67873..0000000 --- a/alembic/versions/50fbad971fbc_add_created_at_to_volunteer.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Add created_at to volunteer - -Revision ID: 50fbad971fbc -Revises: 838af0da9402 -Create Date: 2025-11-22 14:43:14.432521 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision: str = '50fbad971fbc' -down_revision: Union[str, None] = '838af0da9402' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - # op.drop_index('ix_items_description', table_name='items') - # op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True) - op.add_column('volunteer', sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True)) - op.alter_column('volunteer', 'linkedin', - existing_type=mysql.VARCHAR(length=3000), - type_=sa.String(length=255), - existing_nullable=True) - op.create_index(op.f('ix_volunteer_linkedin'), 'volunteer', ['linkedin'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_volunteer_linkedin'), table_name='volunteer') - op.alter_column('volunteer', 'linkedin', - existing_type=sa.String(length=255), - type_=mysql.VARCHAR(length=3000), - existing_nullable=True) - op.drop_column('volunteer', 'created_at') - op.drop_index(op.f('ix_users_email'), table_name='users') - op.create_index('ix_items_description', 'items', ['description'], unique=False) - # ### end Alembic commands ### diff --git a/alembic/versions/544f4a8a3a6f_add_discord_invite_sent_to_volunteer.py b/alembic/versions/544f4a8a3a6f_add_discord_invite_sent_to_volunteer.py deleted file mode 100644 index 02d1976..0000000 --- a/alembic/versions/544f4a8a3a6f_add_discord_invite_sent_to_volunteer.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add_discord_invite_sent_to_volunteer - -Revision ID: 544f4a8a3a6f -Revises: 7cf65bf6bf3f -Create Date: 2026-01-06 00:00:09.701702 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '544f4a8a3a6f' -down_revision: Union[str, None] = '7cf65bf6bf3f' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('volunteer', sa.Column('discord_invite_sent', sa.Boolean(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('volunteer', 'discord_invite_sent') - # ### end Alembic commands ### diff --git a/alembic/versions/794a393796c0_create_baseline_tables.py b/alembic/versions/794a393796c0_create_baseline_tables.py new file mode 100644 index 0000000..1f68fc1 --- /dev/null +++ b/alembic/versions/794a393796c0_create_baseline_tables.py @@ -0,0 +1,247 @@ +"""create_baseline_tables + +Revision ID: 794a393796c0 +Revises: +Create Date: 2026-06-09 15:33:23.717902 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '794a393796c0' +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('jobtitle', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(length=255), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_jobtitle_title'), 'jobtitle', ['title'], unique=False) + op.create_table('project', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=100), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('link', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_project_name'), 'project', ['name'], unique=False) + op.create_table('squad', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('description', sa.String(length=255), nullable=True), + sa.Column('discord_role_id', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_squad_name'), 'squad', ['name'], unique=True) + op.create_table('users', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('email', sa.String(length=320), nullable=True), + sa.Column('hashed_password', sa.String(length=255), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.Column('role', sa.Enum('ADMIN', 'HEAD', 'MENTOR', name='userrole'), nullable=False), + sa.Column('reset_token', sa.String(length=255), nullable=True), + sa.Column('reset_token_expires_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True) + op.create_index(op.f('ix_users_reset_token'), 'users', ['reset_token'], unique=False) + op.create_table('vertical', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('description', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_vertical_name'), 'vertical', ['name'], unique=True) + op.create_table('volunteer_status', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('description', sa.String(length=255), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_volunteer_status_name'), 'volunteer_status', ['name'], unique=True) + op.create_table('volunteer_type', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=50), nullable=True), + sa.Column('description', sa.String(length=255), nullable=True), + sa.Column('order', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_volunteer_type_name'), 'volunteer_type', ['name'], unique=True) + op.create_table('items', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(length=255), nullable=True), + sa.Column('description', sa.String(length=300), nullable=True), + sa.Column('owner_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['owner_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_items_title'), 'items', ['title'], unique=False) + op.create_table('job_opening', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(length=255), nullable=False), + sa.Column('description', sa.Text(), nullable=False), + sa.Column('requirements', sa.Text(), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('owner_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['owner_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_job_opening_title'), 'job_opening', ['title'], unique=False) + op.create_table('project_squad', + sa.Column('project_id', sa.Integer(), nullable=False), + sa.Column('squad_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['project_id'], ['project.id'], ), + sa.ForeignKeyConstraint(['squad_id'], ['squad.id'], ), + sa.PrimaryKeyConstraint('project_id', 'squad_id') + ) + op.create_table('volunteer', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=255), nullable=True), + sa.Column('linkedin', sa.String(length=255), nullable=True), + sa.Column('github', sa.String(length=255), nullable=True), + sa.Column('email', sa.String(length=255), nullable=True), + sa.Column('phone', sa.String(length=30), nullable=True), + sa.Column('discord', sa.String(length=255), nullable=True), + sa.Column('discord_invite_sent', sa.Boolean(), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.Column('is_apoiase_supporter', sa.Boolean(), nullable=True), + sa.Column('jobtitle_id', sa.Integer(), nullable=True), + sa.Column('status_id', sa.Integer(), nullable=True), + sa.Column('volunteer_type_id', sa.Integer(), nullable=True), + sa.Column('squad_id', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('edit_token', sa.String(length=255), nullable=True), + sa.Column('edit_token_expires_at', sa.DateTime(), nullable=True), + sa.Column('daily_edits_count', sa.Integer(), nullable=True), + sa.Column('last_edit_date', sa.Date(), nullable=True), + sa.ForeignKeyConstraint(['jobtitle_id'], ['jobtitle.id'], ), + sa.ForeignKeyConstraint(['squad_id'], ['squad.id'], ), + sa.ForeignKeyConstraint(['status_id'], ['volunteer_status.id'], ), + sa.ForeignKeyConstraint(['volunteer_type_id'], ['volunteer_type.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_volunteer_edit_token'), 'volunteer', ['edit_token'], unique=False) + op.create_index(op.f('ix_volunteer_email'), 'volunteer', ['email'], unique=False) + op.create_index(op.f('ix_volunteer_github'), 'volunteer', ['github'], unique=False) + op.create_index(op.f('ix_volunteer_linkedin'), 'volunteer', ['linkedin'], unique=False) + op.create_index(op.f('ix_volunteer_name'), 'volunteer', ['name'], unique=False) + op.create_table('badges', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(length=255), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('volunteer_id', sa.Integer(), nullable=False), + sa.Column('issuer_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['issuer_id'], ['users.id'], ), + sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_badges_id'), 'badges', ['id'], unique=False) + op.create_table('certificates', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('volunteer_id', sa.Integer(), nullable=False), + sa.Column('hours', sa.Integer(), nullable=False), + sa.Column('issued_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('is_cancelled', sa.Boolean(), nullable=True), + sa.Column('certificate_type', sa.String(length=50), nullable=True), + sa.Column('issuer_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['issuer_id'], ['users.id'], ), + sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('feedbacks', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('content', sa.Text(), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('volunteer_id', sa.Integer(), nullable=False), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_feedbacks_id'), 'feedbacks', ['id'], unique=False) + op.create_table('job_application', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('job_id', sa.Integer(), nullable=True), + sa.Column('volunteer_id', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.ForeignKeyConstraint(['job_id'], ['job_opening.id'], ), + sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('mentor_mentee', + sa.Column('mentor_id', sa.Integer(), nullable=False), + sa.Column('mentee_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['mentee_id'], ['volunteer.id'], ), + sa.ForeignKeyConstraint(['mentor_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('mentor_id', 'mentee_id') + ) + op.create_table('volunteer_status_history', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('volunteer_id', sa.Integer(), nullable=True), + sa.Column('status_id', sa.Integer(), nullable=True), + sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True), + sa.ForeignKeyConstraint(['status_id'], ['volunteer_status.id'], ), + sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('volunteer_vertical', + sa.Column('volunteer_id', sa.Integer(), nullable=False), + sa.Column('vertical_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['vertical_id'], ['vertical.id'], ), + sa.ForeignKeyConstraint(['volunteer_id'], ['volunteer.id'], ), + sa.PrimaryKeyConstraint('volunteer_id', 'vertical_id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('volunteer_vertical') + op.drop_table('volunteer_status_history') + op.drop_table('mentor_mentee') + op.drop_table('job_application') + op.drop_index(op.f('ix_feedbacks_id'), table_name='feedbacks') + op.drop_table('feedbacks') + op.drop_table('certificates') + op.drop_index(op.f('ix_badges_id'), table_name='badges') + op.drop_table('badges') + op.drop_index(op.f('ix_volunteer_name'), table_name='volunteer') + op.drop_index(op.f('ix_volunteer_linkedin'), table_name='volunteer') + op.drop_index(op.f('ix_volunteer_github'), table_name='volunteer') + op.drop_index(op.f('ix_volunteer_email'), table_name='volunteer') + op.drop_index(op.f('ix_volunteer_edit_token'), table_name='volunteer') + op.drop_table('volunteer') + op.drop_table('project_squad') + op.drop_index(op.f('ix_job_opening_title'), table_name='job_opening') + op.drop_table('job_opening') + op.drop_index(op.f('ix_items_title'), table_name='items') + op.drop_table('items') + op.drop_index(op.f('ix_volunteer_type_name'), table_name='volunteer_type') + op.drop_table('volunteer_type') + op.drop_index(op.f('ix_volunteer_status_name'), table_name='volunteer_status') + op.drop_table('volunteer_status') + op.drop_index(op.f('ix_vertical_name'), table_name='vertical') + op.drop_table('vertical') + op.drop_index(op.f('ix_users_reset_token'), table_name='users') + op.drop_index(op.f('ix_users_email'), table_name='users') + op.drop_table('users') + op.drop_index(op.f('ix_squad_name'), table_name='squad') + op.drop_table('squad') + op.drop_index(op.f('ix_project_name'), table_name='project') + op.drop_table('project') + op.drop_index(op.f('ix_jobtitle_title'), table_name='jobtitle') + op.drop_table('jobtitle') + # ### end Alembic commands ### diff --git a/alembic/versions/7cf65bf6bf3f_add_volunteer_types.py b/alembic/versions/7cf65bf6bf3f_add_volunteer_types.py deleted file mode 100755 index e0bca6c..0000000 --- a/alembic/versions/7cf65bf6bf3f_add_volunteer_types.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Add volunteer types - -Revision ID: 7cf65bf6bf3f -Revises: 03fa6dddb4dc -Create Date: 2025-12-14 17:50:57.474552 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '7cf65bf6bf3f' -down_revision: Union[str, None] = '03fa6dddb4dc' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - # op.create_table( - # 'volunteer_type', - # sa.Column('id', sa.Integer(), nullable=False), - # sa.Column('name', sa.String(length=50), nullable=False), - # sa.Column('description', sa.String(length=255), nullable=True), - # sa.PrimaryKeyConstraint('id'), - # sa.UniqueConstraint('name') - # ) - # op.create_index(op.f('ix_volunteer_type_name'), 'volunteer_type', ['name'], unique=True) - - op.bulk_insert( - sa.Table( - 'volunteer_type', - sa.MetaData(), - sa.Column('id', sa.Integer(), primary_key=True), - sa.Column('name', sa.String(length=50)), - sa.Column('description', sa.String(length=255)), - ), - [ - {'id': 1, 'name': 'Junior', 'description': 'Volunteer with basic experience'}, - {'id': 2, 'name': 'Mentor', 'description': 'Experienced volunteer guiding others'}, - {'id': 3, 'name': 'Apoiador', 'description': 'Supporter volunteer'} - ] - ) - op.add_column('volunteer', sa.Column('volunteer_type_id', sa.Integer(), nullable=True)) - op.create_foreign_key(None, 'volunteer', 'volunteer_type', ['volunteer_type_id'], ['id']) - - # Update existing volunteers to default 'Junior' type - op.execute("UPDATE volunteer SET volunteer_type_id = 1 WHERE volunteer_type_id IS NULL") - - # Make column not nullable - # op.alter_column('volunteer', 'volunteer_type_id', existing_type=sa.Integer(), nullable=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, 'volunteer', type_='foreignkey') - op.drop_column('volunteer', 'volunteer_type_id') - op.drop_index(op.f('ix_volunteer_type_name'), table_name='volunteer_type') - op.drop_table('volunteer_type') - # ### end Alembic commands ### diff --git a/alembic/versions/838af0da9402_create_a_baseline_migrations.py b/alembic/versions/838af0da9402_create_a_baseline_migrations.py deleted file mode 100755 index 4cf11fd..0000000 --- a/alembic/versions/838af0da9402_create_a_baseline_migrations.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Create a baseline migrations - -Revision ID: 838af0da9402 -Revises: -Create Date: 2024-05-07 10:26:26.486498 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision: str = '838af0da9402' -down_revision: Union[str, None] = None -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - pass - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('volunteer', - sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False), - sa.Column('name', mysql.VARCHAR(length=45), nullable=True), - sa.Column('linkedin', mysql.VARCHAR(length=3072), nullable=True), - sa.Column('email', mysql.VARCHAR(length=320), nullable=True), - sa.Column('is_active', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True), - sa.Column('jobtitle_id', mysql.INTEGER(), autoincrement=False, nullable=True), - sa.ForeignKeyConstraint(['jobtitle_id'], ['jobtitle.id'], name='volunteer_ibfk_1'), - sa.PrimaryKeyConstraint('id'), - mysql_collate='utf8mb4_0900_ai_ci', - mysql_default_charset='utf8mb4', - mysql_engine='InnoDB' - ) - op.create_index('ix_volunteer_name', 'volunteer', ['name'], unique=False) - op.create_table('items', - sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False), - sa.Column('title', mysql.VARCHAR(length=255), nullable=True), - sa.Column('description', mysql.TEXT(), nullable=True), - sa.Column('owner_id', mysql.INTEGER(), autoincrement=False, nullable=True), - sa.ForeignKeyConstraint(['owner_id'], ['users.id'], name='items_ibfk_1'), - sa.PrimaryKeyConstraint('id'), - mysql_collate='utf8mb4_0900_ai_ci', - mysql_default_charset='utf8mb4', - mysql_engine='InnoDB' - ) - op.create_table('jobtitle', - sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False), - sa.Column('title', mysql.VARCHAR(length=255), nullable=True), - sa.Column('is_active', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True), - sa.PrimaryKeyConstraint('id'), - mysql_collate='utf8mb4_0900_ai_ci', - mysql_default_charset='utf8mb4', - mysql_engine='InnoDB' - ) - op.create_index('ix_jobtitle_title', 'jobtitle', ['title'], unique=False) - op.create_table('users', - sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False), - sa.Column('email', mysql.VARCHAR(length=320), nullable=True), - sa.Column('hashed_password', mysql.VARCHAR(length=255), nullable=True), - sa.Column('is_active', mysql.TINYINT(display_width=1), autoincrement=False, nullable=True), - sa.PrimaryKeyConstraint('id'), - mysql_collate='utf8mb4_0900_ai_ci', - mysql_default_charset='utf8mb4', - mysql_engine='InnoDB' - ) - op.create_index('ix_users_email', 'users', ['email'], unique=True) - # ### end Alembic commands ### diff --git a/alembic/versions/842ae7994682_add_discord_to_volunteer.py b/alembic/versions/842ae7994682_add_discord_to_volunteer.py deleted file mode 100755 index 40345b5..0000000 --- a/alembic/versions/842ae7994682_add_discord_to_volunteer.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add_discord_to_volunteer - -Revision ID: 842ae7994682 -Revises: 1a8b326c7c3d -Create Date: 2025-12-09 18:10:09.947931 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '842ae7994682' -down_revision: Union[str, None] = '1a8b326c7c3d' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('volunteer', sa.Column('discord', sa.String(length=255), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('volunteer', 'discord') - # ### end Alembic commands ### diff --git a/alembic/versions/885ee5c8b30c_add_badges_model.py b/alembic/versions/885ee5c8b30c_add_badges_model.py deleted file mode 100644 index ad140af..0000000 --- a/alembic/versions/885ee5c8b30c_add_badges_model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add badges model - -Revision ID: 885ee5c8b30c -Revises: 280bfcafaea7 -Create Date: 2026-02-20 01:24:26.376210 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '885ee5c8b30c' -down_revision: Union[str, None] = '280bfcafaea7' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/alembic/versions/8fb47fe0135f_add_is_apoiase_supporter.py b/alembic/versions/8fb47fe0135f_add_is_apoiase_supporter.py deleted file mode 100644 index e29800a..0000000 --- a/alembic/versions/8fb47fe0135f_add_is_apoiase_supporter.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add_is_apoiase_supporter - -Revision ID: 8fb47fe0135f -Revises: 544f4a8a3a6f -Create Date: 2026-01-09 14:10:58.939692 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '8fb47fe0135f' -down_revision: Union[str, None] = '544f4a8a3a6f' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('volunteer', sa.Column('is_apoiase_supporter', sa.Boolean(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('volunteer', 'is_apoiase_supporter') - # ### end Alembic commands ### diff --git a/alembic/versions/9c3cd5955758_add_initial_volunteer_statuses.py b/alembic/versions/9c3cd5955758_add_initial_volunteer_statuses.py deleted file mode 100755 index 6244950..0000000 --- a/alembic/versions/9c3cd5955758_add_initial_volunteer_statuses.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Add initial volunteer statuses - -Revision ID: 9c3cd5955758 -Revises: 468e7b292839 -Create Date: 2025-12-04 11:35:10.639603 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision: str = '9c3cd5955758' -down_revision: Union[str, None] = '468e7b292839' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.bulk_insert( - sa.Table( - 'volunteer_status', - sa.MetaData(), - sa.Column('id', sa.Integer), - sa.Column('name', sa.String), - sa.Column('description', sa.String), - ), - [ - {'name': 'INTERESTED', 'description': 'Volunteer expressed interest.'}, - {'name': 'CONTACTED', 'description': 'Volunteer has been contacted.'}, - {'name': 'SCREENING', 'description': 'Volunteer is undergoing screening.'}, - {'name': 'ACTIVE', 'description': 'Volunteer is active.'}, - {'name': 'INACTIVE', 'description': 'Volunteer is inactive.'}, - ] - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.execute("DELETE FROM volunteer_status WHERE name IN ('INTERESTED', 'CONTACTED', 'SCREENING', 'ACTIVE', 'INACTIVE')") - # ### end Alembic commands ### diff --git a/alembic/versions/9d6e1bd86f06_add_description_to_squad.py b/alembic/versions/9d6e1bd86f06_add_description_to_squad.py deleted file mode 100644 index 805aebc..0000000 --- a/alembic/versions/9d6e1bd86f06_add_description_to_squad.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add description to squad - -Revision ID: 9d6e1bd86f06 -Revises: acafbc8a9999 -Create Date: 2026-01-28 13:10:45.538298 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = '9d6e1bd86f06' -down_revision: Union[str, None] = 'acafbc8a9999' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('squad', sa.Column('description', sa.String(length=255), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('squad', 'description') - # ### end Alembic commands ### diff --git a/alembic/versions/a48937e1e488_add_referral_and_terms_fields_to_.py b/alembic/versions/a48937e1e488_add_referral_and_terms_fields_to_.py new file mode 100644 index 0000000..cce8253 --- /dev/null +++ b/alembic/versions/a48937e1e488_add_referral_and_terms_fields_to_.py @@ -0,0 +1,40 @@ +"""add_referral_and_terms_fields_to_volunteer + +Revision ID: a48937e1e488 +Revises: 794a393796c0 +Create Date: 2026-06-12 17:03:41.340921 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'a48937e1e488' +down_revision: Union[str, None] = '794a393796c0' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('volunteer', sa.Column('bio', sa.Text(), nullable=True)) + op.add_column('volunteer', sa.Column('referred_by_name', sa.String(length=255), nullable=True)) + op.add_column('volunteer', sa.Column('referred_by_position', sa.String(length=255), nullable=True)) + op.add_column('volunteer', sa.Column('referred_by_linkedin', sa.String(length=255), nullable=True)) + op.add_column('volunteer', sa.Column('terms_accepted', sa.Boolean(), nullable=False)) + op.add_column('volunteer', sa.Column('acceptance_date', sa.DateTime(timezone=True), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('volunteer', 'acceptance_date') + op.drop_column('volunteer', 'terms_accepted') + op.drop_column('volunteer', 'referred_by_linkedin') + op.drop_column('volunteer', 'referred_by_position') + op.drop_column('volunteer', 'referred_by_name') + op.drop_column('volunteer', 'bio') + # ### end Alembic commands ### diff --git a/alembic/versions/a74a653cbf11_add_volunteer_edit_tracking.py b/alembic/versions/a74a653cbf11_add_volunteer_edit_tracking.py deleted file mode 100755 index 8abb8b8..0000000 --- a/alembic/versions/a74a653cbf11_add_volunteer_edit_tracking.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Add volunteer edit tracking - -Revision ID: a74a653cbf11 -Revises: 842ae7994682 -Create Date: 2025-12-12 00:36:38.200336 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'a74a653cbf11' -down_revision: Union[str, None] = '842ae7994682' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('volunteer', sa.Column('edit_token', sa.String(length=255), nullable=True)) - op.add_column('volunteer', sa.Column('edit_token_expires_at', sa.DateTime(), nullable=True)) - op.add_column('volunteer', sa.Column('daily_edits_count', sa.Integer(), nullable=True)) - op.add_column('volunteer', sa.Column('last_edit_date', sa.Date(), nullable=True)) - op.create_index(op.f('ix_volunteer_edit_token'), 'volunteer', ['edit_token'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_volunteer_edit_token'), table_name='volunteer') - op.drop_column('volunteer', 'last_edit_date') - op.drop_column('volunteer', 'daily_edits_count') - op.drop_column('volunteer', 'edit_token_expires_at') - op.drop_column('volunteer', 'edit_token') - # ### end Alembic commands ### diff --git a/alembic/versions/a879d6c0610f_add_password_reset_fields_to_user.py b/alembic/versions/a879d6c0610f_add_password_reset_fields_to_user.py deleted file mode 100644 index 9db00d8..0000000 --- a/alembic/versions/a879d6c0610f_add_password_reset_fields_to_user.py +++ /dev/null @@ -1,34 +0,0 @@ -"""add password reset fields to user - -Revision ID: a879d6c0610f -Revises: e9463ebe5b56 -Create Date: 2026-03-03 18:56:50.600252 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'a879d6c0610f' -down_revision: Union[str, None] = 'e9463ebe5b56' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('users', sa.Column('reset_token', sa.String(length=255), nullable=True)) - op.add_column('users', sa.Column('reset_token_expires_at', sa.DateTime(), nullable=True)) - op.create_index(op.f('ix_users_reset_token'), 'users', ['reset_token'], unique=False) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_users_reset_token'), table_name='users') - op.drop_column('users', 'reset_token_expires_at') - op.drop_column('users', 'reset_token') - # ### end Alembic commands ### diff --git a/alembic/versions/acafbc8a9999_add_feedback_model.py b/alembic/versions/acafbc8a9999_add_feedback_model.py deleted file mode 100644 index 200f4af..0000000 --- a/alembic/versions/acafbc8a9999_add_feedback_model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Add Feedback model - -Revision ID: acafbc8a9999 -Revises: 8fb47fe0135f -Create Date: 2026-01-13 17:50:40.255395 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'acafbc8a9999' -down_revision: Union[str, None] = '8fb47fe0135f' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/alembic/versions/b48a3d6f234e_add_phone_to_volunteer.py b/alembic/versions/b48a3d6f234e_add_phone_to_volunteer.py deleted file mode 100755 index 2235272..0000000 --- a/alembic/versions/b48a3d6f234e_add_phone_to_volunteer.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add phone to volunteer - -Revision ID: b48a3d6f234e -Revises: 9c3cd5955758 -Create Date: 2025-12-08 13:52:34.259987 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -from sqlalchemy.dialects import mysql - -# revision identifiers, used by Alembic. -revision: str = 'b48a3d6f234e' -down_revision: Union[str, None] = '9c3cd5955758' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('volunteer', 'phone') - # ### end Alembic commands ### diff --git a/alembic/versions/b891cb556342_add_certificate_model.py b/alembic/versions/b891cb556342_add_certificate_model.py deleted file mode 100644 index 76b227a..0000000 --- a/alembic/versions/b891cb556342_add_certificate_model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add_certificate_model - -Revision ID: b891cb556342 -Revises: fe37356bc2ec -Create Date: 2026-02-17 17:42:56.422478 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'b891cb556342' -down_revision: Union[str, None] = 'fe37356bc2ec' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/alembic/versions/df42d3b4b6a5_add_jobopening_and_jobapplication.py b/alembic/versions/df42d3b4b6a5_add_jobopening_and_jobapplication.py deleted file mode 100644 index 29ec18f..0000000 --- a/alembic/versions/df42d3b4b6a5_add_jobopening_and_jobapplication.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Add JobOpening and JobApplication - -Revision ID: df42d3b4b6a5 -Revises: 9d6e1bd86f06 -Create Date: 2026-01-30 18:31:41.939893 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'df42d3b4b6a5' -down_revision: Union[str, None] = '9d6e1bd86f06' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/alembic/versions/e9463ebe5b56_add_mentor_mentee_relationship.py b/alembic/versions/e9463ebe5b56_add_mentor_mentee_relationship.py deleted file mode 100644 index 3b5828b..0000000 --- a/alembic/versions/e9463ebe5b56_add_mentor_mentee_relationship.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Add mentor_mentee relationship - -Revision ID: e9463ebe5b56 -Revises: 885ee5c8b30c -Create Date: 2026-02-24 16:44:14.918570 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'e9463ebe5b56' -down_revision: Union[str, None] = '885ee5c8b30c' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('mentor_mentee', - sa.Column('mentor_id', sa.Integer(), nullable=False), - sa.Column('mentee_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['mentee_id'], ['volunteer.id'], ), - sa.ForeignKeyConstraint(['mentor_id'], ['volunteer.id'], ), - sa.PrimaryKeyConstraint('mentor_id', 'mentee_id') - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('mentor_mentee') - # ### end Alembic commands ### diff --git a/alembic/versions/f88261e5dc27_add_vertical_model.py b/alembic/versions/f88261e5dc27_add_vertical_model.py deleted file mode 100644 index 48b8f80..0000000 --- a/alembic/versions/f88261e5dc27_add_vertical_model.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Add Vertical model - -Revision ID: f88261e5dc27 -Revises: 42f35efc471b -Create Date: 2026-02-09 14:11:42.171240 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'f88261e5dc27' -down_revision: Union[str, None] = '42f35efc471b' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - pass - # ### end Alembic commands ### diff --git a/alembic/versions/fe37356bc2ec_add_order_to_volunteer_type.py b/alembic/versions/fe37356bc2ec_add_order_to_volunteer_type.py deleted file mode 100644 index 8dc5755..0000000 --- a/alembic/versions/fe37356bc2ec_add_order_to_volunteer_type.py +++ /dev/null @@ -1,30 +0,0 @@ -"""add order to volunteer_type - -Revision ID: fe37356bc2ec -Revises: f88261e5dc27 -Create Date: 2026-02-15 14:09:34.674184 - -""" -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision: str = 'fe37356bc2ec' -down_revision: Union[str, None] = 'f88261e5dc27' -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('volunteer_type', sa.Column('order', sa.Integer(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('volunteer_type', 'order') - # ### end Alembic commands ### diff --git a/app/database.py b/app/database.py index 9962aec..8388a6d 100644 --- a/app/database.py +++ b/app/database.py @@ -4,7 +4,6 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from .settings import settings -from app import models SQLALCHEMY_DATABASE_URL = ( diff --git a/app/models.py b/app/models.py index f568995..0d8f8eb 100644 --- a/app/models.py +++ b/app/models.py @@ -150,6 +150,12 @@ class Volunteer(Base): volunteer_type_id = Column(Integer, ForeignKey("volunteer_type.id"), nullable=True) squad_id = Column(Integer, ForeignKey("squad.id"), nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) + bio = Column(Text, nullable=True) # Text ára biografia do voluntário + referred_by_name = Column(String(255), nullable=True) + referred_by_position = Column(String(255), nullable=True) + referred_by_linkedin = Column(String(255), nullable=True) + terms_accepted = Column(Boolean, default=False, nullable=False) + acceptance_date = Column(DateTime(timezone=True), nullable=True) jobtitle = relationship("JobTitle", back_populates="volunteers") status = relationship("VolunteerStatus", back_populates="volunteers") From 9297345e7e6e0d3e3845b04b9cd593a81bed40cd Mon Sep 17 00:00:00 2001 From: edu Date: Fri, 12 Jun 2026 17:35:18 -0300 Subject: [PATCH 3/7] feat: update volunteer schemas with referral and terms fields --- app/schemas.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/schemas.py b/app/schemas.py index 2cd77b6..538676f 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -184,6 +184,13 @@ class VolunteerBase(VolunteerCommon): phone: Optional[str] = Field(None, max_length=30) discord: Optional[str] = Field(None, max_length=255) email: str = Field(..., max_length=255) + + #novos campos US 6 + bio: Optional[str] = None + referred_by_name: Optional[str] = Field(None, max_length=255) + referred_by_position: Optional[str] = Field(None, max_length=255) + referred_by_linkedin: Optional[str] = Field(None, max_length=255) + terms_accepted: Optional[bool] = False class VolunteerCreate(VolunteerBase): # name: str @@ -301,6 +308,8 @@ class VolunteerPublic(VolunteerCommon): badges: list[BadgeRead] = [] mentees: list[VolunteerShort] = [] mentors: list[VolunteerShort] = [] + acceptance_date: Optional[datetime] = None + class Config: orm_mode = True @@ -318,6 +327,7 @@ class VolunteerList(VolunteerBase): status: Optional[VolunteerStatus] = None volunteer_type: Optional[VolunteerType] = None squad: Optional['Squad'] = None + acceptance_date: Optional[datetime] = None class Config: orm_mode = True From 005ebd19e201dd891463b597fc5a9a44745fbd3b Mon Sep 17 00:00:00 2001 From: edu Date: Fri, 12 Jun 2026 17:47:37 -0300 Subject: [PATCH 4/7] feat: add strict validations and regex for referral fields in schemas --- app/schemas.py | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/app/schemas.py b/app/schemas.py index 538676f..71a5796 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -1,4 +1,6 @@ -from pydantic import BaseModel, Field +import re + +from pydantic import BaseModel, Field, validator from typing import Optional, Union from datetime import datetime import enum @@ -187,10 +189,46 @@ class VolunteerBase(VolunteerCommon): #novos campos US 6 bio: Optional[str] = None - referred_by_name: Optional[str] = Field(None, max_length=255) - referred_by_position: Optional[str] = Field(None, max_length=255) - referred_by_linkedin: Optional[str] = Field(None, max_length=255) + referred_by_name: Optional[str] = Field(None, max_length=100) + referred_by_position: Optional[str] = Field(None, max_length=100) + referred_by_linkedin: Optional[str] = Field(None, max_length=150) terms_accepted: Optional[bool] = False + + # 1 VALIDAÇÃO: Nome de quem indicou (Alfanumérico + Acentos + Espaços) + @validator('referred_by_name') + def validate_referred_name(cls, v): + if v: + # Regex que permite letras (com acentos), números e espaços. Bloqueia @, #, $, etc. + if not re.match(r"^[a-zA-Z0-9áéíóúâêîôûãõçÁÉÍÓÚÂÊÎÔÛÃÕÇ\s]+$", v): + raise ValueError("O nome não deve conter caracteres especiais") + return v + + # 2 VALIDAÇÃO: Cargo de quem indicou (Alfanumérico + Acentos + Espaços) + @validator('referred_by_position') + def validate_referred_position(cls, v): + if v: + if not re.match(r"^[a-zA-Z0-9áéíóúâêîôûãõçÁÉÍÓÚÂÊÎÔÛÃÕÇ\s]+$", v): + raise ValueError("O cargo não deve conter caracteres especiais") + return v + + # 3 VALIDAÇÃO CONJUNTA: Se houver indicação, Nome e LinkedIn são obrigatórios e valida o /in/ + @validator('referred_by_linkedin') + def validate_linkedin_and_dependency(cls, v, values): + referred_name = values.get('referred_by_name') + + # Se preencheu o nome de quem indicou, o LinkedIn se torna obrigatório + if referred_name and not v: + raise ValueError("O LinkedIn da indicação é obrigatório quando há uma indicação") + + if v: + # Não permite espaços + if " " in v: + raise ValueError("O link do LinkedIn não deve conter espaços") + # Garante que possui o caminho de perfil pessoal (/in/) + if "/in/" not in v: + raise ValueError("Digite um link válido do LinkedIn (deve conter /in/)") + + return v class VolunteerCreate(VolunteerBase): # name: str From eaba50f11a953f0bf0b149d2e583d99cb4c952de Mon Sep 17 00:00:00 2001 From: edu Date: Fri, 12 Jun 2026 17:49:45 -0300 Subject: [PATCH 5/7] feat: implement timestamping logic for terms acceptance in volunteer crud --- app/crud.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/crud.py b/app/crud.py index 6aa4d0b..9c8239e 100644 --- a/app/crud.py +++ b/app/crud.py @@ -119,6 +119,11 @@ def create_volunteer(db: Session, volunteer: schemas.VolunteerCreate, jobtitle_i db_volunteer = models.Volunteer(**volunteer.dict(exclude_unset=True, exclude={'vertical_ids'})) # Ensure jobtitle_id is set if it wasn't in the dict (though schema says it is required) + + # Set acceptance_date if terms are accepted at creation time #US6 + if db_volunteer.terms_accepted: + db_volunteer.acceptance_date = datetime.now() + if not db_volunteer.jobtitle_id: db_volunteer.jobtitle_id = jobtitle_id From 7019a1ca2c4082f9ead588927427e37fd279783c Mon Sep 17 00:00:00 2001 From: edu Date: Fri, 12 Jun 2026 17:58:06 -0300 Subject: [PATCH 6/7] chore: restore requirements.txt to match upstream develop standard --- requirements.txt | 3 +- requirements_lock.txt | 123 ++++++++++++++++++++++++++++++------------ 2 files changed, 89 insertions(+), 37 deletions(-) diff --git a/requirements.txt b/requirements.txt index 925fb89..79e1ab6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,5 +33,4 @@ urllib3==2.2.3 uvicorn==0.31.1 wheel==0.44.0 pytest -httpx - +httpx \ No newline at end of file diff --git a/requirements_lock.txt b/requirements_lock.txt index 925fb89..bff5683 100644 --- a/requirements_lock.txt +++ b/requirements_lock.txt @@ -1,37 +1,90 @@ -alembic==1.13.3 -annotated-types==0.7.0 -anyio==4.6.2.post1 -asgiref==3.8.1 -certifi==2024.8.30 -click==8.1.7 -ecdsa==0.19.0 -fastapi==0.115.2 -greenlet==3.1.1 -h11==0.14.0 +asn1crypto==1.5.1 +autocommand==2.2.2 +bcc==0.30.0 +bcrypt==4.2.0 +beautifulsoup4==4.13.3 +blinker==1.9.0 +certifi==2025.1.31 +chardet==5.2.0 +click==8.1.8 +command-not-found==0.3 +cryptography==43.0.0 +cssselect==1.3.0 +cupshelpers==1.0 +dbus-python==1.3.2 +distro==1.9.0 +distro-info==1.13 +fuse-python==1.0.9 +gyp-next==0.16.2 +html5lib-modern==1.2 +httplib2==0.22.0 idna==3.10 -Mako==1.3.5 -MarkupSafe==3.0.1 -mysql-connector-python==9.0.0 -passlib==1.7.4 -pyasn1==0.6.1 -pydantic==2.9.2 -pydantic-settings==2.5.2 -pydantic_core==2.23.4 -python-dateutil==2.9.0.post0 -python-dotenv==1.0.1 -python-jose==3.3.0 -python-multipart==0.0.12 -rsa==4.9 -setuptools==75.1.0 -sib-api-v3-sdk==7.6.0 -six==1.16.0 -sniffio==1.3.1 -SQLAlchemy==2.0.35 -starlette==0.39.2 +importlib_metadata==8.6.1 +inflect==7.3.1 +jaraco.classes==3.4.0 +jaraco.context==6.0.1 +jaraco.functools==4.1.0 +jeepney==0.8.0 +keyring==25.6.0 +language-selector==0.1 +launchpadlib==2.1.0 +lazr.restfulclient==0.14.6 +lazr.uri==1.0.6 +lxml==5.3.2 +markdown-it-py==3.0.0 +mdurl==0.1.2 +mechanize==0.4.10 +more-itertools==10.6.0 +mutagen==1.47.0 +netaddr==1.3.0 +netifaces==0.11.0 +numpy==2.2.3 +oauthlib==3.2.2 +olefile==0.47 +osc==1.12.1 +packaging==24.2 +pexpect==4.9.0 +pillow==11.1.0 +psutil==5.9.8 +ptyprocess==0.7.0 +pycairo==1.27.0 +pycryptodomex==3.20.0 +pycups==2.0.4 +Pygments==2.18.0 +PyGObject==3.50.0 +PyJWT==2.10.1 +pylibacl==0.7.2 +pyparsing==3.1.2 +PyQt6==6.8.1 +PyQt6_sip==13.10.0 +python-apt==3.0.0 +python-debian==1.0.1+ubuntu1 +pyxattr==0.8.1 +PyYAML==6.0.2 +requests==2.32.3 +rich==13.9.4 +rpm==4.20.1 +ruamel.yaml==0.18.10 +ruamel.yaml.clib==0.2.12 +scour==0.38.2 +SecretStorage==3.3.3 +sentry-sdk==2.18.0 +soupsieve==2.6 +systemd-python==235 +tornado==6.4.2 +typeguard==4.4.2 typing_extensions==4.12.2 -urllib3==2.2.3 -uvicorn==0.31.1 -wheel==0.44.0 -pytest -httpx - +ubuntu-drivers-common==0.0.0 +ubuntu-pro-client==8001 +ufw==0.36.2 +unattended-upgrades==0.1 +urllib3==2.3.0 +usb-creator==0.3.16 +wadllib==2.0.0 +webencodings==0.5.1 +websocket-client==1.8.0 +websockets==14.1 +wheel==0.45.1 +xkit==0.0.0 +yt-dlp==2025.3.27 +zipp==3.21.0 \ No newline at end of file From 0cfe4a358111c012d2fd63f597b66d370418cb55 Mon Sep 17 00:00:00 2001 From: edu Date: Fri, 19 Jun 2026 11:07:17 -0300 Subject: [PATCH 7/7] feat: implement tech stack storage and fix volunteer registration fields --- app/crud.py | 24 +++++++++++++++++++++--- app/main.py | 1 + app/models.py | 11 +++++++++++ app/schemas.py | 3 +++ docker-compose.yml | 30 +++++++++++++++--------------- 5 files changed, 51 insertions(+), 18 deletions(-) diff --git a/app/crud.py b/app/crud.py index 10cf216..762ba8a 100644 --- a/app/crud.py +++ b/app/crud.py @@ -117,7 +117,7 @@ def create_volunteer(db: Session, volunteer: schemas.VolunteerCreate, jobtitle_i # Extract vertical_ids before creating the model vertical_ids = volunteer.vertical_ids or [] - db_volunteer = models.Volunteer(**volunteer.dict(exclude_unset=True, exclude={'vertical_ids'})) + db_volunteer = models.Volunteer(**volunteer.dict(exclude_unset=True, exclude={'vertical_ids', 'techs_frontend', 'techs_backend'})) # Ensure jobtitle_id is set if it wasn't in the dict (though schema says it is required) # Set acceptance_date if terms are accepted at creation time #US6 @@ -138,8 +138,26 @@ def create_volunteer(db: Session, volunteer: schemas.VolunteerCreate, jobtitle_i if vertical_ids: verticals = db.query(models.Vertical).filter(models.Vertical.id.in_(vertical_ids)).all() db_volunteer.verticals = verticals - db.commit() - db.refresh(db_volunteer) + + # Persistir techs frontend + for tech in volunteer.techs_frontend: + db.add(models.VolunteerTech( + volunteer_id=db_volunteer.id, + area="frontend", + tech=tech + )) + + # Persistir techs backend + for tech in volunteer.techs_backend: + db.add(models.VolunteerTech( + volunteer_id=db_volunteer.id, + area="backend", + tech=tech + )) + + + db.commit() + db.refresh(db_volunteer) # Add initial status to history status_history_entry = models.VolunteerStatusHistory( diff --git a/app/main.py b/app/main.py index d32bd0b..05ddc7c 100644 --- a/app/main.py +++ b/app/main.py @@ -33,6 +33,7 @@ async def health_check(): origins = [ "http://localhost", "http://localhost:5173", + "http://localhost:5174", "http://localhost:8080", "https://stars.soujunior.tech", ] diff --git a/app/models.py b/app/models.py index d78558d..2402021 100644 --- a/app/models.py +++ b/app/models.py @@ -154,6 +154,7 @@ class Volunteer(Base): name = Column(String(255), index=True) linkedin = Column(String(255), index=True) github = Column(String(255), index=True, nullable=True) + techs = relationship("VolunteerTech", backref="volunteer", cascade="all, delete-orphan") email = Column(String(255), index=True) phone = Column(String(30)) discord = Column(String(255), nullable=True) @@ -171,6 +172,7 @@ class Volunteer(Base): referred_by_linkedin = Column(String(255), nullable=True) terms_accepted = Column(Boolean, default=False, nullable=False) acceptance_date = Column(DateTime(timezone=True), nullable=True) + jobtitle = relationship("JobTitle", back_populates="volunteers") status = relationship("VolunteerStatus", back_populates="volunteers") @@ -207,6 +209,15 @@ def masked_email(self): parts = self.email.split('@') return '***@' + parts[1] return self.email # Or return None if preferred for invalid emails + +class VolunteerTech(Base): #nova tabela para armazenar as tecnologias dos voluntários + __tablename__ = "volunteer_tech" + + id = Column(Integer, primary_key=True, autoincrement=True) + volunteer_id = Column(Integer, ForeignKey("volunteer.id", ondelete="CASCADE"), nullable=False) + area = Column(Enum("frontend", "backend"), nullable=False) + tech = Column(String(100), nullable=False) + class VolunteerStatusHistory(Base): diff --git a/app/schemas.py b/app/schemas.py index 35fa51d..3e5f3ab 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -259,11 +259,14 @@ class VolunteerCreate(VolunteerBase): # name: str # email: str # masked_email: Optional[str] = None + techs_frontend: list[str] = [] + techs_backend: list[str] = [] is_active: Optional[bool] = True jobtitle_id: int volunteer_type_id: Optional[int] = None squad_id: Optional[int] = None vertical_ids: Optional[list[int]] = None + class FeedbackBase(BaseModel): content: str diff --git a/docker-compose.yml b/docker-compose.yml index 3880bcf..de1fb01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,19 +13,19 @@ services: depends_on: - mysql_database - mysql_database: - image: mysql:8.3 - container_name: mysql_stars - restart: unless-stopped - command: --default-authentication-plugin=caching_sha2_password - environment: - MYSQL_DATABASE: 'stars' - MYSQL_ROOT_PASSWORD: 'root' # Define a senha diretamente para o usuário root padrão - ports: - - '3306:3306' - volumes: - - mysql_database:/var/lib/mysql +# mysql_database: +# image: mysql:8.3 +# container_name: mysql_stars +# restart: unless-stopped +# command: --default-authentication-plugin=caching_sha2_password +# environment: +# MYSQL_DATABASE: 'stars' +# MYSQL_ROOT_PASSWORD: 'root' # Define a senha diretamente para o usuário root padrão +# ports: +# - '3306:3306' +# volumes: +# - mysql_database:/var/lib/mysql -volumes: - mysql_database: - name: mysql_database \ No newline at end of file +# volumes: +# mysql_database: +# name: mysql_database \ No newline at end of file