from __future__ import annotations
import sedate
from datetime import date, datetime
from onegov.core.orm import Base
from onegov.core.orm.mixins import TimestampMixin
from onegov.form.models.submission import SurveySubmission
from sqlalchemy import ForeignKey
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Mapped
from sqlalchemy.schema import CheckConstraint
from uuid import uuid4, UUID
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from onegov.form.models.definition import SurveyDefinition
[docs]
class SurveySubmissionWindow(Base, TimestampMixin):
""" Defines a submission window during which a survey definition
may be used to create submissions.
Submissions created thusly are attached to the currently active
survey window.
"""
[docs]
__tablename__ = 'submission_windows'
#: the public id of the submission window
[docs]
id: Mapped[UUID] = mapped_column(
primary_key=True,
default=uuid4
)
#: the name of the survey to which this submission window belongs
[docs]
name: Mapped[str] = mapped_column(ForeignKey('surveys.name'))
#: the title of the submission window
[docs]
title: Mapped[str | None]
#: the survey to which this submission window belongs
[docs]
survey: Mapped[SurveyDefinition] = relationship(
back_populates='submission_windows'
)
#: true if the submission window is enabled
[docs]
enabled: Mapped[bool] = mapped_column(default=True)
#: the start date of the window
#: the end date of the window
#: the timezone of the window
[docs]
timezone: Mapped[str] = mapped_column(default='Europe/Zurich')
#: submissions linked to this
[docs]
submissions: Mapped[list[SurveySubmission]] = relationship(
back_populates='submission_window'
)
[docs]
__table_args__ = (
# ensures that start <= end
CheckConstraint(
'"start" <= "end"',
name='start_smaller_than_end'
),
)
@property
[docs]
def localized_start(self) -> datetime:
return sedate.align_date_to_day(
sedate.standardize_date(
sedate.as_datetime(self.start), self.timezone
), self.timezone, 'down'
)
@property
[docs]
def localized_end(self) -> datetime:
return sedate.align_date_to_day(
sedate.standardize_date(
sedate.as_datetime(self.end), self.timezone
), self.timezone, 'up'
)
@property
[docs]
def in_the_future(self) -> bool:
return sedate.utcnow() <= self.localized_start
@property
[docs]
def in_the_past(self) -> bool:
return self.localized_end <= sedate.utcnow()
@property
[docs]
def in_the_present(self) -> bool:
return self.localized_start <= sedate.utcnow() <= self.localized_end
[docs]
def accepts_submissions(self) -> bool:
if not self.enabled:
return False
if not self.in_the_present:
return False
return True