File size: 8,338 Bytes
ca8ebf7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import datetime
import os
import sys

class GoogleCalendarExporter:
    """
    Класс для экспорта задач в Google Calendar
    """
    
    def __init__(self, credentials_path='credentials/google-credentials.json', calendar_id='primary'):
        """
        Инициализация подключения к Google Calendar
        
        Args:
            credentials_path: путь к JSON-файлу с ключами сервисного аккаунта
            calendar_id: ID календаря ('primary' для основного или конкретный ID)
        """
        self.credentials_path = credentials_path
        self.calendar_id = calendar_id
        self.service = None
        
        # Проверяем наличие файла с ключами
        if not os.path.exists(credentials_path):
            print(f"❌ Файл с ключами не найден: {credentials_path}")
            print("💡 Убедитесь, что файл лежит в папке credentials/")
            sys.exit(1)
        
        self._authenticate()
    
    def _authenticate(self):
        """Аутентификация в Google Calendar API через сервисный аккаунт"""
        try:
            # Определяем права доступа (нужны для записи)
            SCOPES = ['https://www.googleapis.com/auth/calendar']  # Полный доступ к календарю [citation:6]
            
            # Загружаем ключи сервисного аккаунта [citation:5]
            credentials = service_account.Credentials.from_service_account_file(
                self.credentials_path, 
                scopes=SCOPES
            )
            
            # Создаем сервис для работы с Calendar API [citation:6]
            self.service = build('calendar', 'v3', credentials=credentials)
            print("✅ Успешная аутентификация в Google Calendar")
            
        except Exception as e:
            print(f"❌ Ошибка аутентификации: {e}")
            sys.exit(1)
    
    def create_event_from_task(self, task):
        """
        Создает событие в календаре из задачи
        
        Args:
            task: словарь с данными задачи (number, summary, full_description, responsible, due_date, due_date_str)
        
        Returns:
            ссылка на созданное событие или None при ошибке
        """
        if not self.service:
            print("❌ Сервис не инициализирован")
            return None
        
        # Проверяем наличие даты
        if not task.get('due_date'):
            print(f"⚠️ Задача #{task.get('number', '?')} пропущена: нет даты")
            return None
        
        try:
            # Формируем событие
            due_date = task['due_date']
            
            # Создаем событие на целый день (если не указано время) [citation:6]
            # Или можно задать конкретное время, например 10:00
            event_date = due_date.strftime('%Y-%m-%d')
            
            # Берем краткое описание или начало полного
            summary = task.get('summary', '')
            if not summary:
                summary = task.get('full_description', '')[:50] + '...'
            
            # Формируем описание события
            description = f"""
📋 Задача #{task.get('number', '?')}

📝 Полное описание:
{task.get('full_description', '')}

👤 Ответственный: {task.get('responsible', 'Не указан')}

📅 Срок: {task.get('due_date_str', '')}

🔗 Создано автоматически парсером задач
            """.strip()
            
            # Создаем событие [citation:6]
            event = {
                'summary': f"Задача #{task['number']}: {summary}",
                'description': description,
                'start': {
                    'date': event_date,  # Целый день
                },
                'end': {
                    'date': event_date,  # Целый день
                },
                'reminders': {
                    'useDefault': True  # Использовать стандартные напоминания
                }
            }
            
            # Добавляем время, если нужно (например, сделать на 10:00)
            # event['start']['dateTime'] = f"{event_date}T10:00:00+03:00"
            # event['end']['dateTime'] = f"{event_date}T11:00:00+03:00"
            
            # Создаем событие в календаре [citation:1]
            created_event = self.service.events().insert(
                calendarId=self.calendar_id,
                body=event
            ).execute()
            
            print(f"✅ Событие создано: {created_event.get('htmlLink')}")
            return created_event.get('htmlLink')
            
        except HttpError as e:
            print(f"❌ Ошибка API при создании события для задачи #{task.get('number', '?')}: {e}")
            return None
        except Exception as e:
            print(f"❌ Неожиданная ошибка для задачи #{task.get('number', '?')}: {e}")
            return None
    
    def create_events_from_tasks(self, tasks):
        """
        Создает события для списка задач
        
        Args:
            tasks: список словарей с задачами
        
        Returns:
            список ссылок на созданные события
        """
        results = []
        
        print(f"\n📅 Создание событий в календаре (ID: {self.calendar_id})...")
        
        for task in tasks:
            event_link = self.create_event_from_task(task)
            if event_link:
                results.append({
                    'task_number': task.get('number'),
                    'task_summary': task.get('summary', '')[:30] + '...',
                    'event_link': event_link
                })
        
        print(f"\n✅ Создано {len(results)} событий из {len(tasks)} задач")
        return results
    
    def check_calendar_access(self):
        """Проверяет доступ к календарю (выводит список ближайших событий)"""
        try:
            now = datetime.datetime.utcnow().isoformat() + 'Z'
            events_result = self.service.events().list(
                calendarId=self.calendar_id,
                timeMin=now,
                maxResults=5,
                singleEvents=True,
                orderBy='startTime'
            ).execute()
            
            events = events_result.get('items', [])
            
            if not events:
                print("📭 В календаре нет предстоящих событий")
            else:
                print(f"📅 Ближайшие события в календаре:")
                for event in events:
                    start = event['start'].get('dateTime', event['start'].get('date'))
                    print(f"   • {start}: {event.get('summary', 'Без названия')}")
            
            return True
            
        except HttpError as e:
            print(f"❌ Ошибка доступа к календарю: {e}")
            print("💡 Проверьте, что:")
            print("   1. Calendar API включен в Google Cloud Console")
            print("   2. Календарь расшарен на email сервисного аккаунта")
            print("   3. Calendar ID указан правильно")
            return False