feature/H-1267: Каталог библиотеки — /library/catalog и /admin/library-category/* #44

Open
anton wants to merge 1 commits from feature/H-1267 into master
+407
View File
@@ -79,6 +79,12 @@ tags:
description: Methods for admin oversight of personal API tokens. Requires "api-tokens-admin" permission.
- name: admin-employment
description: Methods for administrative read-only access to employee employments, including external identifiers used by integrations. Requires "user-edit" permission.
- name: library
description: Корпоративная библиотека (книги). Требуется право `book-access`.
- name: admin-library-category
description: |
Редактор каталога библиотеки: дерево категорий и книг (H-1267). Требуется
право `book-manager`.
paths:
/mobile/bind/{id}/{token}:
@@ -8264,6 +8270,312 @@ paths:
Запись не найдена. Включает случаи обращения к записям,
принадлежащим другим тенантам.
/library/catalog:
get:
tags: [library]
summary: Каталог библиотеки (категории и книги)
description: |
Клиентский каталог библиотеки (H-1267). Контракт идентичен /article/category:
без параметров — корень каталога, с id/hash_id — содержимое категории.
Видимость категорий и книг по группам пользователей применяется автоматически.
operationId: libraryCatalog
security:
- SessionAuth: [ ]
parameters:
- name: id
in: query
required: false
description: ID категории (пусто — корень каталога)
schema: { type: string, format: uuid }
- name: hash_id
in: query
required: false
description: Хэш категории, альтернатива id
schema: { type: string }
- name: q
in: query
required: false
description: Поиск по названию, автору и серии книги
schema: { type: string }
- name: tags
in: query
required: false
description: ID тегов через запятую
schema: { type: string }
responses:
200:
description: Содержимое категории или результаты поиска
content:
application/json:
schema:
type: object
properties:
category:
description: Текущая категория (null для корня)
nullable: true
allOf:
- $ref: '#/components/schemas/libraryCatalogCategory'
categories:
type: array
description: Подкатегории текущей категории
items:
$ref: '#/components/schemas/libraryCatalogCategory'
items:
type: array
description: Книги текущей категории
items:
$ref: '#/components/schemas/libraryCatalogBook'
tags:
type: array
description: Теги, доступные в текущей категории
items:
$ref: '#/components/schemas/tag'
breadcrumbs:
type: array
description: Хлебные крошки (пусто для корня)
items:
type: object
properties:
id: { type: string, format: uuid }
label: { type: string }
url: { type: string }
q:
type: string
nullable: true
description: Поисковый запрос
400: { description: Некорректный id категории }
404: { description: Категория не найдена }
401: { description: Unauthorized request }
403: { description: Unauthorized request }
/admin/library-category/items:
get:
tags: [admin-library-category]
summary: Дерево каталога (один уровень)
description: |
Узлы одного уровня дерева для редактора каталога. Без id — корень,
с id категории — её дети. Дети категорий грузятся лениво повторным
запросом. У категорий в data есть children_count.
operationId: adminLibraryCategoryItems
security:
- SessionAuth: [ ]
parameters:
- name: id
in: query
required: false
description: ID категории (item_id узла, не узла дерева)
schema: { type: string, format: uuid }
responses:
200:
description: Массив узлов дерева
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/libraryCatalogTreeNode'
403: { description: Нет права book-manager }
/admin/library-category/create:
post:
tags: [admin-library-category]
summary: Создать категорию
operationId: adminLibraryCategoryCreate
security:
- SessionAuth: [ ]
requestBody:
content:
application/json:
schema:
type: object
required: [name]
properties:
name: { type: string }
parent_id:
type: string
format: uuid
nullable: true
description: ID родительского узла дерева (null — корень)
responses:
200:
description: Результат (errors при ошибке валидации)
content:
application/json:
schema:
$ref: '#/components/schemas/libraryCatalogEditorResult'
403: { description: Нет права book-manager }
/admin/library-category/update:
put:
tags: [admin-library-category]
summary: Обновить узел дерева (категорию или книгу)
description: |
id — идентификатор УЗЛА дерева (key из items). Для категории принимает
name/description/status_id/thumb_style_id/content_style_id/tags_id/
userGroupsVisibleId/userGroupsHiddenId/image; для книги — title и другие
поля книги. tags_id — строка с ID через запятую. image — объект {id, fid}
(fid обязателен для построения URL картинки категории; image: null — не менять).
Узлы чужих каталогов недоступны (404).
operationId: adminLibraryCategoryUpdate
security:
- SessionAuth: [ ]
parameters:
- name: id
in: query
required: true
schema: { type: string, format: uuid }
requestBody:
content:
application/json:
schema:
type: object
responses:
200:
description: Результат
content:
application/json:
schema:
$ref: '#/components/schemas/libraryCatalogEditorResult'
400: { description: Некорректный uuid }
404: { description: Узел не найден или принадлежит другому каталогу }
/admin/library-category/delete:
delete:
tags: [admin-library-category]
summary: Удалить узел дерева
description: |
Категория удаляется вместе с поддеревом; для книги удаляется только узел
(книга остаётся в библиотеке). id — идентификатор узла дерева.
operationId: adminLibraryCategoryDelete
security:
- SessionAuth: [ ]
parameters:
- name: id
in: query
required: true
schema: { type: string, format: uuid }
responses:
200: { description: Удалено (true) }
400: { description: Некорректный uuid }
404: { description: Узел не найден или принадлежит другому каталогу }
/admin/library-category/update-tree:
post:
tags: [admin-library-category]
summary: Перенести узел в другую категорию
operationId: adminLibraryCategoryUpdateTree
security:
- SessionAuth: [ ]
requestBody:
content:
application/json:
schema:
type: object
required: [childId]
properties:
childId:
type: string
format: uuid
description: ID переносимого узла дерева
parentId:
type: string
format: uuid
nullable: true
description: ID узла целевой категории (null — в корень)
responses:
200: { description: Перенесено }
400: { description: Не передан childId }
404: { description: Узел не найден, либо родитель — не категория }
500: { description: Перенос не выполнен }
/admin/library-category/sort:
post:
tags: [admin-library-category]
summary: Сохранить порядок узлов
description: Карта «ID узла дерева → порядковый номер». Чужие узлы игнорируются.
operationId: adminLibraryCategorySort
security:
- SessionAuth: [ ]
requestBody:
content:
application/json:
schema:
type: object
required: [sort]
properties:
sort:
type: object
additionalProperties: { type: integer }
responses:
200: { description: Сохранено }
400: { description: sort — не объект }
/admin/library-category/create-item:
post:
tags: [admin-library-category]
summary: Добавить книгу в категорию
description: |
entity_id принудительно Entity::Book (375) — подменить нельзя. Дубликаты
по (parent_id, item_id) не создаются.
operationId: adminLibraryCategoryCreateItem
security:
- SessionAuth: [ ]
requestBody:
content:
application/json:
schema:
type: object
required: [item_id]
properties:
item_id:
type: string
format: uuid
description: ID книги
parent_id:
type: string
format: uuid
nullable: true
description: ID узла категории (null — корень)
responses:
200:
description: Результат
content:
application/json:
schema:
$ref: '#/components/schemas/libraryCatalogEditorResult'
404: { description: Родитель не найден или не категория }
/admin/library-category/create-items:
post:
tags: [admin-library-category]
summary: Добавить несколько книг (мультивыбор)
description: Транзакционно; при ошибке валидации любого элемента — полный откат.
operationId: adminLibraryCategoryCreateItems
security:
- SessionAuth: [ ]
requestBody:
content:
application/json:
schema:
type: array
items:
type: object
required: [item_id]
properties:
item_id: { type: string, format: uuid }
parent_id:
type: string
format: uuid
nullable: true
responses:
200:
description: Результат (data — массив созданных узлов)
content:
application/json:
schema:
$ref: '#/components/schemas/libraryCatalogEditorResult'
components:
securitySchemes:
SessionAuth:
@@ -8875,6 +9187,101 @@ components:
items:
$ref: '#/components/schemas/tag'
libraryCatalogCategory:
type: object
description: Категория каталога библиотеки
properties:
id: { type: string, format: uuid }
name: { type: string }
title: { type: string }
description: { type: string, nullable: true }
hash_id: { type: string }
url: { type: string }
status_id:
type: integer
description: 1 - Active, 2 - Disabled
thumb_style_id:
type: integer
description: Превью 1 - картинка и текст, 2 - только текст, 3 - только картинка
content_style_id:
type: integer
description: Вид содержимого 1 - плитка, 2 - список
thumbUrl: { type: string }
imageUrl: { type: string }
iconUrl: { type: string }
tags:
type: array
items:
$ref: '#/components/schemas/tag'
libraryCatalogBook:
type: object
description: Книга в каталоге библиотеки (состав полей карточки книги)
properties:
id: { type: string, format: uuid }
entity_id: { type: integer, example: 375 }
entityId: { type: integer, example: 375 }
name: { type: string, description: Совпадает с title }
title: { type: string }
description: { type: string, nullable: true }
url: { type: string }
status_id:
type: integer
description: 1 - В библиотеке, 2 - На руках, 3 - Удалена
statusName: { type: string }
author: { type: string, nullable: true }
series: { type: string, nullable: true }
publishing_house: { type: string, nullable: true }
year_issue: { type: integer, nullable: true }
page_quantity: { type: integer, nullable: true }
read_quantity: { type: integer, nullable: true }
is_print: { type: boolean, description: Есть бумажная версия }
thumbUrl: { type: string, description: Обложка (или плейсхолдер) }
thumbMiniCubeUrl: { type: string }
tags:
type: array
items:
$ref: '#/components/schemas/tag'
countLike: { type: integer }
isLikeUser: { type: boolean }
isFavoriteUser: { type: boolean }
isOnHandUser: { type: boolean, description: Книга сейчас на руках }
libraryCatalogTreeNode:
type: object
description: Узел дерева редактора каталога библиотеки
properties:
key:
type: string
format: uuid
description: ID узла дерева (hr_category_tree_item)
title: { type: string }
folder: { type: boolean, description: true — категория }
lazy: { type: boolean, description: Дети грузятся отдельным запросом }
children:
type: array
nullable: true
description: null — не загружены (лениво)
items: { type: object }
data:
type: object
description: |
treeData сущности. Для категории — поля libraryCatalogCategory плюс item_id,
children_count, userGroupsVisible/Hidden, organization_id, isTenantSynced.
Для книги — поля libraryCatalogBook плюс item_id.
libraryCatalogEditorResult:
type: object
description: Единый формат ответа редактора каталога
properties:
success: { type: boolean }
data:
nullable: true
description: Созданный/обновлённый узел (или массив узлов для create-items)
errors:
nullable: true
description: Ошибки валидации (null при успехе)
calendarEventType:
type: object
properties: