from datetime import date, datetime from dateutil.relativedelta import relativedelta # BSD class Birthday: def __init__(self, person, date): person = person.strip() date = date.strip() if not person or not date: raise ValueError("One of the parameters was invalid or empty!") self.PERSON = person.strip() self.DATE = date.strip() def __eq__(self, other): return self.PERSON == other.PERSON and self.DATE == other.DATE def __repr__(self): return f'{self.__class__.__name__}: {self.PERSON} {self.DATE}' # ist nur python 2 => muss für __lt__ als python 3 neugeschrieben werden # def __cmp__(self, other): # if hasattr(other, 'DATE') and hasattr(other, 'PERSON'): # splittedDateSelf = self.DATE.split('.') # splittedDateOther = other.DATE.split('.') # comp = splittedDateSelf[1].__cmp__(splittedDateOther[1]) # compare month # if comp == 0: # comp = splittedDateSelf[0].__cmp__(splittedDateOther[0]) # compare day # if comp == 0: # comp = self.PERSON.__cmp__(other.PERSON) # compare name # # return comp def get_congratulation(self): return f"Alles Gute {self.PERSON} ❤" def get_csv_line(self): return f"{self.PERSON},{self.DATE}" class ModuleBirthdayReminder: def __init__(self, groups, send, log): self.tag = "%20s - " % "mBirthdayReminder" self.log = log self.send = send self.birthday_list = {} self.GROUPS = groups for group in groups: self.load_birthdays_from_csv(group) self.log.debug(f"{self.tag}Modul BirthdayReminder geladen") def load_birthdays_from_csv(self, groupInfo): lines = [] try: with open(groupInfo["BIRTHDAYDIR"], 'r', encoding='utf16') as f: lines = f.readlines() except IOError as exc: self.log.error( f"{self.tag}Reading birthdays from csv failed: {exc}") self.birthday_list[groupInfo["NAME"]] = [] for line in lines: try: birthday = self.interpret_birthday_line(line) self.birthday_list[groupInfo["NAME"]].append(birthday) except (SyntaxError, ValueError) as exc: self.log.warning( f"{self.tag}Error while interpreting birthday line:{line}; Error: {exc}") def check_for_birthdays(self): today = date.today() dm = today.strftime("%d.%m") for key, value in self.birthday_list.items(): for birthday in value: if dm == birthday.DATE: for group in self.GROUPS: if group["NAME"] == key: self.send(birthday.get_congratulation(), group["ID"]) break def get_next_birthday(self, groupInfo): today = datetime.today() format = "%d.%m.%Y" delta = 800 next_birthdays=[] next_birthday_date = None birthday_next_year_string = "" for birthday in self.birthday_list[groupInfo["NAME"]]: # Dieses Jahr birthday_string = f"{birthday.DATE}.{date.today().strftime('%Y')}" birthday_dt = datetime.strptime(birthday_string, format) delta_temp = (birthday_dt - today).days + 1 # Damit er bei 47h nicht 1 Tag sagt if 0 < delta_temp < delta: next_birthday_date = birthday_dt delta = delta_temp else: # Nächstes Jahr (Für den Jahresüberlauf) next_year = date.today() + relativedelta(years=1) birthday_next_year_string = f"{birthday.DATE}.{next_year.strftime('%Y')}" birthday_next_year = datetime.strptime( birthday_next_year_string, format) delta_temp = (birthday_next_year - today).days + 1 # Damit er bei 47h nicht 1 Tag sagt if delta_temp < delta: next_birthday_date = birthday_dt delta = delta_temp message = "Niemand hat hier Geburtstag! Wir sind in einer Zeitschleife gefangen." if next_birthday_date: for birthday in self.birthday_list[groupInfo["NAME"]]: # Dieses Jahr birthday_string = f"{birthday.DATE}.{date.today().strftime('%Y')}" birthday_dt = datetime.strptime(birthday_string, format) if birthday_dt == next_birthday_date: next_birthdays.append(birthday) if delta == 1: message = f"Morgen hat{next_birthdays[0].PERSON} Geburtstag!🎉" if(len(next_birthdays)>1): message=f"Morgen haben" for birthday in next_birthdays: message+=f" {birthday.PERSON} und" message = message[:-4] message+=" Geburtstag!🎉" else: message = f"Als nächstes hat {next_birthdays[0].PERSON} am {next_birthdays[0].DATE} Geburtstag (noch {delta} Tage)" if(len(next_birthdays)>1): message=f"Als nächstes haben" for birthday in next_birthdays: message+=f" {birthday.PERSON} und" message = message[:-4] message+=" am {next_birthdays.DATE} Geburtstag (noch {delta} Tage)" return message def get_birthdaylist(self, groupInfo): message = "Alle Geburtstage:\n" liste = self.birthday_list[groupInfo["NAME"]] # for birthday in liste.sort(): for birthday in liste: message += f"{birthday.PERSON}, {birthday.DATE}\n" return message def interpret_birthday_line(self, line): splitted = line.strip().split(",") if len(splitted) != 2: raise SyntaxError( "Invalid birthday syntax! Needs to be: person, date(Day.Month) eg.: Karl, 02.09") person = splitted[0].strip() if len(person) == 0: raise SyntaxError( "No name given! Needs to be: person, date(Day.Month) eg.: Karl, 02.09") splittedDate = splitted[1].strip().split(".") if len(splitted) != 2: raise SyntaxError( "Invalid date! Needs to be: person, date(Day.Month) eg.: Karl, 02.09") day = splittedDate[0].strip() month = splittedDate[1].strip() if len(day) > 2 or len(month) > 2 or len(day) == 0 or len(month) == 0: raise SyntaxError( "Invalid date! Needs to be: person, date(Day.Month) eg.: Karl, 02.09") if len(day) == 1: day = f"0{day}" if len(month) == 1: month = f"0{month}" return Birthday(person, f"{day}.{month}") def save_birthday(self, message, groupInfo): birthday: Birthday = None try: birthday = self.interpret_birthday_line(message) if birthday in self.birthday_list[groupInfo["NAME"]]: return "Birthday is already saved" self.birthday_list[groupInfo["NAME"]].append(birthday) except (SyntaxError, ValueError) as exc: self.log.warning( f"{self.tag}Error while interpreting birthday line:{message}; Error: {exc}") return f"{exc}" try: with open(groupInfo["BIRTHDAYDIR"], 'a', encoding='utf16') as f: f.write(f"{birthday.get_csv_line()}\n") return "Successfully added birthday" except IOError as exc: self.log.error( f"{self.tag}Adding new birthday'{birthday.get_csv_line()}' to file failed: {exc}") return "Saving birthday failed"