/** * @fileoverview Calendars API - работа с календарями (CRUD + подписки) * @module api/calendarsApi */ import { dataManager } from "../managers/dataManager.js"; import { authHeaders, getCsrfToken } from "../utils/authUtils.js"; import { API_URLS, API_DEFAULTS } from "../constants/apiUrls.js"; /** * Получить список доступных календарей текущего пользователя * @param {number} [ttl] - Time to live кеша в мс * @returns {Promise} Массив календарей */ export async function getMyCalendars(ttl = API_DEFAULTS.TTL.CALENDARS) { const key = "calendars:my"; return dataManager.fetch( key, async () => { const url = new URL(API_URLS.CALENDARS, window.location.origin); const response = await fetch(url.toString(), { headers: authHeaders(false), }); if (response.status === 401) { console.warn("[CalendarsAPI] 401 Unauthorized"); return []; } if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); return data.results || []; }, ttl, ); } /** * Получить календарь по ID * @param {number} calendarId - ID календаря * @param {number} [ttl] - Time to live кеша в мс * @returns {Promise} Календарь */ export async function getCalendar(calendarId, ttl = API_DEFAULTS.TTL.CALENDARS) { const key = `calendars:${calendarId}`; return dataManager.fetch( key, async () => { const url = new URL( API_URLS.CALENDAR_DETAIL(calendarId), window.location.origin, ); const response = await fetch(url.toString(), { headers: authHeaders(false), }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); }, ttl, ); } /** * Создать новый календарь * @param {Object} calendarData - Данные календаря * @param {string} calendarData.title - Название * @param {string} [calendarData.description] - Описание * @param {string} [calendarData.color] - Цвет (#RRGGBB) * @param {string} [calendarData.icon] - Иконка * @param {string} [calendarData.visibility] - Видимость (public/private/department/custom) * @param {number} [calendarData.owner_user] - ID владельца-пользователя * @param {number} [calendarData.owner_department] - ID владельца-отдела * @returns {Promise} Созданный календарь */ export async function createCalendar(calendarData) { const url = new URL("/api/v1/calendar/calendars/", window.location.origin); const response = await fetch(url.toString(), { method: "POST", headers: authHeaders(), body: JSON.stringify(calendarData), }); if (!response.ok) { const error = await response .json() .catch(() => ({ detail: response.statusText })); throw new Error(error.detail || `HTTP ${response.status}`); } // Инвалидируем кеш списка календарей dataManager.invalidate("calendars:my"); return response.json(); } /** * Обновить календарь * @param {number} calendarId - ID календаря * @param {Object} updates - Обновления * @returns {Promise} Обновленный календарь */ export async function updateCalendar(calendarId, updates) { const url = new URL( `/api/v1/calendar/calendars/${calendarId}/`, window.location.origin, ); const response = await fetch(url.toString(), { method: "PATCH", headers: authHeaders(), body: JSON.stringify(updates), }); if (!response.ok) { const error = await response .json() .catch(() => ({ detail: response.statusText })); throw new Error(error.detail || `HTTP ${response.status}`); } // Инвалидируем кеш dataManager.invalidate(`calendars:${calendarId}`); dataManager.invalidate("calendars:my"); return response.json(); } /** * Удалить календарь * @param {number} calendarId - ID календаря * @returns {Promise} */ export async function deleteCalendar(calendarId) { const url = new URL( `/api/v1/calendar/calendars/${calendarId}/`, window.location.origin, ); const response = await fetch(url.toString(), { method: "DELETE", headers: authHeaders(false), }); if (!response.ok) { const error = await response .json() .catch(() => ({ detail: response.statusText })); throw new Error(error.detail || `HTTP ${response.status}`); } // Инвалидируем кеш dataManager.invalidate(`calendars:${calendarId}`); dataManager.invalidate("calendars:my"); } /** * Подписаться на календарь * @param {number} calendarId - ID календаря * @param {Object} [options] - Опции подписки * @param {boolean} [options.can_edit] - Право редактирования * @param {boolean} [options.can_manage] - Право управления * @returns {Promise} Данные подписки */ export async function subscribeToCalendar(calendarId, options = {}) { const url = new URL( API_URLS.CALENDAR_SUBSCRIBE(calendarId), window.location.origin, ); const response = await fetch(url.toString(), { method: "POST", headers: authHeaders(), body: JSON.stringify(options), }); if (!response.ok) { const error = await response .json() .catch(() => ({ detail: response.statusText })); throw new Error(error.detail || `HTTP ${response.status}`); } // Инвалидируем кеш dataManager.invalidate(`calendars:${calendarId}`); dataManager.invalidate("calendars:my"); dataManager.invalidate("subscriptions:my"); return response.json(); } /** * Отписаться от календаря * @param {number} calendarId - ID календаря * @returns {Promise} */ export async function unsubscribeFromCalendar(calendarId) { const url = new URL( API_URLS.CALENDAR_UNSUBSCRIBE(calendarId), window.location.origin, ); const response = await fetch(url.toString(), { method: "POST", headers: authHeaders(false), }); if (!response.ok) { const error = await response .json() .catch(() => ({ detail: response.statusText })); throw new Error(error.detail || `HTTP ${response.status}`); } // Инвалидируем кеш dataManager.invalidate(`calendars:${calendarId}`); dataManager.invalidate("calendars:my"); dataManager.invalidate("subscriptions:my"); } /** * Получить мои подписки на календари * @param {number} [ttl=60000] - Time to live кеша в мс * @returns {Promise} Массив подписок */ export async function getMySubscriptions(ttl = 60000) { const key = "subscriptions:my"; return dataManager.fetch( key, async () => { const url = new URL( "/api/v1/calendar/subscriptions/", window.location.origin, ); const response = await fetch(url.toString(), { headers: authHeaders(false), }); if (response.status === 401) { console.warn("[CalendarsAPI] 401 Unauthorized"); return []; } if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); return data.results || []; }, ttl, ); } /** * Инвалидировать весь кеш календарей */ export function invalidateCalendarsCache() { dataManager.invalidatePattern(/^calendars:/); dataManager.invalidatePattern(/^subscriptions:/); }