Spaces:
Sleeping
Sleeping
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
|