842 lines
33 KiB
YAML
842 lines
33 KiB
YAML
openapi: 3.0.3
|
||
|
||
info:
|
||
title: Sarex Resources API
|
||
version: "1.0.0"
|
||
description: |
|
||
REST API сервиса **sarex-resources** (`platform/sarex-resources`) — управление
|
||
ресурсами/проектами, их типами (иерархия), локациями, а также разрешениями
|
||
сервисных аккаунтов на ресурсы и на компании.
|
||
|
||
Сервис написан на Python (**Django 4.1 + Django REST Framework**, GeoDjango/PostGIS).
|
||
Роутинг задаётся в `server/config/urls.py`:
|
||
|
||
- `resource-management/` — Django-admin;
|
||
- `api/v1/` — основной API (`apps.resource.urls`);
|
||
- `api/v2/` — расширенный API ресурсов (`apps.resource.urls_v2`).
|
||
|
||
Списочные и CRUD-эндпоинты строятся `rest_framework.routers.DefaultRouter`
|
||
поверh `ModelViewSet`; часть операций — отдельные `APIView`.
|
||
|
||
### Аутентификация
|
||
На уровне приложения аутентификация и permission-классы DRF **отключены**
|
||
(`DEFAULT_AUTHENTICATION_CLASSES = []`, permission-классы не заданы —
|
||
эффективно `AllowAny`). Ограничение доступа обеспечивается сетевым слоем
|
||
(istio/ingress, внутрикластерный доступ к `sarex-resources-service`).
|
||
|
||
### Пагинация
|
||
Используется `rest_framework.pagination.LimitOffsetPagination` с очень большим
|
||
`PAGE_SIZE` (100000). Списочные ответы оборачиваются в
|
||
`{ count, next, previous, results }`; постранично управляется параметрами
|
||
`limit` и `offset`.
|
||
|
||
### Идентификаторы ресурсов
|
||
У ресурса есть внутренний `id` (int, в API почти не используется), публичный
|
||
`public_id`/`id` (UUID — основной идентификатор в URL detail-эндпоинтов v1/v2)
|
||
и устаревший `target_id` (`_target_id`, int) для обратной совместимости.
|
||
Удаление — «мягкое» (`deleted=True`), объекты с `deleted=True` из выборок
|
||
исключаются.
|
||
|
||
### Замечания (расхождения кода)
|
||
- Detail-роуты `resource` в v1/v2 ищут объект по `public_id` (UUID), а не по
|
||
первичному ключу; путь при этом выглядит как `/api/v1/resource/{public_id}/`.
|
||
- Ряд аналитических эндпоинтов (`users-grouped-by-resource`,
|
||
`users-with-resources`, `resources-grouped-by-sa`) возвращают
|
||
«сырые» структуры (`dict`/списки), не обёрнутые в пагинацию.
|
||
- `bulk_delete/resource_permission/` и `permissions-bulk/` выполняют
|
||
**жёсткое** удаление разрешений (`.delete()`), в отличие от «мягкого»
|
||
удаления сущностей.
|
||
- `RetrieveResourceByTargetIdAPIView` при отсутствии ресурса возвращает
|
||
`404` без тела.
|
||
|
||
contact:
|
||
name: sarex-resources
|
||
url: https://gitlab/platform/sarex-resources
|
||
|
||
servers:
|
||
- url: https://api.sarex.io/resource-management
|
||
description: Production admin (istio VirtualService, prefix /resource-management)
|
||
- url: http://sarex-resources-service.resources-prod
|
||
description: Внутрикластерный адрес (ClusterIP), production namespace
|
||
- url: http://sarex-resources-service.resources-stage
|
||
description: Внутрикластерный адрес (ClusterIP), stage namespace
|
||
- url: http://localhost:8888
|
||
description: Локальный запуск (docker-compose, 8888 → 8000)
|
||
|
||
tags:
|
||
- name: resources
|
||
description: Ресурсы (проекты)
|
||
- name: resources_v2
|
||
description: Расширенные ресурсы (api/v2)
|
||
- name: resource_types
|
||
description: Типы ресурсов (иерархия)
|
||
- name: locations
|
||
description: Локации (гео-данные)
|
||
- name: resource_permissions
|
||
description: Разрешения сервисных аккаунтов на ресурсы
|
||
- name: company_permissions
|
||
description: Разрешения сервисных аккаунтов на компании
|
||
- name: analytics
|
||
description: Служебные/аналитические эндпоинты (группировки, интеграция с Sarex)
|
||
|
||
paths:
|
||
|
||
/api/v1/resource/:
|
||
get:
|
||
tags: [resources]
|
||
summary: Список ресурсов
|
||
parameters:
|
||
- { name: tenant_id, in: query, schema: { type: string }, description: "ID компании; поддерживает список через запятую" }
|
||
- { name: type, in: query, schema: { type: integer } }
|
||
- { name: parent, in: query, schema: { type: integer }, description: "ID родителя; фильтрация по поддереву (ltree)" }
|
||
- { name: show_in_overview, in: query, schema: { type: boolean } }
|
||
- { name: id, in: query, schema: { type: string }, description: "public_id (UUID); список через запятую" }
|
||
- { name: target_id, in: query, schema: { type: string }, description: "устаревший target_id; список через запятую" }
|
||
- { name: service_accounts, in: query, schema: { type: string }, description: "UUID сервисных аккаунтов через запятую (доступные ресурсы)" }
|
||
- { name: limit, in: query, schema: { type: integer } }
|
||
- { name: offset, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/PaginatedResourceList"
|
||
post:
|
||
tags: [resources]
|
||
summary: Создать ресурс
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceWrite" }
|
||
responses:
|
||
"201":
|
||
description: Created
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceWrite" }
|
||
|
||
/api/v1/resource/{public_id}/:
|
||
parameters:
|
||
- { name: public_id, in: path, required: true, schema: { type: string, format: uuid } }
|
||
get:
|
||
tags: [resources]
|
||
summary: Получить ресурс по public_id
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceRetrieve" }
|
||
"404": { description: Не найден }
|
||
delete:
|
||
tags: [resources]
|
||
summary: Мягкое удаление ресурса (deleted=true)
|
||
responses:
|
||
"204": { description: No Content }
|
||
|
||
/api/v1/resource_type/:
|
||
get:
|
||
tags: [resource_types]
|
||
summary: Список типов ресурсов
|
||
parameters:
|
||
- { name: parent, in: query, schema: { type: integer }, description: "ID родителя; фильтрация по поддереву" }
|
||
- { name: limit, in: query, schema: { type: integer } }
|
||
- { name: offset, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/PaginatedResourceTypeList" }
|
||
post:
|
||
tags: [resource_types]
|
||
summary: Создать тип ресурса
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceTypeWrite" }
|
||
responses:
|
||
"201":
|
||
description: Created
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceTypeWrite" }
|
||
|
||
/api/v1/resource_type/filters/:
|
||
get:
|
||
tags: [resource_types]
|
||
summary: "Значения фильтра типов ресурсов (потомки родителя)"
|
||
parameters:
|
||
- { name: parent, in: query, schema: { type: integer }, description: "ID родителя; вернёт его потомков" }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
parent:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
|
||
/api/v1/resource_type/{id}/:
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer } }
|
||
get:
|
||
tags: [resource_types]
|
||
summary: Получить тип ресурса
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceTypeRetrieve" }
|
||
delete:
|
||
tags: [resource_types]
|
||
summary: Мягкое удаление типа ресурса
|
||
responses:
|
||
"204": { description: No Content }
|
||
|
||
/api/v1/location/:
|
||
get:
|
||
tags: [locations]
|
||
summary: Список локаций
|
||
parameters:
|
||
- { name: limit, in: query, schema: { type: integer } }
|
||
- { name: offset, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/PaginatedLocationList" }
|
||
post:
|
||
tags: [locations]
|
||
summary: Создать локацию
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/LocationWrite" }
|
||
responses:
|
||
"201":
|
||
description: Created
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/LocationWrite" }
|
||
|
||
/api/v1/location/{id}/:
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer } }
|
||
get:
|
||
tags: [locations]
|
||
summary: Получить локацию
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/LocationRetrieve" }
|
||
delete:
|
||
tags: [locations]
|
||
summary: Мягкое удаление локации
|
||
responses:
|
||
"204": { description: No Content }
|
||
|
||
/api/v1/resource_permission/:
|
||
get:
|
||
tags: [resource_permissions]
|
||
summary: Список разрешений на ресурсы
|
||
parameters:
|
||
- { name: public_resource_id, in: query, schema: { type: string }, description: "UUID через запятую" }
|
||
- { name: resource_id, in: query, schema: { type: string }, description: "внутренние id через запятую" }
|
||
- { name: service_account, in: query, schema: { type: string }, description: "UUID через запятую" }
|
||
- { name: tenant_id, in: query, schema: { type: string }, description: "ID компаний через запятую (по resource.tenant_id)" }
|
||
- { name: company_id, in: query, schema: { type: string }, description: "синоним tenant_id" }
|
||
- { name: limit, in: query, schema: { type: integer } }
|
||
- { name: offset, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/PaginatedResourcePermissionList" }
|
||
post:
|
||
tags: [resource_permissions]
|
||
summary: "Создать разрешение(я) на ресурс"
|
||
description: "Принимает один объект или массив (bulk). Поле resource определяется по public_resource_id."
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- $ref: "#/components/schemas/ResourcePermissionWrite"
|
||
- type: array
|
||
items: { $ref: "#/components/schemas/ResourcePermissionWrite" }
|
||
responses:
|
||
"201":
|
||
description: Created
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- $ref: "#/components/schemas/ResourcePermissionWrite"
|
||
- type: array
|
||
items: { $ref: "#/components/schemas/ResourcePermissionWrite" }
|
||
|
||
/api/v1/resource_permission/{id}/:
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer } }
|
||
get:
|
||
tags: [resource_permissions]
|
||
summary: Получить разрешение на ресурс
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourcePermissionRetrieve" }
|
||
delete:
|
||
tags: [resource_permissions]
|
||
summary: Мягкое удаление разрешения
|
||
responses:
|
||
"204": { description: No Content }
|
||
|
||
/api/v1/company_resource_permission/:
|
||
get:
|
||
tags: [company_permissions]
|
||
summary: Список разрешений на компании
|
||
parameters:
|
||
- { name: service_account, in: query, schema: { type: string }, description: "UUID через запятую" }
|
||
- { name: tenant_id, in: query, schema: { type: string }, description: "ID компаний через запятую" }
|
||
- { name: limit, in: query, schema: { type: integer } }
|
||
- { name: offset, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/PaginatedCompanyPermissionList" }
|
||
post:
|
||
tags: [company_permissions]
|
||
summary: "Создать разрешение(я) на компанию"
|
||
description: "Принимает один объект или массив (bulk_create)."
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
oneOf:
|
||
- $ref: "#/components/schemas/CompanyPermission"
|
||
- type: array
|
||
items: { $ref: "#/components/schemas/CompanyPermission" }
|
||
responses:
|
||
"201":
|
||
description: Created
|
||
|
||
/api/v1/company_resource_permission/{id}/:
|
||
parameters:
|
||
- { name: id, in: path, required: true, schema: { type: integer } }
|
||
get:
|
||
tags: [company_permissions]
|
||
summary: Получить разрешение на компанию
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/CompanyPermission" }
|
||
delete:
|
||
tags: [company_permissions]
|
||
summary: Мягкое удаление разрешения на компанию
|
||
responses:
|
||
"204": { description: No Content }
|
||
|
||
/api/v1/targets/{target_id}/resource/:
|
||
get:
|
||
tags: [resources]
|
||
summary: Получить ресурс по устаревшему target_id
|
||
parameters:
|
||
- { name: target_id, in: path, required: true, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceRetrieve" }
|
||
"404": { description: Не найден }
|
||
|
||
/api/v1/bulk_delete/resource_permission/:
|
||
post:
|
||
tags: [resource_permissions]
|
||
summary: Массовое (жёсткое) удаление разрешений на ресурсы
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: array
|
||
items: { type: integer }
|
||
required: [id]
|
||
responses:
|
||
"200": { description: OK }
|
||
"400": { description: "id не передан или содержит не-int" }
|
||
|
||
/api/v1/service-accounts/:
|
||
get:
|
||
tags: [analytics]
|
||
summary: Сервисные аккаунты, имеющие доступ к ресурсу
|
||
description: "Нужно указать ровно один из resource_id (UUID) или target_id (int)."
|
||
parameters:
|
||
- { name: resource_id, in: query, schema: { type: string, format: uuid } }
|
||
- { name: target_id, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
results:
|
||
type: array
|
||
items: { type: string, format: uuid }
|
||
"400": { description: "не указан либо указаны оба параметра / ошибка парсинга" }
|
||
"404": { description: Ресурс не найден }
|
||
|
||
/api/v1/users-grouped-by-resource/:
|
||
get:
|
||
tags: [analytics]
|
||
summary: "Пользователи, сгруппированные по ресурсам"
|
||
description: "Обращается к ядру Sarex за списком пользователей. Возвращает map resource_id → [user_id]."
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties:
|
||
type: array
|
||
items: { type: integer }
|
||
|
||
/api/v1/resources-grouped-by-sa/:
|
||
get:
|
||
tags: [analytics]
|
||
summary: "Ресурсы, сгруппированные по сервисным аккаунтам"
|
||
description: "Учитывает прямые (read) и компанейские разрешения. Возвращает map service_account → [public_resource_id]."
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
additionalProperties:
|
||
type: array
|
||
items: { type: string, format: uuid }
|
||
|
||
/api/v1/users-with-resources/:
|
||
post:
|
||
tags: [analytics]
|
||
summary: "Доступные ресурсы для списка пользователей в рамках компании"
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: array
|
||
items: { type: integer }
|
||
tenant_id: { type: integer }
|
||
required: [id, tenant_id]
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
results:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
unrestricted_access: { type: boolean }
|
||
resources:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
id: { type: string, format: uuid }
|
||
name: { type: string }
|
||
"400": { description: "не передан id или tenant_id / некорректный tenant_id" }
|
||
|
||
/api/v1/permissions-bulk/:
|
||
patch:
|
||
tags: [resource_permissions]
|
||
summary: "Синхронизация (bulk) разрешений на ресурсы и компании"
|
||
description: |
|
||
Приводит разрешения к переданному состоянию: создаёт недостающие,
|
||
удаляет лишние (жёстко). `permissions` — map service_account → [resource_id],
|
||
`unrestricted_permissions` — map service_account → bool (доступ ко всей компании).
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
tenant_id: { type: integer }
|
||
permissions:
|
||
type: object
|
||
additionalProperties:
|
||
type: array
|
||
items: { type: string, format: uuid }
|
||
unrestricted_permissions:
|
||
type: object
|
||
additionalProperties: { type: boolean }
|
||
required: [tenant_id, permissions]
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/api/v2/resource/:
|
||
get:
|
||
tags: [resources_v2]
|
||
summary: Список расширенных ресурсов
|
||
parameters:
|
||
- { name: tenant_id, in: query, schema: { type: string }, description: "список через запятую" }
|
||
- { name: type, in: query, schema: { type: integer } }
|
||
- { name: parent, in: query, schema: { type: integer } }
|
||
- { name: show_in_overview, in: query, schema: { type: boolean } }
|
||
- { name: id, in: query, schema: { type: string }, description: "public_id (UUID) через запятую" }
|
||
- { name: target_id, in: query, schema: { type: integer } }
|
||
- { name: service_accounts, in: query, schema: { type: string } }
|
||
- { name: limit, in: query, schema: { type: integer } }
|
||
- { name: offset, in: query, schema: { type: integer } }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/PaginatedResourceExpandedList" }
|
||
post:
|
||
tags: [resources_v2]
|
||
summary: Создать расширенный ресурс
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceExpandedWrite" }
|
||
responses:
|
||
"201":
|
||
description: Created
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceExpandedWrite" }
|
||
|
||
/api/v2/resource/{public_id}/:
|
||
parameters:
|
||
- { name: public_id, in: path, required: true, schema: { type: string, format: uuid } }
|
||
- { name: tenant_id, in: query, schema: { type: string }, description: "фильтр по компаниям (через запятую) при retrieve" }
|
||
get:
|
||
tags: [resources_v2]
|
||
summary: Получить расширенный ресурс по public_id
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceExpandedRetrieve" }
|
||
"404": { description: "there is no resource with provided id" }
|
||
patch:
|
||
tags: [resources_v2]
|
||
summary: Частичное обновление расширенного ресурса
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceExpandedPartialUpdate" }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ResourceExpandedPartialUpdate" }
|
||
delete:
|
||
tags: [resources_v2]
|
||
summary: Мягкое удаление расширенного ресурса
|
||
responses:
|
||
"204": { description: No Content }
|
||
|
||
components:
|
||
|
||
schemas:
|
||
|
||
PermissionType:
|
||
type: integer
|
||
description: "0=read, 1=write, 2=delete, 3=admin"
|
||
enum: [0, 1, 2, 3]
|
||
|
||
ResourceRetrieve:
|
||
type: object
|
||
properties:
|
||
id: { type: string, format: uuid, description: "public_id" }
|
||
name: { type: string }
|
||
type: { type: integer, nullable: true }
|
||
tenant_id: { type: integer }
|
||
location: { type: integer, nullable: true }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer }
|
||
target_id: { type: integer, nullable: true }
|
||
code: { type: string }
|
||
|
||
ResourceWrite:
|
||
type: object
|
||
properties:
|
||
id: { type: string, format: uuid, nullable: true, readOnly: true }
|
||
name: { type: string }
|
||
type: { type: integer, nullable: true }
|
||
tenant_id: { type: integer }
|
||
location: { type: integer, nullable: true }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer }
|
||
target_id: { type: integer, nullable: true }
|
||
code: { type: string }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [name, tenant_id, target_id]
|
||
|
||
PaginatedResourceList:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, nullable: true }
|
||
previous: { type: string, nullable: true }
|
||
results:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/ResourceRetrieve" }
|
||
|
||
ResourceTypeRetrieve:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer }
|
||
|
||
ResourceTypeWrite:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
name: { type: string }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [name]
|
||
|
||
PaginatedResourceTypeList:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, nullable: true }
|
||
previous: { type: string, nullable: true }
|
||
results:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/ResourceTypeRetrieve" }
|
||
|
||
LocationRetrieve:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
coordinate_system: { type: integer }
|
||
geometry: { type: object, description: "GeoJSON-геометрия" }
|
||
geography: { type: object, description: "GeoJSON-геометрия (geography)" }
|
||
latitude: { type: string, format: decimal }
|
||
longitude: { type: string, format: decimal }
|
||
created_by: { type: integer }
|
||
|
||
LocationWrite:
|
||
allOf:
|
||
- $ref: "#/components/schemas/LocationRetrieve"
|
||
- type: object
|
||
properties:
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [name, coordinate_system, geometry, geography, latitude, longitude]
|
||
|
||
PaginatedLocationList:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, nullable: true }
|
||
previous: { type: string, nullable: true }
|
||
results:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/LocationRetrieve" }
|
||
|
||
ResourcePermissionRetrieve:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
service_account: { type: string, format: uuid }
|
||
public_resource_id: { type: string, format: uuid }
|
||
type: { $ref: "#/components/schemas/PermissionType" }
|
||
created_by: { type: integer }
|
||
|
||
ResourcePermissionWrite:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
service_account: { type: string, format: uuid }
|
||
public_resource_id: { type: string, format: uuid }
|
||
type: { $ref: "#/components/schemas/PermissionType" }
|
||
created_by: { type: integer }
|
||
resource: { type: integer, description: "заполняется сервером по public_resource_id" }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [service_account, public_resource_id]
|
||
|
||
PaginatedResourcePermissionList:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, nullable: true }
|
||
previous: { type: string, nullable: true }
|
||
results:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/ResourcePermissionRetrieve" }
|
||
|
||
CompanyPermission:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, readOnly: true }
|
||
service_account: { type: string, format: uuid }
|
||
tenant_id: { type: integer }
|
||
created_by: { type: integer }
|
||
created_at: { type: string, format: date-time, readOnly: true }
|
||
updated_at: { type: string, format: date-time, readOnly: true }
|
||
required: [service_account, tenant_id]
|
||
|
||
PaginatedCompanyPermissionList:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, nullable: true }
|
||
previous: { type: string, nullable: true }
|
||
results:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/CompanyPermission" }
|
||
|
||
ResourcePhoto:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
author_id: { type: integer }
|
||
created_at: { type: string, format: date-time }
|
||
image: { type: string, format: uri }
|
||
|
||
ResourceExpandedRead:
|
||
type: object
|
||
properties:
|
||
id: { type: string, format: uuid }
|
||
name: { type: string }
|
||
type: { type: integer, nullable: true }
|
||
tenant_id: { type: integer }
|
||
location: { type: integer, nullable: true }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer }
|
||
target_id: { type: integer, nullable: true }
|
||
code: { type: string }
|
||
description: { type: string }
|
||
location_verbose: { type: string }
|
||
latitude: { type: number, format: float }
|
||
longitude: { type: number, format: float }
|
||
photos:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/ResourcePhoto" }
|
||
attributes: { type: object }
|
||
planning_widget_id: { type: integer, nullable: true }
|
||
work_schedule_project_id: { type: integer, nullable: true }
|
||
show_in_overview: { type: boolean }
|
||
widgets: { type: object }
|
||
meta: { type: object }
|
||
|
||
ResourceExpandedRetrieve:
|
||
allOf:
|
||
- $ref: "#/components/schemas/ResourceExpandedRead"
|
||
|
||
PaginatedResourceExpandedList:
|
||
type: object
|
||
properties:
|
||
count: { type: integer }
|
||
next: { type: string, nullable: true }
|
||
previous: { type: string, nullable: true }
|
||
results:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/ResourceExpandedRead" }
|
||
|
||
ResourceExpandedWrite:
|
||
type: object
|
||
properties:
|
||
id: { type: string, format: uuid, nullable: true, readOnly: true }
|
||
name: { type: string }
|
||
type: { type: integer, nullable: true }
|
||
tenant_id: { type: integer }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer }
|
||
target_id: { type: integer, nullable: true }
|
||
description: { type: string }
|
||
location_verbose: { type: string }
|
||
latitude: { type: number, format: float }
|
||
longitude: { type: number, format: float }
|
||
attributes: { type: object }
|
||
planning_widget_id: { type: integer, nullable: true }
|
||
work_schedule_project_id: { type: integer, nullable: true }
|
||
code: { type: string }
|
||
show_in_overview: { type: boolean }
|
||
widgets: { type: object }
|
||
meta: { type: object }
|
||
required: [name, tenant_id, target_id]
|
||
|
||
ResourceExpandedPartialUpdate:
|
||
type: object
|
||
properties:
|
||
id: { type: string, format: uuid, readOnly: true }
|
||
name: { type: string }
|
||
type: { type: integer, nullable: true }
|
||
tenant_id: { type: integer, readOnly: true }
|
||
location: { type: integer, nullable: true }
|
||
parent_id: { type: integer, nullable: true }
|
||
created_by: { type: integer, readOnly: true }
|
||
target_id: { type: integer, readOnly: true }
|
||
code: { type: string }
|
||
description: { type: string }
|
||
location_verbose: { type: string }
|
||
latitude: { type: number, format: float }
|
||
longitude: { type: number, format: float }
|
||
attributes: { type: object }
|
||
planning_widget_id: { type: integer, nullable: true }
|
||
show_in_overview: { type: boolean }
|
||
widgets: { type: object }
|
||
meta: { type: object }
|