Skip to content

Commit df34f65

Browse files
authored
Merge branch 'main' into volunteer-dash
2 parents 3b21508 + f59ad23 commit df34f65

File tree

20 files changed

+687
-69
lines changed

20 files changed

+687
-69
lines changed

backend/app/models/User.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ class FormStatus(str, PyEnum):
2121
REJECTED = "rejected"
2222

2323

24+
class Language(str, PyEnum):
25+
ENGLISH = "en"
26+
FRENCH = "fr"
27+
28+
2429
class User(Base):
2530
__tablename__ = "users"
2631
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
@@ -42,6 +47,16 @@ class User(Base):
4247
nullable=False,
4348
default=FormStatus.INTAKE_TODO,
4449
)
50+
language = Column(
51+
SQLEnum(
52+
Language,
53+
name="language_enum",
54+
create_type=False,
55+
values_callable=lambda enum_cls: [member.value for member in enum_cls],
56+
),
57+
nullable=False,
58+
default=Language.ENGLISH,
59+
)
4560

4661
role = relationship("Role")
4762

backend/app/models/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .Task import Task, TaskPriority, TaskStatus, TaskType
2222
from .TimeBlock import TimeBlock
2323
from .Treatment import Treatment
24-
from .User import FormStatus, User
24+
from .User import FormStatus, Language, User
2525
from .UserData import UserData
2626
from .VolunteerData import VolunteerData
2727

@@ -44,6 +44,7 @@
4444
"Form",
4545
"FormSubmission",
4646
"FormStatus",
47+
"Language",
4748
"Task",
4849
"TaskType",
4950
"TaskPriority",

backend/app/routes/auth.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,7 @@ async def get_current_user(
124124
if not user:
125125
raise HTTPException(status_code=404, detail="User not found")
126126

127-
return UserCreateResponse(
128-
id=user.id,
129-
first_name=user.first_name,
130-
last_name=user.last_name,
131-
email=user.email,
132-
role_id=user.role_id,
133-
auth_id=user.auth_id,
134-
approved=user.approved,
135-
form_status=user.form_status,
136-
)
127+
return UserCreateResponse.model_validate(user)
137128
except HTTPException:
138129
raise
139130
except Exception as e:

backend/app/schemas/user.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ class FormStatus(str, Enum):
5050
REJECTED = "rejected"
5151

5252

53+
class Language(str, Enum):
54+
ENGLISH = "en"
55+
FRENCH = "fr"
56+
57+
5358
class UserBase(BaseModel):
5459
"""
5560
Base schema for user model with common attributes shared across schemas.
@@ -107,6 +112,7 @@ class UserUpdateRequest(BaseModel):
107112
role: Optional[UserRole] = None
108113
approved: Optional[bool] = None
109114
form_status: Optional[FormStatus] = None
115+
language: Optional[Language] = None
110116

111117

112118
class UserCreateResponse(BaseModel):
@@ -122,6 +128,7 @@ class UserCreateResponse(BaseModel):
122128
auth_id: str
123129
approved: bool
124130
form_status: FormStatus
131+
language: Language
125132

126133
# from_attributes enables automatic mapping from SQLAlchemy model to Pydantic model
127134
model_config = ConfigDict(from_attributes=True)
@@ -145,6 +152,7 @@ class UserResponse(BaseModel):
145152
user_data: Optional[UserDataResponse] = None
146153
volunteer_data: Optional[VolunteerDataResponse] = None
147154
availability: List[AvailabilityTemplateSlot] = []
155+
language: Language
148156

149157
model_config = ConfigDict(from_attributes=True)
150158

backend/app/seeds/users.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from app.models.SuggestedTime import suggested_times
1515
from app.models.Task import Task
1616
from app.models.Treatment import Treatment
17-
from app.models.User import FormStatus, User
17+
from app.models.User import FormStatus, Language, User
1818
from app.models.UserData import UserData
1919
from app.models.VolunteerData import VolunteerData
2020
from app.utilities.form_constants import ExperienceId, TreatmentId
@@ -375,6 +375,7 @@ def seed_users(session: Session) -> None:
375375
approved=True,
376376
active=True,
377377
form_status=FormStatus.INTAKE_TODO,
378+
language=Language.ENGLISH,
378379
)
379380
session.add(user)
380381
session.flush() # Get user ID

backend/app/services/implementations/intake_form_processor.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from sqlalchemy.orm import Session
77

8-
from app.models import Experience, FormStatus, Treatment, User, UserData
8+
from app.models import Experience, FormStatus, Language, Treatment, User, UserData
99

1010
logger = logging.getLogger(__name__)
1111

@@ -86,6 +86,8 @@ def process_form_submission(self, user_id: str, form_data: Dict[str, Any]) -> Us
8686

8787
if "additional_info" in form_data:
8888
user_data.additional_info = self._trim_text(form_data.get("additional_info"))
89+
# Update language for owning user
90+
owning_user.language = form_data.get("language", Language.ENGLISH)
8991

9092
# Commit all changes
9193
self.db.commit()

backend/app/services/implementations/match_service.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,10 +806,11 @@ def _attach_initial_suggested_times(self, match: Match, volunteer: User) -> None
806806
)
807807
volunteer_tz = timezone.utc
808808

809-
# Project templates onto the next week
810-
projection_weeks = 1
809+
# Project templates 8 days ahead (1 week + 1 day) to ensure we capture at least one future
810+
# occurrence of each template day, even if today's times have already passed
811+
projection_days = 8
811812

812-
for day_offset in range(projection_weeks * 7):
813+
for day_offset in range(projection_days):
813814
# Calculate target date in UTC
814815
target_date_utc = now + timedelta(days=day_offset)
815816

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""add language enum and column to users model
2+
3+
Revision ID: 329a7ab72d38
4+
Revises: 8d2cd99b9eb8
5+
Create Date: 2025-11-06 19:37:26.647630
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
import sqlalchemy as sa
12+
from alembic import op
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = "329a7ab72d38"
16+
down_revision: Union[str, None] = "8d2cd99b9eb8"
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
_LANGUAGE_VALUES = (
21+
"en",
22+
"fr",
23+
)
24+
25+
_DEFAULT_LANGUAGE = "en"
26+
27+
28+
def upgrade() -> None:
29+
op.execute("CREATE TYPE language_enum AS ENUM ('en', 'fr')")
30+
31+
op.add_column(
32+
"users",
33+
sa.Column(
34+
"language",
35+
sa.Enum(*_LANGUAGE_VALUES, name="language_enum", create_type=False),
36+
nullable=False,
37+
server_default=_DEFAULT_LANGUAGE,
38+
),
39+
)
40+
41+
42+
def downgrade() -> None:
43+
op.drop_column("users", "language")
44+
op.execute("DROP TYPE language_enum")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""merge multiple heads drop_available_times_table
2+
3+
Revision ID: 77423a45f740
4+
Revises: 93cc5dac324a, dda4b46776e9
5+
Create Date: 2025-11-24 21:20:43.406772
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
# revision identifiers, used by Alembic.
12+
revision: str = "77423a45f740"
13+
down_revision: Union[str, None] = ("93cc5dac324a", "dda4b46776e9")
14+
branch_labels: Union[str, Sequence[str], None] = None
15+
depends_on: Union[str, Sequence[str], None] = None
16+
17+
18+
def upgrade() -> None:
19+
pass
20+
21+
22+
def downgrade() -> None:
23+
pass
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""merge multiple heads
2+
3+
Revision ID: 93cc5dac324a
4+
Revises: 23dae9594e1d, 329a7ab72d38
5+
Create Date: 2025-11-24 19:04:33.167997
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
# revision identifiers, used by Alembic.
12+
revision: str = "93cc5dac324a"
13+
down_revision: Union[str, None] = ("23dae9594e1d", "329a7ab72d38")
14+
branch_labels: Union[str, Sequence[str], None] = None
15+
depends_on: Union[str, Sequence[str], None] = None
16+
17+
18+
def upgrade() -> None:
19+
pass
20+
21+
22+
def downgrade() -> None:
23+
pass

0 commit comments

Comments
 (0)