diff options
| author | matin <matin.kaufmann@gmail.com> | 2025-09-12 20:45:28 +0200 |
|---|---|---|
| committer | matin <matin.kaufmann@gmail.com> | 2025-09-12 20:45:28 +0200 |
| commit | 95d784fb414c6270e560fc0cf7ed289765ddd3ab (patch) | |
| tree | 31f66d2c230634d9325beb82f1125876a3a63e30 /calendar_manager.py | |
| parent | 315bdeffd7b8c7c1a1792cb91d25ff0ac17fecda (diff) | |
AI refactoring (see architecture analysis and refactoring_summary)
Diffstat (limited to 'calendar_manager.py')
| -rw-r--r-- | calendar_manager.py | 234 |
1 files changed, 130 insertions, 104 deletions
diff --git a/calendar_manager.py b/calendar_manager.py index f6ec0db..72a7b3b 100644 --- a/calendar_manager.py +++ b/calendar_manager.py @@ -1,122 +1,99 @@ # calendar_manager.py -import json -import uuid from datetime import datetime - -class CalendarEntry: - def __init__(self, start_date, end_date, keyword, entry_id=None, corrected_start_date=None, corrected_end_date=None, time_period=None, commentary: str = ""): - self.id = entry_id if entry_id else str(uuid.uuid4()) - # Convert string dates to datetime if necessary - self.start_date = ( - datetime.fromisoformat(start_date) - if isinstance(start_date, str) - else start_date - ) - self.end_date = ( - datetime.fromisoformat(end_date) - if isinstance(end_date, str) - else end_date - ) - self.keyword = keyword - self.corrected_start_date = corrected_start_date - self.corrected_end_date = corrected_end_date - self.time_period = time_period - self.commentary = commentary - def to_dict(self): - return { - 'id': self.id, - 'start_date': self.start_date.isoformat(), - 'end_date': self.end_date.isoformat(), - 'keyword': self.keyword, - 'corrected_start_date': self.corrected_start_date.isoformat() if self.corrected_start_date else None, - 'corrected_end_date': self.corrected_end_date.isoformat() if self.corrected_end_date else None, - 'commentary': self.commentary, - } - - @classmethod - def from_dict(cls, data): - return cls( - start_date=datetime.fromisoformat(data['start_date']), - end_date=datetime.fromisoformat(data['end_date']), - keyword=data['keyword'], - entry_id=data['id'], - corrected_start_date=datetime.fromisoformat(data['corrected_start_date']) if data.get('corrected_start_date') else None, - corrected_end_date=datetime.fromisoformat(data['corrected_end_date']) if data.get('corrected_end_date') else None, - commentary=data.get('commentary', ""), - ) - - def __repr__(self): - return (f"CalendarEntry(id={self.id}, start_date={self.start_date}, " - f"end_date={self.end_date}, keyword='{self.keyword}', " - f"corrected_start_date={self.corrected_start_date}, corrected_end_date={self.corrected_end_date})") +from typing import List, Optional, Tuple +from file_service import FileService +from event_type_handler import EventTypeHandler +from date_service import DateService +from config import EventConfig +from calendar_entry import CalendarEntry class CalendarManager: - def __init__(self, filename=None): + """Manages calendar entries with CRUD operations and data integrity""" + + def __init__(self, filename: Optional[str] = None): self.filename = filename - self.entries = [] + self.entries: List[CalendarEntry] = [] if filename: - self.entries = self.add_entries_from_file(filename) + self.load_file(filename) - def switch_file(self, new_filename): - """Switch to a new file.""" + def switch_file(self, new_filename: str): + """Switch to a new file without loading data""" self.filename = new_filename - def load_file(self, new_filename): - """Clears current entries and loads entries from new file.""" + def load_file(self, new_filename: str) -> bool: + """Clear current entries and load entries from new file""" self.clear_entries() - self.add_entries_from_file(new_filename) - self.switch_file(new_filename) + new_entries = FileService.load_calendar_from_file(new_filename) + if new_entries: + self.entries.extend(new_entries) + self.filename = new_filename + return True + return False - def add_entries_from_file(self, file_path): - """Add events from another JSON file to the current calendar.""" - try: - with open(file_path, 'r') as f: - data = json.load(f) - new_entries = [CalendarEntry.from_dict(entry) for entry in data] - self.entries.extend(new_entries) - self.save_entries() - return new_entries - except (FileNotFoundError, json.JSONDecodeError) as e: - print(f"Error reading file {file_path}: {e}") - return [] + def add_entries_from_file(self, file_path: str) -> List[CalendarEntry]: + """Add events from another JSON file to the current calendar""" + new_entries = FileService.load_calendar_from_file(file_path) + if new_entries: + self.entries.extend(new_entries) + self.save_entries() + return new_entries def clear_entries(self): + """Clear all entries from the calendar""" self.entries = [] - def save_entries(self): - """Save the current list of events to the file.""" + def save_entries(self) -> bool: + """Save the current list of events to the file""" if self.filename: - try: - with open(self.filename, 'w') as f: - json.dump([entry.to_dict() for entry in self.entries], f, indent=4) - except Exception as e: - print(f"Error writing to file {self.filename}: {e}") + return FileService.save_calendar_to_file(self.entries, self.filename) + return False - def add_entry(self, start_date, end_date, keyword, commentary: str = ""): - """Add a new event to the calendar.""" - new_entry = CalendarEntry(start_date, end_date, keyword, commentary=commentary) - self.entries.append(new_entry) - self.save_entries() - return new_entry + def add_entry(self, start_date: str, end_date: str, keyword: str, commentary: str = "") -> Optional[CalendarEntry]: + """Add a new event to the calendar with validation""" + try: + # Validate inputs + if not EventTypeHandler.validate_event_type(keyword): + raise ValueError(f"Invalid keyword: {keyword}") + + # Create and add entry + new_entry = CalendarEntry(start_date, end_date, keyword, commentary=commentary) + self.entries.append(new_entry) + self.save_entries() + return new_entry + + except Exception as e: + print(f"Error adding entry: {e}") + return None - def modify_entry(self, entry_id, start_date=None, end_date=None, keyword=None, commentary=None): - """Modify an existing event by ID.""" + def modify_entry(self, entry_id: str, start_date: Optional[str] = None, + end_date: Optional[str] = None, keyword: Optional[str] = None, + commentary: Optional[str] = None) -> Optional[CalendarEntry]: + """Modify an existing event by ID with validation""" entry = self.get_entry_by_id(entry_id) - if entry: + if not entry: + return None + + try: if start_date: - entry.start_date = start_date + entry.start_date = datetime.fromisoformat(start_date) if end_date: - entry.end_date = end_date + entry.end_date = datetime.fromisoformat(end_date) if keyword: + if not EventTypeHandler.validate_event_type(keyword): + raise ValueError(f"Invalid keyword: {keyword}") entry.keyword = keyword if commentary is not None: entry.commentary = commentary + self.save_entries() return entry - return None + + except Exception as e: + print(f"Error modifying entry: {e}") + return None - def delete_entry(self, entry_id): - """Delete an event by ID.""" + def delete_entry(self, entry_id: str) -> Optional[CalendarEntry]: + """Delete an event by ID""" entry = self.get_entry_by_id(entry_id) if entry: self.entries.remove(entry) @@ -124,27 +101,76 @@ class CalendarManager: return entry return None - def get_entry_by_id(self, entry_id): - """Get an event by its ID.""" + def get_entry_by_id(self, entry_id: str) -> Optional[CalendarEntry]: + """Get an event by its ID""" return next((entry for entry in self.entries if entry.id == entry_id), None) - def list_entries(self): - """List all calendar entries.""" - return self.entries + def list_entries(self) -> List[CalendarEntry]: + """List all calendar entries""" + return self.entries.copy() # Return copy to prevent external modification - def correct_dates(self, list_of_events): + def correct_dates(self, corrected_events: List[Tuple[datetime, datetime, str]]): + """Apply corrected dates to calendar entries and calculate time_period""" + # Clear all corrections first for entry in self.entries: entry.corrected_start_date = None entry.corrected_end_date = None entry.time_period = None - for start_date, end_date, original_id in list_of_events: + # Apply corrections and calculate time_period + for start_date, end_date, original_id in corrected_events: entry = self.get_entry_by_id(original_id) - if not entry: - continue - - entry.corrected_start_date = start_date - entry.corrected_end_date = end_date + if entry: + entry.corrected_start_date = start_date + entry.corrected_end_date = end_date + + # Calculate and store time_period based on corrected dates + entry.time_period = self._calculate_time_period(entry) + def get_entries_by_keyword(self, keyword: str) -> List[CalendarEntry]: + """Get all entries with a specific keyword""" + return [entry for entry in self.entries if entry.keyword == keyword] + + def _calculate_time_period(self, entry: CalendarEntry) -> str: + """Calculate time_period for an entry based on corrected dates""" + if not entry.corrected_start_date or not entry.corrected_end_date: + return "" + + start_dt = entry.corrected_start_date + end_dt = entry.corrected_end_date + + if end_dt < start_dt: + return "" + + if entry.keyword == "Sonstige": + # For "Sonstige", show days + delta_days = DateService.calculate_days_between(start_dt, end_dt) + return f"{delta_days} Tage" + else: + # For EZ types, show months + total_months = DateService.calculate_months_between(start_dt, end_dt) + + if entry.keyword == "EZ 50%": + # Half-time projects count as half months + total_months = (total_months + 1) // 2 # Round up + + return f"{total_months} Monate" + + def validate_entry_data(self, start_date: str, end_date: str, keyword: str) -> List[str]: + """Validate entry data and return list of errors""" + errors = [] + + try: + start_dt = datetime.fromisoformat(start_date) + end_dt = datetime.fromisoformat(end_date) + + if start_dt > end_dt: + errors.append("Start date cannot be after end date") -
\ No newline at end of file + except ValueError: + errors.append("Invalid date format") + + if not EventTypeHandler.validate_event_type(keyword): + errors.append(f"Invalid keyword: {keyword}") + + return errors
\ No newline at end of file |
