Kaynağa Gözat

Session command

Kirk Trombley 4 yıl önce
ebeveyn
işleme
c10f1fc34c
2 değiştirilmiş dosya ile 151 ekleme ve 1 silme
  1. 0 1
      README.md
  2. 151 0
      src/commands/session.py

+ 0 - 1
README.md

@@ -9,7 +9,6 @@ TODO as always
 ## Missing Commands
 
 Needs the following ported from rollbot3 for feature parity:
-- session
 - curse
 - hangguy
 - watchlist

+ 151 - 0
src/commands/session.py

@@ -0,0 +1,151 @@
+from typing import Optional
+import datetime
+
+from rollbot import as_command, initialize_data, RollbotFailure
+from rollbot.injection import Subcommand, Data, ChannelAdmin, Channel, Lazy
+
+
+@initialize_data
+class DnDSession:
+    session_time: Optional[float] = None
+
+    @staticmethod
+    def fmt(sesh):
+        if (
+            sesh is None
+            or sesh.session_time is None
+            or sesh.session_time < datetime.datetime.now().timestamp()
+        ):
+            return "No upcoming session found."
+        return "Next DnD session scheduled for " + datetime.datetime.fromtimestamp(
+            sesh.session_time
+        ).strftime("%b %d, %Y, at %I:%M %p")
+
+
+WEEKDAYS = {
+    "monday": 0,
+    "tuesday": 1,
+    "wednesday": 2,
+    "thursday": 3,
+    "friday": 4,
+    "saturday": 5,
+    "sunday": 6,
+}
+
+
+def pop_arg(text):
+    if text is None:
+        return None, None
+    text = text.strip()
+    parts = text.split(maxsplit=1)
+    if len(parts) == 1:
+        return parts[0], None
+    return parts[0], parts[1]
+
+
+def parse_datetime(arg_text):
+    if arg_text is None:
+        return
+
+    day_date, arg_text = pop_arg(arg_text)
+    day_date = day_date.lower()
+    if day_date in WEEKDAYS:
+        today = datetime.date.today()
+        day_diff = WEEKDAYS[day_date] - today.weekday()
+        next_day = today + datetime.timedelta((day_diff) % 7)
+        month = next_day.month
+        day = next_day.day
+        year = next_day.year
+    else:
+        date_parts = day_date.split("/")
+        if len(date_parts) == 3:
+            month = date_parts[0]
+            day = date_parts[1]
+            year = date_parts[2]
+        elif len(date_parts) == 2:
+            month = date_parts[0]
+            day = date_parts[1]
+            year = datetime.date.today().year
+        else:
+            return
+
+    hour = 19
+    minute = 45
+
+    if arg_text is None:
+        return datetime.datetime(int(year), int(month), int(day), int(hour), int(minute))
+
+    time, arg_text = pop_arg(arg_text)
+    time_parts = time.split(":")
+    hour = time_parts[0]
+    if len(time_parts) > 1:
+        minute = time_parts[1]
+
+    ampm, arg_text = pop_arg(arg_text)
+
+    if ampm is None:
+        return datetime.datetime(int(year), int(month), int(day), int(hour), int(minute))
+
+    if ampm.lower() == "pm":
+        hour = int(hour) + 12
+
+    return datetime.datetime(int(year), int(month), int(day), int(hour), int(minute))
+
+
+SUBCOMMANDS = ("next", "view", "late", "cancel")
+VALID_DETAIL = "Valid subcommands are: next, view, late, and cancel"
+NEEDS_ADMIN = ("next", "cancel")
+
+
+@as_command
+async def session(
+    subc: Subcommand,
+    get_sesh: Lazy(Data(DnDSession).For(Channel)),
+    store: Data(DnDSession),
+    admin: ChannelAdmin,
+    channel: Channel,
+):
+    if subc is None:
+        RollbotFailure.MISSING_SUBCOMMAND.raise_exc(detail=VALID_DETAIL)
+
+    if subc.name not in SUBCOMMANDS:
+        RollbotFailure.INVALID_SUBCOMMAND.raise_exc(detail=VALID_DETAIL)
+
+    if not admin and subc.name in NEEDS_ADMIN:
+        RollbotFailure.PERMISSIONS.raise_exc()
+
+    sesh = await get_sesh()
+
+    if subc.name == "view":
+        return DnDSession.fmt(sesh)
+
+    if subc.name == "next":
+        dt = parse_datetime(subc.args)
+        if dt is None:
+            RollbotFailure.INVALID_ARGUMENTS.raise_exc(
+                detail="Could not process argument as a date/time."
+            )
+        if dt < datetime.datetime.now():
+            RollbotFailure.INVALID_ARGUMENTS.raise_exc(
+                detail="Cannot schedule sessions in the past."
+            )
+
+        sesh.session_time = dt.timestamp()
+        await store.save(channel, sesh)
+        return DnDSession.fmt(sesh)
+
+    if sesh is None or sesh.session_time is None:
+        return "No upcoming session found."
+
+    if subc.name == "late":
+        now = datetime.datetime.now().timestamp()
+        if sesh.session_time >= now:
+            return "You're not late yet!"
+
+        late = (now - sesh.session_time) / 60
+        return f"You're running {late:.2f} minutes late..."
+
+    if subc.name == "cancel":
+        sesh.session_time = None
+        await store.save(channel, sesh)
+        return "Sigh, session cancelled..."