import io import uuid from datetime import datetime, timedelta import discord from discord import Colour from peewee import * from peewee import ModelSelect db = SqliteDatabase("root.db") class BaseModel(Model): class Meta: database = db class Poll(BaseModel): question = CharField() author = IntegerField() channel = IntegerField() message = IntegerField() def get_embed(self) -> discord.Embed: embed = discord.Embed(title="Umfrage", description=self.question) embed.add_field(name="Erstellt von", value=f'<@!{self.author}>', inline=False) embed.add_field(name="\u200b", value="\u200b", inline=False) for choice in self.choices: name = f'{choice.emoji} {choice.text}' value = f'{len(choice.choice_chosen)}' embed.add_field(name=name, value=value, inline=False) participants = {str(choice_chosen.member_id): 1 for choice_chosen in PollChoiceChosen.select().join(PollChoice, on=PollChoiceChosen.poll_choice).where( PollChoice.poll == self)} embed.add_field(name="\u200b", value="\u200b", inline=False) embed.add_field(name="Anzahl der Teilnehmer an der Umfrage", value=f"{len(participants)}", inline=False) return embed class PollChoice(BaseModel): poll = ForeignKeyField(Poll, backref='choices') text = CharField() emoji = CharField() class PollChoiceChosen(BaseModel): poll_choice = ForeignKeyField(PollChoice, backref='choice_chosen') member_id = IntegerField() class Appointment(BaseModel): channel = IntegerField() message = IntegerField() date_time = DateTimeField() reminder = IntegerField() title = CharField() description = CharField() author = IntegerField() recurring = IntegerField() reminder_sent = BooleanField() uuid = UUIDField(default=uuid.uuid4()) def get_embed(self, state: int) -> discord.Embed: attendees = self.attendees description = (f"- Durch Klicken auf Anmelden erhältst du eine Benachrichtigung zum Beginn des Termins" f"{f', sowie {self.reminder} Minuten vorher' if self.reminder > 0 else f''}.\n" f"- Durch Klicken auf Abmelden nimmst du deine vorherige Anmeldung wieder zurück und wirst " f"nicht benachrichtigt.") if state != 2 else "" emoji = "📅" if state == 0 else ("📣" if state == 1 else "✅") embed = discord.Embed(title=f"{emoji} __{self.title}__ {'findet jetzt statt.' if state == 2 else ''}", description=description) embed.color = Colour.green() if state == 0 else Colour.yellow() if state == 1 else 19607 if len(self.description) > 0: embed.add_field(name="Beschreibung", value=self.description, inline=False) embed.add_field(name="Startzeitpunkt", value=self.get_start_time(state), inline=False) if self.reminder > 0 and state == 0: embed.add_field(name="Erinnerung", value=f"{self.reminder} Minuten vor dem Start", inline=False) if self.recurring > 0: embed.add_field(name="Wiederholung", value=f"Alle {self.recurring} Tage", inline=False) if len(attendees) > 0: embed.add_field(name=f"Teilnehmerinnen ({len(attendees)})", value=",".join([f"<@{attendee.member_id}>" for attendee in attendees])) return embed def remind_at(self) -> datetime: if self.reminder_sent: return self.date_time elif datetime.now() >= self.date_time: Appointment.update(reminder_sent=True).where(Appointment.id == self.id).execute() self.reminder_sent = True return self.date_time else: return self.date_time - timedelta(minutes=self.reminder) def get_start_time(self, state) -> str: if state == 0: return f"<t:{int(self.date_time.timestamp())}:F>" return f"<t:{int(self.date_time.timestamp())}:F> (<t:{int(self.date_time.timestamp())}:R>)" def get_ics_file(self): fmt = "%Y%m%dT%H%M" appointment = f"BEGIN:VCALENDAR\n" \ f"PRODID:Boty McBotface\n" \ f"VERSION:2.0\n" \ f"BEGIN:VTIMEZONE\n" \ f"TZID:Europe/Berlin\n" \ f"BEGIN:DAYLIGHT\n" \ f"TZOFFSETFROM:+0100\n" \ f"TZOFFSETTO:+0200\n" \ f"TZNAME:CEST\n" \ f"DTSTART:19700329T020000\n" \ f"RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3\n" \ f"END:DAYLIGHT\n" \ f"BEGIN:STANDARD\n" \ f"TZOFFSETFROM:+0200\n" \ f"TZOFFSETTO:+0100\n" \ f"TZNAME:CET\n" \ f"DTSTART:19701025T030000\n" \ f"RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\n" \ f"END:STANDARD\n" \ f"END:VTIMEZONE\n" \ f"BEGIN:VEVENT\n" \ f"DTSTAMP:{datetime.now().strftime(fmt)}00Z\n" \ f"UID:{self.uuid}\n" \ f"SUMMARY:{self.title}\n" appointment += f"RRULE:FREQ=DAILY;INTERVAL={self.recurring}\n" if self.recurring else f"" appointment += f"DTSTART;TZID=Europe/Berlin:{self.date_time.strftime(fmt)}00\n" \ f"DTEND;TZID=Europe/Berlin:{self.date_time.strftime(fmt)}00\n" \ f"TRANSP:OPAQUE\n" \ f"BEGIN:VALARM\n" \ f"ACTION:DISPLAY\n" \ f"TRIGGER;VALUE=DURATION:-PT{self.reminder}M\n" \ f"DESCRIPTION:{self.description}\n" \ f"END:VALARM\n" \ f"END:VEVENT\n" \ f"END:VCALENDAR" ics_file = io.BytesIO(appointment.encode("utf-8")) return ics_file class Attendee(BaseModel): appointment = ForeignKeyField(Appointment, backref='attendees') member_id = IntegerField() class Topic(BaseModel): channel = IntegerField() name = CharField() @classmethod def get_topics(cls, channel: int, topic: str = None) -> ModelSelect: topics: ModelSelect = cls.select().where(Topic.channel == channel) return topics.where(Topic.name == topic) if topic else topics @classmethod def has_links(cls, channel: int, topic: str = None) -> bool: for topic in cls.get_topics(channel, topic=topic): if len(list(topic.links)) > 0: return True return False def append_field(self, embed: discord.Embed): value = "" for link in self.links: value += f"- [{link.title}]({link.link})\n" embed.add_field(name=self.name.capitalize(), value=value, inline=False) class Link(BaseModel): link = CharField() title = CharField() topic = ForeignKeyField(Topic, backref='links') class Timer(BaseModel): name = CharField() status = CharField() working_time = IntegerField() break_time = IntegerField() remaining = IntegerField() guild = IntegerField() channel = IntegerField() message = IntegerField() def create_embed(self): color = discord.Colour.green() if self.status == "Arbeiten" else 0xFFC63A if self.status == "Pause" else discord.Colour.red() zeiten = f"{self.working_time} Minuten Arbeiten\n{self.break_time} Minuten Pause" remaining_value = f"{self.remaining} Minuten" endzeit = (datetime.now() + timedelta(minutes=self.remaining)).strftime("%H:%M") end_value = f" [bis {endzeit} Uhr]" if self.status != "Beendet" else "" angemeldet_value = ", ".join([f"<@{attendee.member}>" for attendee in self.attendees]) embed = discord.Embed(title=self.name, color=color) embed.add_field(name="Status:", value=self.status, inline=False) embed.add_field(name="Zeiten:", value=zeiten, inline=False) embed.add_field(name="verbleibende Zeit:", value=remaining_value + end_value, inline=False) embed.add_field(name="angemeldete User:", value=angemeldet_value if len(angemeldet_value) > 0 else "-", inline=False) return embed class TimerAttendee(BaseModel): timer = ForeignKeyField(Timer, backref="attendees") member = IntegerField() class Command(BaseModel): command = CharField(unique=True) description = CharField() class CommandText(BaseModel): text = CharField() command = ForeignKeyField(Command, backref="texts") class SprachRohr(BaseModel): url = CharField() year = IntegerField() issue = CharField() class News(BaseModel): link = CharField() date = CharField() db.create_tables([Poll, PollChoice, PollChoiceChosen, Appointment, Attendee, Topic, Link, Timer, TimerAttendee, Command, CommandText, SprachRohr, News], safe=True)