Metadata-Version: 2.4
Name: mobnslib
Version: 1.2.1
Summary: Библиотека для взаимодействия с сетевым дневником (NetSchool)
Author-email: VelimVIM <sliwkimyau@gmail.com>
Project-URL: Homepage, https://github.com/chstudios-ru/mobnslib
Project-URL: Bug Tracker, https://github.com/chstudios-ru/mobnslib/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24.0
Requires-Dist: aiofiles>=23.1.0
Provides-Extra: test
Requires-Dist: pytest>=7.0.0; extra == "test"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
Requires-Dist: python-dotenv; extra == "test"
Requires-Dist: pyotp; extra == "test"
Dynamic: license-file

# mobnslib

Асинхронная библиотека для взаимодействия с мобильным API Сетевого Города (NetSchool) / Сетевого Дневника.
Позволяет производить авторизацию через Госуслуги (ЕСИА), получать информацию об оценках, домашнем задании, расписании и почте.

---

## 📦 Установка

Библиотека опубликована на **PyPI** (конфигурация сборки описана в `pyproject.toml` в корне):

```bash
pip install mobnslib
```

Также можно установить напрямую из репозитория GitHub:

```bash
pip install git+https://github.com/chstudios-ru/mobnslib.git
```
*Для работы библиотеки требуется `httpx`.*

---

## 🚀 Быстрый старт

Пример полной авторизации через ЕСИА и получения дневника на текущую неделю.

```python
import asyncio
from mobnslib import nslib

async def main():
    # 1. Инициализация клиента. Укажите URL вашей школы/региона.
    client = nslib(url="https://school.region.ru/")

    # 2. Авторизация через ЕСИА (Госуслуги)
    print("Авторизация...")
    login_data = await client.esia_login("ВАШ_ТЕЛЕФОН_ИЛИ_СНИЛС", "ВАШ_ПАРОЛЬ")
    
    # Если включена двухфакторная аутентификация (MFA)
    if login_data.get('status') == 'ENTER_MFA':
        mfa_types = {
            "TTP": "из приложения с кодами",
            "MAX": "из макса",
            "SMS": "из смс"
        }
        desc = login_data.get('desc', '')
        source = mfa_types.get(desc, desc)
        code = input(f"Введите код {source}: ")
        login_data = await client.esia_mfa(code, login_data)
        
    # Завершение входа и получение токенов
    tokens = await client.esia_login_end(login_data)
    access_token = tokens['access_token']
    
    # 3. Получение базовой информации об ученике
    info = await client.get_info(access_token)
    student_id = info[0]['id']
    print(f"Привет, {info[0]['firstName']}! Ваш ID: {student_id}")
    
    # 4. Получение дневника (расписания)
    diary = await client.get_diary(access_token, student_id)
    print(f"Получено дней в дневнике: {len(diary)}")

if __name__ == "__main__":
    asyncio.run(main())
```

---

## 📚 Документация по методам

Ниже представлен подробный список всех доступных методов класса `nslib`.
Библиотека разбита на логические модули (API), но все методы вызываются напрямую от экземпляра `client`.

Все основные методы требуют передачи `access_token` (строки). Многие методы требуют `student_id`.

### 🔑 Авторизация (ЕСИА) и токены

* **`esia_login(login, password)`**
  Начинает процесс авторизации.
  Возвращает словарь `login_data`. Если требуется MFA (2FA), ключ `'status'` будет равен `'ENTER_MFA'`, а ключ `'desc'` указывает способ получения кода:
  * `"TTP"` — из приложения с кодами (одноразовые коды TOTP, например Google Authenticator или Яндекс Ключ);
  * `"MAX"` — из приложения / мессенджера Max;
  * `"SMS"` — из SMS-сообщения.
  
  Если MFA не требуется, `'status'` равен `'DONE'`.

* **`esia_mfa(mfa_code, login_data)`**
  Прохождение двухфакторной аутентификации. `login_data` — результат метода `esia_login`. Возвращает обновленный словарь `login_data`.

* **`esia_login_end(login_or_mfa_data)`**
  Завершает авторизацию. Возвращает словарь с токенами: `access_token`, `refresh_token`, `expires_in`, `created_at`.

* **`token_refresh(refresh_token)`**
  Обновляет истекший `access_token`. Возвращает новые `access_token` и `refresh_token`.

### 👤 Информация об ученике и учебе (User API)

* **`get_info(access_token)`**
  Возвращает информацию о текущем пользователе (список профилей). 
  *Пример ответа: `[{ "id": 123456, "firstName": "Иван", "organizations": [...] }]`.*

* **`get_school_year(access_token, student_id)`**
  Возвращает информацию об учебных годах.
  *Ответ: `{"nowYear": 987654, "allYears": [...]}`.* `nowYear` (ID текущего года) нужен для других методов.

* **`get_subjects(access_token, student_id, school_year_id, diary=None)`**
  Возвращает список предметов, изучаемых в заданном учебном году.

* **`get_totals(access_token, student_id, school_year_id)`**
  Возвращает массив со всеми итоговыми (четвертными, годовыми) оценками ученика.

* **`get_terms(access_token, student_id, school_year_id)`**
  Возвращает список учебных периодов (четвертей/триместров) с датами их начала и конца.

* **`get_ver()`**
  Возвращает актуальную версию мобильного API (например, `"1.3.9"`).

* **`get_server_list()`** *(Статический метод)*
  Возвращает список всех доступных серверов (регионов) Сетевого Города, поддерживающих мобильное приложение.
  *Вызов:* `await nslib.get_server_list()`.

### 📓 Дневник, Задания и События (Diary API)

* **`get_diary(access_token, student_id, start_date=None, end_date=None, day=None, pattern='%Y-%m-%d')`**
  Возвращает расписание (список дней и уроков). 
  Если передать параметр `day` (один день), метод вернет расписание на всю неделю, содержащую этот день. 
  Если передать `start_date` и `end_date`, метод вернет расписание за указанный промежуток (можно запросить неделю, месяц и т.д.).
  Даты можно передавать как в виде строк, так и в виде объектов `datetime` или `date`. Формат `pattern` применяется для преобразования дат `day`, `start_date` и `end_date` в нужный строковый формат. По умолчанию возвращает текущую неделю.

* **`get_assignments(access_token, student_id, classmeeting_ids=None, diary=None, limit=20, delay=0.1)`**
  Возвращает подробные данные домашних заданий по урокам. Вы можете передать готовый список уроков `diary` (результат `get_diary`), и метод сам извлечет задания для этих дней.
  * **Зачем параметры `limit` и `delay`**: именно таким образом запрашивает данные официальное мобильное приложение NetSchool — порциями по `limit` элементов с небольшими паузами `delay` между запросами. Разработчики официального клиента неспроста используют эту схему: следование ей обеспечивает безопасную загрузку данных, делает поведение библиотеки неотличимым от штатного мобильного клиента, предотвращает перегрузку сервера Сетевого Города и спасает от ошибок `HTTP 429 Too Many Requests`.

* **`get_attachment_info(access_token, assignment_ids=None, diary=None, limit=20, delay=0.1)`**
  Возвращает метаданные вложений к домашним заданиям. Также может принимать готовый `diary`.
  * **Зачем параметры `limit` и `delay`**: аналогично методу заданий, повторяет проверенный паттерн официального мобильного приложения для порционной загрузки информации о файлах без риска нарваться на блокировки или перегрузить сервер.

* **`load_attachment(access_token, attachment_id)`**
  Скачивает вложение по его ID.

* **`upload_attachment(access_token, student_id, file_path)`**
  Загружает файл на сервер Сетевого Города (для прикрепления к ответу на ДЗ или к письму).

* **`get_announcements(access_token, student_id)`**
  Возвращает список школьных объявлений (на доске объявлений).

* **Методы событий (оценки, новое ДЗ и т.д.):**
  Позволяют получить список событий и итогов за последние 'period_days' (дней):
  - `get_homework_info_events(access_token, student_id, period_days, ...)` — события новых домашних заданий и итогов за последние 'period_days' (дней).
  - `get_result_info_events(...)` — события новых выставленных оценок и итогов за последние 'period_days' (дней).
  - `get_term_total_info_events(...)` — события итоговых оценок за учебный период и итогов за последние 'period_days' (дней).
  - `get_year_total_info_events(...)` — события итоговых оценок за учебный год и итогов за последние 'period_days' (дней).
  - `get_all_events(...)` — получить все типы событий и итогов за последние 'period_days' (дней) разом.

### ✉️ Внутренняя почта (Mail API)

* **`get_mail_unread_count(access_token, student_id)`**
  Возвращает количество непрочитанных писем.

* **Чтение ящиков (постраничная загрузка писем):**
  Сервер возвращает письма не сразу всеми сотнями, а порциями (страницами). По умолчанию возвращаются первые 20 писем (`page=1`, `page_size=20`), отсортированные от самых новых к старым.
  
  Методы возвращают словарь со структурой:
  ```json
  {
    "page": 1,
    "pageSize": 20,
    "totalPages": 5,
    "totalItems": 94,
    "items": [...]
  }
  ```
  * `totalItems` — общее количество писем в ящике;
  * `totalPages` — общее количество страниц;
  * `page` — текущий номер страницы;
  * `pageSize` — размер страницы (количество писем, запрашиваемых за раз);
  * `items` — список самих объектов писем на текущей странице.

  Чтобы получить следующие письма, передавайте номер следующей страницы: `page=2`, `page=3` и т.д.
  Параметр `invert_sort=True` меняет порядок сортировки (по умолчанию `False` — сначала новые, с `True` — сначала старые).

  Доступные методы для разных ящиков:
  - `get_inbox_mails(access_token, student_id, page_size=20, page=1, invert_sort=False)` — входящие.
  - `get_sent_mails(...)` — отправленные.
  - `get_draft_mails(...)` — черновики.
  - `get_deleted_mails(...)` — корзина.

* **`read_mail(access_token, student_id, message_id, page_size=150)`**
  Не только помечает письмо как прочитанное на сервере, но и **возвращает его полный объект со всем содержимым**: телом письма (текстом), темой, автором, подробными списками получателей, прикрепленными вложениями и метаданными.

* **`send_mail(access_token, student_id, subject, text, to_ids, copy=None, hidden_copy=None, attachment_ids=None, message_id=None, notify=False, draft=False)`**
  Отправка нового письма или сохранение черновика:
  * `subject` и `text` — тема и текст сообщения;
  * `to_ids` — список ID основных получателей (поле «Кому»);
  * `copy` — список ID пользователей для открытой копии (поле «Копия», видны всем адресатам);
  * `hidden_copy` — список ID для скрытой копии (поле «Скрытая копия», не видны другим получателям);
  * `attachment_ids` — список ID прикрепленных файлов (предварительно загруженных через `upload_attachment`);
  * `message_id` — ID сообщения при редактировании существующего черновика;
  * `notify` — запрос отчета о прочтении (если `True`, отправителю придет уведомление, когда получатель откроет письмо);
  * `draft` — сохранить в «Черновики» без отправки (если `True`).

* **`delete_mail(access_token, student_id, message_id)`**
  Перемещает письмо в корзину.

* **Шаблоны ответов (возвращают черновик ответа):**
  - `get_sample_reply_mail(access_token, student_id, message_id)` — ответить.
  - `get_sample_reply_all_mail(...)` — ответить всем.
  - `get_sample_forward_mail(...)` — переслать.

### 👥 Адресная книга и ЧС (Address Book)

* **`get_recipients(access_token, student_id, org_id)`**
  Возвращает адресную книгу школы (учителя, администраторы). Требует `org_id` (можно получить из `get_info`).

* **`get_recipient_by_id(access_token, user_id)`**
  Возвращает профиль пользователя по его ID.

* **`block_user(access_token, student_id, user_id)`**
  Добавляет пользователя в черный список почты.

* **`unblock_user(access_token, student_id, user_id)`**
  Удаляет пользователя из черного списка.

* **`get_blocked_users(access_token, student_id)`**
  Возвращает список пользователей, добавленных в черный список.

