forked from LeineLab-Public/lab-signal-bot
models: add next_user_to_send_request()
This commit is contained in:
parent
da2352642e
commit
f6f99b860b
107
models.py
107
models.py
@ -11,7 +11,8 @@ import datetime
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
def utc_now():
|
def utc_now():
|
||||||
return datetime.datetime.now(datetime.timezone.utc)
|
# We remove the timezone information, because SQLite does not support it
|
||||||
|
return datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
||||||
|
|
||||||
class User(SQLModel, table=True):
|
class User(SQLModel, table=True):
|
||||||
id: int = Field(primary_key=True)
|
id: int = Field(primary_key=True)
|
||||||
@ -41,6 +42,19 @@ def all_users_sorted(session: Session) -> List[User]:
|
|||||||
users.sort(key=lambda u: u.sort_time())
|
users.sort(key=lambda u: u.sort_time())
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
def next_user_to_send_request(session: Session, task: "Task") -> User | None:
|
||||||
|
# Return the user who should send the next request (or None if we already
|
||||||
|
# sent requests for this Task to all users)
|
||||||
|
|
||||||
|
requested_users = [r.user for r in task.participation_requests]
|
||||||
|
|
||||||
|
users = all_users_sorted(session)
|
||||||
|
for u in users:
|
||||||
|
if u in requested_users:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return u
|
||||||
|
|
||||||
class Task(SQLModel, table=True):
|
class Task(SQLModel, table=True):
|
||||||
id: int = Field(primary_key=True)
|
id: int = Field(primary_key=True)
|
||||||
name: str
|
name: str
|
||||||
@ -65,8 +79,8 @@ class Task(SQLModel, table=True):
|
|||||||
def additional_requests_to_be_sent(self):
|
def additional_requests_to_be_sent(self):
|
||||||
# return the number of additional requests to be sent
|
# return the number of additional requests to be sent
|
||||||
return self.required_number_of_participants \
|
return self.required_number_of_participants \
|
||||||
- len(self.accepted_participation_requests()) \
|
- len(self.accepted_requests()) \
|
||||||
- len(self.requested_participation_requests())
|
- len(self.requested_requests())
|
||||||
|
|
||||||
def freshly_expired_requests(self, now) -> List["ParticipationRequest"]:
|
def freshly_expired_requests(self, now) -> List["ParticipationRequest"]:
|
||||||
expired_requests = []
|
expired_requests = []
|
||||||
@ -152,7 +166,6 @@ class AlreadyRejected(StateTransitionError):
|
|||||||
class Timeout(StateTransition):
|
class Timeout(StateTransition):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ParticipationRequest(SQLModel, table=True):
|
class ParticipationRequest(SQLModel, table=True):
|
||||||
id: int = Field(primary_key=True)
|
id: int = Field(primary_key=True)
|
||||||
user_id: int = Field(foreign_key="user.id")
|
user_id: int = Field(foreign_key="user.id")
|
||||||
@ -283,6 +296,90 @@ def test_all_users_sorted(session):
|
|||||||
users = all_users_sorted(session)
|
users = all_users_sorted(session)
|
||||||
assert users == [u1, u3, u2]
|
assert users == [u1, u3, u2]
|
||||||
|
|
||||||
|
def test_next_user(session):
|
||||||
|
u1 = User(name="u1")
|
||||||
|
u2 = User(name="u2")
|
||||||
|
u3 = User(name="u3")
|
||||||
|
|
||||||
|
session.add(u1)
|
||||||
|
session.add(u2)
|
||||||
|
session.add(u3)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
# Starting order
|
||||||
|
users = all_users_sorted(session)
|
||||||
|
assert users == [u1, u2, u3]
|
||||||
|
|
||||||
|
t1 = Task(name="t1", required_number_of_participants=2, due=utc_now(), timeout=10)
|
||||||
|
|
||||||
|
session.add(t1)
|
||||||
|
|
||||||
|
assert t1.additional_requests_to_be_sent() == 2
|
||||||
|
|
||||||
|
assert next_user_to_send_request(session, t1) == u1
|
||||||
|
|
||||||
|
r1 = ParticipationRequest(user=u1, task=t1, requested_at=utc_now())
|
||||||
|
session.add(r1)
|
||||||
|
|
||||||
|
assert next_user_to_send_request(session, t1) == u2
|
||||||
|
|
||||||
|
# Starting order
|
||||||
|
users = all_users_sorted(session)
|
||||||
|
assert users == [u1, u2, u3]
|
||||||
|
|
||||||
|
# Another additional request should be sent out.
|
||||||
|
assert t1.additional_requests_to_be_sent() == 1
|
||||||
|
|
||||||
|
# After rejecting, two additional requests should be sent out.
|
||||||
|
assert isinstance(r1.try_reject(utc_now()).unwrap(), RejectInTime)
|
||||||
|
assert t1.additional_requests_to_be_sent() == 2
|
||||||
|
|
||||||
|
# Create another Task
|
||||||
|
t2 = Task(name="t2", required_number_of_participants=2, due=utc_now(), timeout=10)
|
||||||
|
session.add(t2)
|
||||||
|
|
||||||
|
# Next user should be user1 (because we rejected in t1)
|
||||||
|
assert next_user_to_send_request(session, t2) == u1
|
||||||
|
|
||||||
|
# Still starting order (because we rejected)
|
||||||
|
users = all_users_sorted(session)
|
||||||
|
assert users == [u1, u2, u3]
|
||||||
|
|
||||||
|
# When we change to accept, only one additional request should be sent out.
|
||||||
|
assert isinstance(r1.try_accept(utc_now()).unwrap(), AcceptAfterRejectAllowed)
|
||||||
|
assert t1.additional_requests_to_be_sent() == 1
|
||||||
|
|
||||||
|
# Next user should be u2 for t2 (because u1 accepted for t1)
|
||||||
|
assert next_user_to_send_request(session, t2) == u2
|
||||||
|
|
||||||
|
# Next user should be user2 for t1 also
|
||||||
|
assert next_user_to_send_request(session, t1) == u2
|
||||||
|
|
||||||
|
# Still starting order (because we rejected)
|
||||||
|
users = all_users_sorted(session)
|
||||||
|
assert users == [u2, u3, u1]
|
||||||
|
|
||||||
|
# Next user should be user2
|
||||||
|
assert next_user_to_send_request(session, t1) == u2
|
||||||
|
|
||||||
|
r3 = ParticipationRequest(user=u3, task=t1, requested_at=utc_now())
|
||||||
|
session.add(r3)
|
||||||
|
|
||||||
|
# Next user should still be user2
|
||||||
|
assert next_user_to_send_request(session, t1) == u2
|
||||||
|
|
||||||
|
r2 = ParticipationRequest(user=u2, task=t1, requested_at=utc_now())
|
||||||
|
session.add(r2)
|
||||||
|
|
||||||
|
# No user should be left
|
||||||
|
assert next_user_to_send_request(session, t1) is None
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
# We sent one request too much...
|
||||||
|
assert t1.additional_requests_to_be_sent() == -1
|
||||||
|
|
||||||
def test_accept(session):
|
def test_accept(session):
|
||||||
now = datetime.datetime(2024, 12, 10, 0, 0)
|
now = datetime.datetime(2024, 12, 10, 0, 0)
|
||||||
dt = datetime.timedelta(days=1)
|
dt = datetime.timedelta(days=1)
|
||||||
@ -390,5 +487,3 @@ def test_reject(session):
|
|||||||
assert(r2.state == ParticipationState.REJECTED)
|
assert(r2.state == ParticipationState.REJECTED)
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user