Skip to content

Commit

Permalink
Define an enum for Rsvp, but keep the old LabeledEnum pending StateMa…
Browse files Browse the repository at this point in the history
…nager support
  • Loading branch information
jace committed Jan 3, 2024
1 parent 5fb0253 commit f50d73f
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 22 deletions.
10 changes: 0 additions & 10 deletions funnel/models/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
'PASSWORD_MIN_LENGTH',
'PASSWORD_MAX_LENGTH',
'IntTitle',
'IntNameTitle',
'check_password_strength',
'profanity',
'add_to_class',
Expand Down Expand Up @@ -144,15 +143,6 @@ class IntTitle(DataclassFromType, int):
title: str = ''


@dataclass(frozen=True)
class IntNameTitle(DataclassFromType, int):
"""Integer value with a name and title (for enums)."""

# The empty default is required for Mypy's enum plugin's `Enum.__call__` analysis
name: str = ''
title: str = ''


@dataclass
class PasswordCheckType:
"""
Expand Down
6 changes: 3 additions & 3 deletions funnel/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -920,10 +920,10 @@ def rsvp_for(
def rsvp_for(self, account: Account | None, create=False) -> Rsvp | None:
return Rsvp.get_for(self, account, create)

def rsvps_with(self, status: str):
def rsvps_with(self, state: RsvpStateEnum) -> Query[Rsvp]:
return self.rsvps.join(Account).filter(
Account.state.ACTIVE,
Rsvp._state == status, # pylint: disable=protected-access
Rsvp._state == state, # pylint: disable=protected-access
)

def rsvp_counts(self) -> dict[str, int]:
Expand Down Expand Up @@ -1561,7 +1561,7 @@ def __repr__(self) -> str:
from .label import Label
from .project_membership import ProjectMembership
from .proposal import Proposal
from .rsvp import Rsvp
from .rsvp import Rsvp, RsvpStateEnum
from .session import Session
from .sponsor_membership import ProjectSponsorMembership
from .update import Update
Expand Down
26 changes: 22 additions & 4 deletions funnel/models/rsvp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

from __future__ import annotations

from dataclasses import dataclass
from enum import ReprEnum
from typing import TYPE_CHECKING, Any, Literal, Self, overload

from flask import current_app

from baseframe import __
from coaster.sqlalchemy import StateManager, with_roles
from coaster.utils import LabeledEnum
from coaster.utils import DataclassFromType, LabeledEnum

from . import (
Mapped,
Expand All @@ -26,7 +28,7 @@
from .project import Project
from .project_membership import project_child_role_map

__all__ = ['Rsvp', 'RSVP_STATUS']
__all__ = ['RSVP_STATUS', 'RsvpStateEnum', 'Rsvp']


class RSVP_STATUS(LabeledEnum): # noqa: N801
Expand All @@ -38,6 +40,22 @@ class RSVP_STATUS(LabeledEnum): # noqa: N801
AWAITING = ('A', 'awaiting', __("Awaiting"))


@dataclass(frozen=True)
class _RsvpOptions(DataclassFromType, str):
"""RSVP options."""

# The empty default is required for Mypy's enum plugin's `Enum.__call__` analysis
response: str = ''
label: str = ''


class RsvpStateEnum(_RsvpOptions, ReprEnum):
YES = 'Y', __("Yes"), __("Going")
NO = 'N', __("No"), __("Not going")
MAYBE = 'M', __("Maybe"), __("Maybe")
AWAITING = 'A', __("Invite"), __("Awaiting")


class Rsvp(UuidMixin, NoIdMixin, Model):
__tablename__ = 'rsvp'
project_id: Mapped[int] = sa_orm.mapped_column(
Expand Down Expand Up @@ -68,8 +86,8 @@ class Rsvp(UuidMixin, NoIdMixin, Model):
_state: Mapped[str] = sa_orm.mapped_column(
'state',
sa.CHAR(1),
StateManager.check_constraint('state', RSVP_STATUS, sa.CHAR(1)),
default=RSVP_STATUS.AWAITING,
StateManager.check_constraint('state', RsvpStateEnum, sa.CHAR(1)),
default=RsvpStateEnum.AWAITING,
nullable=False,
)
state = with_roles(
Expand Down
10 changes: 5 additions & 5 deletions funnel/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
ProjectTransitionForm,
)
from ..models import (
RSVP_STATUS,
Account,
Project,
ProjectRsvpStateEnum,
RegistrationCancellationNotification,
RegistrationConfirmationNotification,
Rsvp,
RsvpStateEnum,
SavedProject,
db,
sa,
Expand Down Expand Up @@ -744,7 +744,7 @@ def rsvp_list(self) -> ReturnRenderWith:
'project': self.obj.current_access(datasets=('primary', 'related')),
'going_rsvps': [
_r.current_access(datasets=('without_parent', 'related', 'related'))
for _r in self.obj.rsvps_with(RSVP_STATUS.YES)
for _r in self.obj.rsvps_with(RsvpStateEnum.YES)
],
'rsvp_form_fields': [
field.get('name', '')
Expand All @@ -755,7 +755,7 @@ def rsvp_list(self) -> ReturnRenderWith:
else None,
}

def get_rsvp_state_csv(self, state):
def get_rsvp_state_csv(self, state: RsvpStateEnum) -> Response:
"""Export participant list as a CSV."""
outfile = io.StringIO(newline='')
out = csv.writer(outfile)
Expand Down Expand Up @@ -789,14 +789,14 @@ def get_rsvp_state_csv(self, state):
@requires_roles({'promoter'})
def rsvp_list_yes_csv(self) -> ReturnView:
"""Return a CSV of RSVP participants who answered Yes."""
return self.get_rsvp_state_csv(state=RSVP_STATUS.YES)
return self.get_rsvp_state_csv(RsvpStateEnum.YES)

@route('rsvp_list/maybe.csv')
@requires_login
@requires_roles({'promoter'})
def rsvp_list_maybe_csv(self) -> ReturnView:
"""Return a CSV of RSVP participants who answered Maybe."""
return self.get_rsvp_state_csv(state=RSVP_STATUS.MAYBE)
return self.get_rsvp_state_csv(RsvpStateEnum.MAYBE)

@route('save', methods=['POST'])
@requires_login
Expand Down

0 comments on commit f50d73f

Please sign in to comment.