diff --git a/.gitignore b/.gitignore index 723ef36f4e4f32c4560383aa5987c575a30c6535..34142fe5c91654493d8dd95e68e432b6351f3196 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.idea \ No newline at end of file +.idea +dist/ +release/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 72a02bb52c2be573baee3f2c4f01e9c6680183a3..83f34df990ff1e4a1a128755bcfe548b02aa41ec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,9 @@ -image: golang:latest +image: golang:1.22 stages: - test + - pre-release + - release run_tests: rules: @@ -27,3 +29,125 @@ lint: codequality: gl-code-quality-report.json paths: - gl-code-quality-report.json + +# ----- prepare release ----- + +# Расчет тега и формирование Changelog +get_changelog: + stage: pre-release + image: + name: orhunp/git-cliff:latest + entrypoint: [ "" ] + rules: + - if: '$CI_PIPELINE_SOURCE == "pipeline" && $PREPARE_RELEASE == "true"' # Запуск при инициации из perxis + - if: $CI_PIPELINE_SOURCE == "web" # или при ручном запуске из GUI + when: manual + variables: + GIT_STRATEGY: clone + GIT_DEPTH: 0 + script: + - echo "$(git-cliff --unreleased | sed '1,6d' | sed '$d')" > current_changelog.md # удалить "лишние" строки для Changelog + artifacts: + reports: + dotenv: vars.env # Use artifacts:reports:dotenv to expose the variables to other jobs + paths: + - current_changelog.md + +# Релиз и запись тега в артефакт для использования в perxis +prepare_release: + stage: pre-release + image: bitnami/git:latest + variables: + GIT_DEPTH: 0 + GIT_STRATEGY: clone + rules: + - if: '$CI_PIPELINE_SOURCE == "pipeline" && $PREPARE_RELEASE == "true"' + - if: $CI_PIPELINE_SOURCE == "web" + needs: + - job: get_changelog + artifacts: true + script: + - | + CURRENT_VERSION=$(git describe --tags --abbrev=0) + RELEASE_VERSION=$CURRENT_VERSION + + # Релиз выполняется только при наличии изменений + if [ $(git rev-list $CURRENT_VERSION..HEAD --count) -gt 0 ]; then + # Если релиз на мастере, то устанавливается версия равная версии в Perxis + RELEASE_VERSION=$PERXIS_RELEASE_VERSION + + # Если релиз хотфиксовый, то увеличиваем патчевую версию + if [ $HOTFIX_RELEASE == "true" ]; then + RELEASE_VERSION=$(echo $CURRENT_VERSION | awk -F . '{print $1"."$2"."$3+1}') + fi + fi + + # Если новая версия совпадает со старой, значит изменений не было, и выпускать новый релиз не нужно + NEEDS_RELEASE=false + if [ "$RELEASE_VERSION" != "$CURRENT_VERSION" ]; then + NEEDS_RELEASE=true + fi + + echo "PERXIS_GO_CURRENT_VERSION=$CURRENT_VERSION" >> vars.env + echo "PERXIS_GO_RELEASE_VERSION=$RELEASE_VERSION" >> vars.env + echo "PERXIS_GO_NEEDS_RELEASE=$NEEDS_RELEASE" >> vars.env + + printf '### Release perxis-go + PERXIS_RELEASE_VERSION: %s + HOTFIX_RELEASE: %s + CURRENT_VERSION: %s + RELEASE_VERSION: %s + NEEDS_RELEASE: %s' $PERXIS_RELEASE_VERSION $HOTFIX_RELEASE $CURRENT_VERSION $RELEASE_VERSION $NEEDS_RELEASE + artifacts: + when: always + paths: + - vars.env + - current_changelog.md + expire_in: 1 week + +# ----- release ----- + +create_release_branch: + stage: release + image: bitnami/git:latest + variables: + GIT_DEPTH: 0 + GIT_STRATEGY: clone + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" && $PREPARE_RELEASE != "true" + - if: $CI_PIPELINE_SOURCE == "web" + script: + - | + if [ $NEEDS_RELEASE == "true" ] && [ $CI_COMMIT_BRANCH == "master" ]; then + git config user.email "gitlab@ci-cd.pipeline" + git config user.name "gitlab-ci" + git remote remove gitlab_origin || true + git remote add gitlab_origin https://release_gitlab_ci:$PERXIS_GO_REPO_ACCESS_TOKEN@git.perx.ru/perxis/perxis-go.git + RELEASE_BRANCH=${VERSION:1:-2} + git branch release/$RELEASE_BRANCH || true + git push gitlab_origin release/$RELEASE_BRANCH + fi + + +release: + stage: release + image: registry.gitlab.com/gitlab-org/release-cli:latest + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" && $PREPARE_RELEASE != "true" + - if: $CI_PIPELINE_SOURCE == "web" + when: manual + needs: + - create_release_branch + script: + - echo "Start release $VERSION" + - | + if [ $NEEDS_RELEASE != "true" ]; then + exit 203 + fi + allow_failure: + exit_codes: + - 203 + release: + name: 'Release $VERSION' + description: '$VERSION' + tag_name: '$VERSION' diff --git a/.gitmodules b/.gitmodules index 79c7c1ea054bf3ed90bc0be427d1350ee0519405..343aa6dbcfdb13e695b9bae0a198d12baa573973 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "perxis-proto"] path = perxis-proto url = https://git.perx.ru/perxis/perxis-proto.git + diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000000000000000000000000000000000000..9682c3a35ae139aceb327b9c367ef0779bd59998 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,25 @@ +version: 2 + +gitlab_urls: + api: https://git.perx.ru/api/v4/ + download: https://git.perx.ru + use_package_registry: true + +before: + hooks: + - go mod tidy + +builds: + - skip: true + +snapshot: + name_template: "{{ incpatch .Version }}-next" + +release: + gitlab: + owner: perxis + name: perxis-go + +announce: + skip: "{{gt .Patch 0}}" + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..a0685cbaeeed3790baa6a4d525a6658cf39cb83b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,145 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.28.0] - 2024-08-19 + +### 🚀 Features + +- *(core)* Изменено поведение обхода схемы schema.Walk, считаем что объект изменился при установке значения Nil ([#PRXS-2648](https://tracker.yandex.ru/PRXS-2648))-([8a7f62f](https://git.perx.ru/perxis/perxis-go/-/commit/8a7f62fcd93f114e941538fe09f41b9c0927ceb0)) +- *(schema)* Реализован функционал для загрузки схем из файлов ([#PRXS-2731](https://tracker.yandex.ru/PRXS-2731))-([0255aad](https://git.perx.ru/perxis/perxis-go/-/commit/0255aad01984ac7b39385df1132f6ed3289e2ba4)) +- *(core)* Добавлен вызов Visitors при компиляции expr-выражения в bson. Добавлен метод Schema.SetSingleLocale ([#PRXS-2656](https://tracker.yandex.ru/PRXS-2656))-([60c45b0](https://git.perx.ru/perxis/perxis-go/-/commit/60c45b0cb14ae81835859ce9e5303a7fba5b733b)) +- Реализована загрузка данных схем и записей через файлы для использования расширениях -([a978cfa](https://git.perx.ru/perxis/perxis-go/-/commit/a978cfa2b8e69ef9b4be4b83d5a7c393f7521815)) +- *(core)* Добавлена функция для ожидания готовности окружения ([#PRXS-2648](https://tracker.yandex.ru/PRXS-2648))-([3e7c23e](https://git.perx.ru/perxis/perxis-go/-/commit/3e7c23efa6a7e42ddcdce460da22208234ab94bd)) + +### 🐛 Bug Fixes + +- *(core)* Исправлена ошибка "assignment to entry in nil map" если у объекта схемы отсутствовали поля ([#PRXS-2770](https://tracker.yandex.ru/PRXS-2770))-([3c4b955](https://git.perx.ru/perxis/perxis-go/-/commit/3c4b955915e26b063aceac7169d6b0f82b7c96bf)) +- *(core)* Исправлена ошибка "panic: runtime error: invalid memory address or nil pointer dereference" при вызове UnmarshalJSON при передаче "null" ([#PRXS-2770](https://tracker.yandex.ru/PRXS-2770))-([36e8b6a](https://git.perx.ru/perxis/perxis-go/-/commit/36e8b6a965cd0b0a7977340c8eea5c9672f168a3)) + +### ⚙️ Miscellaneous Tasks + +- Увеличен стандартный размер очереди Job Queue с 100 до 10000 -([ba53c5a](https://git.perx.ru/perxis/perxis-go/-/commit/ba53c5a0a0469e1ccdd18297ea38357342116a49)) +- *(schema)* Добавлено получение вложенных в Reference полей схемы -([7b14a23](https://git.perx.ru/perxis/perxis-go/-/commit/7b14a239c46a7700051a4115e274b55e0bee5e60)) +- GoReleaser configuration -([36ce38d](https://git.perx.ru/perxis/perxis-go/-/commit/36ce38dad5a17a3876dc9f26ea4b3ff09ed0793a)) + +## [0.27.0] - 2024-07-24 + +### 🚀 Features + +- Добавлен пакет `localizer` для работы с переводами данных ([#PRXS-2653](https://tracker.yandex.ru/PRXS-2653))-([53a37c4](https://git.perx.ru/perxis/perxis-go/-/commit/53a37c45a8a76e2b4cf7f2b5a7874b06465269b9)) +- *(core)* Внесены изменения для работы с переводами через Items API -([ebf80bb](https://git.perx.ru/perxis/perxis-go/-/commit/ebf80bb317f126f85e69a813651054fbf77a2bae)) +- *(logs)* Обновление API логирования, релевантность результатов поиска ([#PRXS-2665](https://tracker.yandex.ru/PRXS-2665))-([97077fb](https://git.perx.ru/perxis/perxis-go/-/commit/97077fbc800a3c3d865ee35a485ed8b6396f3444)) +- *(core)* Обновление References API: поддержка локализации контента -([87b92c5](https://git.perx.ru/perxis/perxis-go/-/commit/87b92c5bc30d1c26b280c85b447a0ca9d313df34)) +- *(core)* Реализована возможность загрузки схем из YAML и JSON файлов ([#PRXS-2731](https://tracker.yandex.ru/PRXS-2731))-([bf29420](https://git.perx.ru/perxis/perxis-go/-/commit/bf294207182bbc0b5ce154029f98aaca00b9c831)) + +### 🐛 Bug Fixes + +- *(core)* Исправлен обход схемы Walk для типа Array, решена ошибка отсутствия схемы при вызове Introspect -([2f684ea](https://git.perx.ru/perxis/perxis-go/-/commit/2f684ea678c0bcd59b8faed69cace00c9a4d29e6)) +- *(core)* Исправлена ошибка при которой не логировались действия с пространствами ([#PRXS-2609](https://tracker.yandex.ru/PRXS-2609))-([d0a7606](https://git.perx.ru/perxis/perxis-go/-/commit/d0a7606248f7e7a3a21075592d69d6845b546cce)) +- *(core)* Исправлена ошибка при которой была возможность изменить обьект находящийся в кеше Items ([#PRXS-2697](https://tracker.yandex.ru/PRXS-2697))-([cd5724d](https://git.perx.ru/perxis/perxis-go/-/commit/cd5724d316f2a0a6738a6159bdfb974938e8fde2)) + +### ⚙️ Miscellaneous Tasks + +- *(api)* Исправлены ошибки linter`а связанные с пропущенными именами переменных при получении результатов ([#PRXS-2610](https://tracker.yandex.ru/PRXS-2610))-([90269af](https://git.perx.ru/perxis/perxis-go/-/commit/90269aff2bae12a05d5394eb223e08ff6c2bdb2f)) +- *(core)* Исправлена передача объектов в кэше сервисов ([#PRXS-2705](https://tracker.yandex.ru/PRXS-2705))-([9180ee7](https://git.perx.ru/perxis/perxis-go/-/commit/9180ee7aa4c433e02030659489adca91bc4c8401)) + +## [0.25.1] - 2024-06-13 + +### 🐛 Bug Fixes + +- *(core)* Исправлен deadlock при одновременном вызове BufferedWriteSyncer.Stop и синхронизации по интервалу ([#PRXS-2576](https://tracker.yandex.ru/PRXS-2576))-([3b823ed](https://git.perx.ru/perxis/perxis-go/-/commit/3b823ed00a22e142e25137dccb5f1c4fbb318d3f)) + +## [0.25.0] - 2024-05-08 + +### 🚀 Features + +- *(core)* Добавлена возможность использовать символ "-" в названиях полей ([#PRXS-1439](https://tracker.yandex.ru/PRXS-1439))-([66b02b9](https://git.perx.ru/perxis/perxis-go/-/commit/66b02b9a6defdbe5e5d5502ff45d67c38c2a5fa4)) +- *(api)* Добавлен метод внутренний метод установки состояния пространства SetState для сервиса Spaces ([#PRXS-2223](https://tracker.yandex.ru/PRXS-2223))-([0057019](https://git.perx.ru/perxis/perxis-go/-/commit/005701931ea9c03d8e54ffa6bbcf351254ff578e)) +- Добавлен метод Find для сервиса Spaces ([#PRXS-2298](https://tracker.yandex.ru/PRXS-2298))-([4135690](https://git.perx.ru/perxis/perxis-go/-/commit/41356904837085adc48f4c8c6edaf8ad7d7fd014)) +- *(core)* Добавлено системное поле SearchScore в Item ([#PRXS-2445](https://tracker.yandex.ru/PRXS-2445))-([087edb3](https://git.perx.ru/perxis/perxis-go/-/commit/087edb39bbe6d22e12dedd9d4795336556f7b844)) + +### ⚙️ Miscellaneous Tasks + +- Перенесено содержимое пакета pkg/id на уровень выше в пакет id -([d13399f](https://git.perx.ru/perxis/perxis-go/-/commit/d13399fd6c26349f7ddf36c4d4e81568a2503a9c)) +- *(core)* Возврат GRPC-ошибки в сервисах -([c6bf265](https://git.perx.ru/perxis/perxis-go/-/commit/c6bf265699d5e9a99c0f583d7b6782b53cda3674)) + +## [0.24.0] - 2024-04-12 + +### 🚀 Features + +- Добавлен OID для Locales -([221d730](https://git.perx.ru/perxis/perxis-go/-/commit/221d730e552dd64d0dc32b21e799a75c6adf4503)) +- Добавлены методы Space, Environment, Collection, Organization для объекта System, который используется в шаблонах ([#PRXS-1813](https://tracker.yandex.ru/PRXS-1813))-([d017315](https://git.perx.ru/perxis/perxis-go/-/commit/d017315e664a9c5fcd84e377e5ba4f3635308f0b)) + +### 🐛 Bug Fixes + +- *(core)* Изменено название и значение констант событий в logging_middleware для коллекций ([#PRXS-2199](https://tracker.yandex.ru/PRXS-2199))-([0cb42c5](https://git.perx.ru/perxis/perxis-go/-/commit/0cb42c57c0b976e9f9dd2f21e326f17d84580969)) + +## [0.22.0] - 2024-03-06 + +### 🚀 Features + +- В пакет data добавлена проверка при установке значения на то, инициализирована ли map -([978a2c9](https://git.perx.ru/perxis/perxis-go/-/commit/978a2c9dc0c6c554ed35f046e33321e2c250fcf2)) +- *(core)* Добавлены функции exists и len для языка запросов expr ([#PRXS-1883](https://tracker.yandex.ru/PRXS-1883))-([eae58bf](https://git.perx.ru/perxis/perxis-go/-/commit/eae58bf4c3cad9fe793b8ccf763bf9ada46266a3)) +- *(extensions)* Добавлена по умолчанию для отображения Icon первой колонкой для коллекции "Настройки/Действия" ([#PRXS-1950](https://tracker.yandex.ru/PRXS-1950))-([9a3936b](https://git.perx.ru/perxis/perxis-go/-/commit/9a3936bea15bd80201b1ae9ffe1518b424dcb1d1)) +- Add filter_core.go -([37d3135](https://git.perx.ru/perxis/perxis-go/-/commit/37d313519b69d83d97560a5c09722cec959596a9)) +- Add unused v2 entry encoder -([79d8eef](https://git.perx.ru/perxis/perxis-go/-/commit/79d8eefc88b4b7c26b855df1492506131184f1a9)) + +### 🐛 Bug Fixes + +- Исправлена потенциальная утечка ресурсов в HTTP-загрузчике файлов (используется в сервисе Images) ([#PRXS-1977](https://tracker.yandex.ru/PRXS-1977))-([143766b](https://git.perx.ru/perxis/perxis-go/-/commit/143766b56f638a43281c26e9d79842198750db6b)) +- *(sync)* Исправлена ошибка синхронизации "received message larger than max". Процесс синхронизации значительно ускорен ([#PRXS-2026](https://tracker.yandex.ru/PRXS-2026))-([083aaf1](https://git.perx.ru/perxis/perxis-go/-/commit/083aaf1f363093219bb58f67b1accbc5a31f097a)) +- Add id import -([6c0ecb0](https://git.perx.ru/perxis/perxis-go/-/commit/6c0ecb0ee0786ae6f388e486c6210e79354f4f88)) + +### ⚙️ Miscellaneous Tasks + +- Обновлена библиотека github.com/expr-lang/expr до версии v1.15.8 ([#PRXS-1667](https://tracker.yandex.ru/PRXS-1667))-([d0069ab](https://git.perx.ru/perxis/perxis-go/-/commit/d0069ab4893e7c0acf360b5a42759d74c6a5cb32)) + +## [0.21.0] - 2024-01-16 + +### 🚀 Features + +- Добавлен интерфейс Cache ([#PRXS-1859](https://tracker.yandex.ru/PRXS-1859))-([c11dae6](https://git.perx.ru/perxis/perxis-go/-/commit/c11dae6a20e9ff04d3840ba4de87998d9eb72e6e)) +- Внесены правки в Spaces после изменений в perxis-proto, перегенерированны grpc-клиенты для Spaces ([#PRXS-1835](https://tracker.yandex.ru/PRXS-1835))-([2a0c015](https://git.perx.ru/perxis/perxis-go/-/commit/2a0c01544486fac5f5cb505a1dab7aa88d7858f4)) +- Добавлена метрика для кэша -([3a6a7a3](https://git.perx.ru/perxis/perxis-go/-/commit/3a6a7a300dd7bad9597c4583871813ac5edecd52)) +- Функция argsToLabels была вынесена в пакет metrics и переименована в GetLabelsFromKV. Теперь функция игнорирует значение без ключа -([b0b4312](https://git.perx.ru/perxis/perxis-go/-/commit/b0b4312d8399b3933af35b88bad301a89488f353)) +- Добавлены metrics middleware для остальных сервисов -([8808371](https://git.perx.ru/perxis/perxis-go/-/commit/8808371cc465b0c16e6c41bd1ab5bf89a466a0ef)) +- *(core)* Добавлена сборка метрик кэша и запросов ([#PRXS-1219](https://tracker.yandex.ru/PRXS-1219))-([706b266](https://git.perx.ru/perxis/perxis-go/-/commit/706b2666190347d594c13d5d3f0f13586463be2a)) +- *(extension)* Добавлен middleware для сбора телеметрии -([221a13f](https://git.perx.ru/perxis/perxis-go/-/commit/221a13f8d19df03106afda566cad011178b1489a)) +- *(core)* Добавлен сбор телеметрии в менеджере расширений ([#PRXS-1898](https://tracker.yandex.ru/PRXS-1898))-([1f18b52](https://git.perx.ru/perxis/perxis-go/-/commit/1f18b5226a8473a5b509ce0cf7001f2e1525b395)) + +### 🐛 Bug Fixes + +- *(items)* Исправлены тесты -([57e7765](https://git.perx.ru/perxis/perxis-go/-/commit/57e776563ae3f6b14338f7fbb2d073ad40496d51)) +- *(items)* Добавлена метрика в CachingMiddleware -([68796ee](https://git.perx.ru/perxis/perxis-go/-/commit/68796ee090f68e16092a88e480900807e229ba80)) +- *(delivery)* Добавлена метрика в CachingMiddleware -([3f182d1](https://git.perx.ru/perxis/perxis-go/-/commit/3f182d11c13c914f6b7b8556f4082ce03ce937cb)) + +### 📚 Documentation + +- Добавлен комментарий -([c715ad8](https://git.perx.ru/perxis/perxis-go/-/commit/c715ad8d8123ca244f8eaa92f7456c9e99101fb4)) +- Добавлены подсказки к метрикам -([2387dac](https://git.perx.ru/perxis/perxis-go/-/commit/2387dac81918f252ac293a0f385d6e9149ec5924)) + +## [0.20.0] - 2023-12-01 + +### 🐛 Bug Fixes + +- *(extensions)* Исправлена ошибка, при которой при обновлении расширений для некоторых коллекций всегда переустанавливались схемы, в которых не было изменений. Добавлен возврат ошибки при любом действии с расширением в случае неправильной его конфигурации ([#PRXS-1695](https://tracker.yandex.ru/PRXS-1695))-([998f3e8](https://git.perx.ru/perxis/perxis-go/-/commit/998f3e84ba73b241740a404d097d2b7c65cd352a)) +- *(core)* Исправлена ошибка, при которой запрещенные правилами поля во вложенных объектах все равно были доступны пользователю ([#PRXS-1673](https://tracker.yandex.ru/PRXS-1673))-([0e1bec9](https://git.perx.ru/perxis/perxis-go/-/commit/0e1bec99fa78ad6f55e74e4cf6c38ee90cc5f205)) + +## [0.19.0] - 2023-11-03 + +### 🚀 Features + +- *(core)* Добавлено поле метадата в схему коллекций, для хранения дополнительной информации о коллекции -([05a7965](https://git.perx.ru/perxis/perxis-go/-/commit/05a7965aa95768f1053854947cf4f4365ce81fd7)) +- *(extensions)* Переработана процедура установки коллекций (Установка расширений) учитывающая что коллекция могла быть создана пользователем и предотвращающая перезапись и потерю данных ([#PRXS-1380](https://tracker.yandex.ru/PRXS-1380))-([1f00274](https://git.perx.ru/perxis/perxis-go/-/commit/1f00274400637dd64d83176f1b650c8b7c129f72)) +- *(extension)* При установке расширения схемы коллекций принадлежащих расширению по-умолчанию будут обновлены. ([#PRXS-1380](https://tracker.yandex.ru/PRXS-1380))-([0dc7312](https://git.perx.ru/perxis/perxis-go/-/commit/0dc7312912999b811d5e48f247afbed3d737c9d7)) +- *(extensions)* При установке расширения больше не перезаписывают конфликтные схемы коллекций. (Удален временный флаг _alwaysSetSchema в Setup) ([#PRXS-1472](https://tracker.yandex.ru/PRXS-1472))-([278b2cb](https://git.perx.ru/perxis/perxis-go/-/commit/278b2cbc96e4ebfbf34e21dccffb929754f9a829)) + +### 🐛 Bug Fixes + +- *(core)* Пакеты 'service' в которых лежат middlewares переименованы на 'middleware' ([#PRXS-1163](https://tracker.yandex.ru/PRXS-1163))-([75f3153](https://git.perx.ru/perxis/perxis-go/-/commit/75f31532aa7b3007d9ff32c89ec6b62877b93085)) +- *(core)* Исправлена ошибка, из-за которой проверка на принадлежность пользователя к разным организациям отрабатывала некорректно. Добавлена очистка кэша при переносе пространства ([#PRXS-1297](https://tracker.yandex.ru/PRXS-1297))-([7aa1d49](https://git.perx.ru/perxis/perxis-go/-/commit/7aa1d497cbd84e4e7b08508d645d794ef77a27ac)) +- *(sdk)* Исправлена ошибка 'failed to uninstall client: not found', возникающая при удалении расширения, клиент которого уже не существует ([#PRXS-1342](https://tracker.yandex.ru/PRXS-1342))-([a170724](https://git.perx.ru/perxis/perxis-go/-/commit/a1707249ff2b82589a990cf08352debb58d467df)) +- *(core)* Исправлена выгрузка лишних полей ("published_at", "published_by", "archived_at","archived_by") в файл при экспорте данных ([#PRXS-1390](https://tracker.yandex.ru/PRXS-1390))-([6dc87f8](https://git.perx.ru/perxis/perxis-go/-/commit/6dc87f8bf1acf2e12a7dc9858ab6407b9ac9ee78)) + +<!-- generated by git-cliff --> diff --git a/Taskfile.yaml b/Taskfile.yaml index 8a16d687681a42527f9dca01dd01fef0790c0aca..a75ab1d82db97c1725b2de039d57ab0e8d20b882 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -1,11 +1,31 @@ version: '3' - vars: PROTODIR: perxis-proto/proto PBDIR: pb + CURRENT_VERSION: + sh: svu current + RELEASE_VERSION: + sh: svu next tasks: + changelog: + cmds: + - git-cliff > CHANGELOG.md --tag {{ .RELEASE_VERSION }} + +# release +# - Сделать changelog +# - Закоммитить все изменения +# - Пометить тэгом версию +# пререлиз - `git tag "$(svu pr --pre-release alpha.1 --build 9)"` +# пререлиз - `git tag "$(svu next)"` +# - Запушить код и тэги на сервер (иначе будет непонятная ошибка goreleaser Not found) + release: + cmds: + - mkdir -p release + - git-cliff {{ .CURRENT_VERSION }}.. --tag {{ .RELEASE_VERSION }} > release/CHANGELOG.md + - goreleaser release --clean --release-notes=release/CHANGELOG.md + mocks: deps: - mocks.proto diff --git a/assets.go b/assets.go new file mode 100644 index 0000000000000000000000000000000000000000..b3ed90c1011a144565e9fc8f293473352ba6cba3 --- /dev/null +++ b/assets.go @@ -0,0 +1,168 @@ +package perxis + +import ( + "io" + "io/fs" + "path/filepath" + + "git.perx.ru/perxis/perxis-go/pkg/errors" + jsoniter "github.com/json-iterator/go" + "gopkg.in/yaml.v3" +) + +// Assets предоставляет методы для загрузки данных из файловой системы +type Assets[T any] struct { + Constructor func() T +} + +// NewAssets возвращает новый экземпляр загрузчика +func NewAssets[T any]() *Assets[T] { + return &Assets[T]{ + Constructor: func() (t T) { return t }, + } +} + +type FromFSFunc[T any] func(fsys fs.FS) ([]T, error) +type FromFileFunc[T any] func(file fs.File) ([]T, error) + +func (a *Assets[T]) Funcs() (FromFSFunc[T], FromFileFunc[T]) { + return a.FromFS, a.FromFile +} + +// WithConstructor устанавливает конструктор для создания новых экземпляров +func (a *Assets[T]) WithConstructor(t func() T) *Assets[T] { + a.Constructor = t + return a +} + +// MustFrom возвращает все записи в переданной файловой системе +func (a *Assets[T]) MustFrom(fsys fs.FS, path string) []T { + res, err := a.From(fsys, path) + if err != nil { + panic(err) + } + return res +} + +// MustOneFrom возвращает одну запись из переданного файла +func (a *Assets[T]) MustOneFrom(fsys fs.FS, path string) T { + res, err := a.From(fsys, path) + if err != nil { + panic(err) + } + if len(res) == 0 { + panic(errors.Errorf("no entries found")) + } + if len(res) > 1 { + panic(errors.Errorf("multiple entries found")) + } + return res[0] +} + +// From возвращает записи из переданного файла +func (a *Assets[T]) From(fsys fs.FS, path string) ([]T, error) { + f, err := fsys.Open(path) + if err != nil { + return nil, err + } + + defer f.Close() + + stat, err := f.Stat() + if err != nil { + return nil, err + } + + if stat.IsDir() { + sub, err := fs.Sub(fsys, path) + if err != nil { + return nil, err + } + return a.FromFS(sub) + } + + return a.FromFile(f) +} + +// FromFile возвращает записи в переданном файле +func (a *Assets[T]) FromFile(file fs.File) ([]T, error) { + stat, err := file.Stat() + if err != nil { + return nil, err + } + + switch filepath.Ext(stat.Name()) { + case ".json": + entry, err := a.FromJSON(file) + if err != nil { + return nil, errors.Wrapf(err, "file '%s'", stat.Name()) + } + return []T{entry}, nil + + case ".yaml", ".yml": + entries, err := a.FromYAML(file) + return entries, errors.Wrapf(err, "file '%s'", stat.Name()) + } + + return nil, errors.Errorf("file '%s' must be in JSON or YAML format", stat.Name()) +} + +// FromFS возвращает все записи в переданной файловой системе +func (a *Assets[T]) FromFS(fsys fs.FS) (result []T, err error) { + if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, _ error) error { + file, err := fsys.Open(path) + if err != nil { + return err + } + defer file.Close() + + if entries, err := a.FromFile(file); err == nil { + result = append(result, entries...) + } + return nil + }); err != nil { + return nil, err + } + + return result, nil +} + +// FromJSON возвращает запись из JSON +func (c *Assets[T]) FromJSON(r io.Reader) (T, error) { + entry := c.Constructor() + data, err := io.ReadAll(r) + if err != nil { + return entry, err + } + + err = jsoniter.Unmarshal(data, &entry) + return entry, err +} + +// FromYAML возвращает записи из YAML +func (c *Assets[T]) FromYAML(r io.Reader) (result []T, err error) { + decoder := yaml.NewDecoder(r) + for { + var data interface{} + err = decoder.Decode(&data) + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return nil, err + } + + json, err := jsoniter.Marshal(data) + if err != nil { + return nil, err + } + + entry := c.Constructor() + if err = jsoniter.Unmarshal(json, &entry); err != nil { + return nil, err + } + result = append(result, entry) + } + + return result, nil +} diff --git a/assets/tests/assets/invalid.txt b/assets/tests/assets/invalid.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/assets/tests/assets/item.json b/assets/tests/assets/item.json new file mode 100644 index 0000000000000000000000000000000000000000..1240b61e1efb8370c3000cafd213a6dfe8de7d53 --- /dev/null +++ b/assets/tests/assets/item.json @@ -0,0 +1,16 @@ +{ + "id": "item3", + "enum": 1, + "data": { + "obj": { + "str": "value" + }, + "arr": [ + "str1", + "str2" + ] + }, + "struct": { + "option": true + } +} \ No newline at end of file diff --git a/assets/tests/assets/items.yaml b/assets/tests/assets/items.yaml new file mode 100644 index 0000000000000000000000000000000000000000..eacf244f47504be87023f538cdd7f02cdbbe7ea0 --- /dev/null +++ b/assets/tests/assets/items.yaml @@ -0,0 +1,23 @@ +--- +id: item1 +enum: 1 +data: + obj: + str: value + arr: + - str1 + - str2 +struct: + option: true + +--- +id: item2 +enum: 1 +data: + obj: + str: value + arr: + - str1 + - str2 +struct: + option: true diff --git a/assets/tests/setup/collections/collections.yaml b/assets/tests/setup/collections/collections.yaml new file mode 100644 index 0000000000000000000000000000000000000000..13c7fe7f4f3fd4806d52e29f8a2aa06ba40b94c4 --- /dev/null +++ b/assets/tests/setup/collections/collections.yaml @@ -0,0 +1,42 @@ +--- +type: object +params: + inline: false + fields: + name: + title: Название + description: Название коллекции + type: string + params: + required: true +metadata: + collection_id: collection_a + collection_name: Коллекция A +--- +type: object +params: + inline: false + fields: + name: + title: Название + description: Название коллекции + type: string + params: + required: true +metadata: + collection_id: collection_b + collection_name: Коллекция B +--- +id: collection_c +name: Коллекция C +schema: + type: object + params: + inline: false + fields: + name: + title: Название + description: Название коллекции + type: string + params: + required: true \ No newline at end of file diff --git a/assets_test.go b/assets_test.go new file mode 100644 index 0000000000000000000000000000000000000000..69a71b8a5323ca6bd8d7b103f66a70b62054ef29 --- /dev/null +++ b/assets_test.go @@ -0,0 +1,86 @@ +package perxis + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type State int + +const ( + State1 State = iota + State2 +) + +type testEntry struct { + ID string + Enum State + Data map[string]interface{} + Struct *nested +} + +type nested struct { + Option *bool +} + +func TestFromFS(t *testing.T) { + tr := true + i1 := &testEntry{ + ID: "item1", + Enum: State2, + Data: map[string]interface{}{ + "obj": map[string]interface{}{"str": "value"}, + "arr": []interface{}{"str1", "str2"}, + }, + Struct: &nested{ + Option: &tr, + }, + } + + i2 := *i1 + i2.ID = "item2" + + i3 := *i1 + i3.ID = "item3" + + assets := NewAssets[*testEntry]() + r, err := assets.FromFS(os.DirFS("assets/tests/assets")) + require.NoError(t, err) + require.Len(t, r, 3) + assert.ElementsMatch(t, []*testEntry{i1, &i2, &i3}, r) +} + +func TestFrom(t *testing.T) { + tr := true + i1 := &testEntry{ + ID: "item1", + Enum: State2, + Data: map[string]interface{}{ + "obj": map[string]interface{}{"str": "value"}, + "arr": []interface{}{"str1", "str2"}, + }, + Struct: &nested{ + Option: &tr, + }, + } + + i2 := *i1 + i2.ID = "item2" + + i3 := *i1 + i3.ID = "item3" + + assets := NewAssets[*testEntry]() + r, err := assets.From(os.DirFS("assets"), "tests/assets") + require.NoError(t, err) + require.Len(t, r, 3) + assert.ElementsMatch(t, []*testEntry{i1, &i2, &i3}, r) + + r, err = assets.From(os.DirFS("assets"), "tests/assets/items.yaml") + require.NoError(t, err) + require.Len(t, r, 2) + assert.Equal(t, []*testEntry{i1, &i2}, r) +} diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000000000000000000000000000000000000..78b82d95b808fd8b3a85e9013870059b8bb46b13 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,107 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. +[bump] +features_always_bump_minor = true +breaking_always_bump_major = true + +[changelog] +# changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file.\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{% if version %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | upper_first }} \ + {% if commit.links %}\ + ({% for link in commit.links %}\ + [{{ link.text }}]({{ link.href }})\ + {% if not loop.last %}, {% endif %}\ + {% endfor %})\ + {% endif %}\ + -([{{ commit.id | truncate(length=7, end="") }}]($REPO/-/commit/{{ commit.id }}))\ + {% endfor %} +{% endfor %}\n +""" +# template for the changelog footer +footer = """ +<!-- generated by git-cliff --> +""" +# remove the leading and trailings +trim = true +# postprocessors +postprocessors = [ + { pattern = '\$REPO', replace = "https://git.perx.ru/perxis/perxis-go" }, +] + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + { pattern = 'Feat:', replace = "feat:"}, + { pattern = 'WIP:', replace = ""}, + { pattern = 'wip:', replace = ""} + # Replace issue numbers + #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, + # Check spelling of the commit with https://github.com/crate-ci/typos + # If the spelling is incorrect, it will be automatically fixed. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "<!-- 0 -->🚀 Features" }, + { message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" }, + { message = "^doc", group = "<!-- 3 -->📚 Documentation" }, + { message = "^perf", group = "<!-- 4 -->⚡ Performance" }, + { message = "^refactor", group = "<!-- 2 -->🚜 Refactor", skip = true }, + { message = "^style", group = "<!-- 5 -->🎨 Styling" }, + { message = "^test", group = "<!-- 6 -->🧪 Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" }, + { body = ".*security", group = "<!-- 8 -->🛡️ Security" }, + { message = "^revert", group = "<!-- 9 -->◀️ Revert" }, + { message = "^irefac", skip = true }, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# regex for matching git tags +# tag_pattern = "v[0-9].*" +# regex for skipping tags +skip_tags = "v0.([0-9]\\.|1[0-8]).*" +# regex for ignoring tags +# ignore_tags = "" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" +# limit the number of commits included in the changelog. +# limit_commits = 42 +link_parsers = [ + { pattern = "#(PRXS-(\\d+))", href = "https://tracker.yandex.ru/$1"}, + { pattern = "RFC(\\d+)", text = "ietf-rfc$1", href = "https://datatracker.ietf.org/doc/html/rfc$1"}, +] \ No newline at end of file diff --git a/go.mod b/go.mod index 81d914bcbb61d73aadf2c8c1851bff6f660d05b5..372a5f1f61d2f523d327d630e73fa21f0aad2eac 100644 --- a/go.mod +++ b/go.mod @@ -17,15 +17,15 @@ require ( github.com/rs/xid v1.5.0 github.com/stretchr/testify v1.8.4 go.mongodb.org/mongo-driver v1.13.0 - go.opentelemetry.io/otel v1.21.0 - go.opentelemetry.io/otel/trace v1.21.0 + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.15.0 + golang.org/x/crypto v0.23.0 golang.org/x/image v0.14.0 - golang.org/x/net v0.18.0 - golang.org/x/oauth2 v0.14.0 - google.golang.org/grpc v1.59.0 - google.golang.org/protobuf v1.31.0 + golang.org/x/net v0.25.0 + golang.org/x/oauth2 v0.18.0 + google.golang.org/grpc v1.64.0 + google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -35,15 +35,15 @@ require ( ) require ( - cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go/compute v1.25.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/brianvoe/gofakeit/v6 v6.26.3 github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gosimple/unidecode v1.0.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -59,12 +59,12 @@ require ( github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect - go.opentelemetry.io/otel/metric v1.21.0 + go.opentelemetry.io/otel/metric v1.24.0 go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.15.0 google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/go.sum b/go.sum index 4fa995ca097f0a961d0c4fc9d10cbe640e972c00..7f00103fa5b26228e50be943d05c23325cbdc38c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= @@ -21,14 +21,14 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -109,12 +109,12 @@ github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.13.0 h1:67DgFFjYOCMWdtTEmKFpV3ffWlFnh+CYZ8ZS/tXWUfY= go.mongodb.org/mongo-driver v1.13.0/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -125,8 +125,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= @@ -136,14 +136,14 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -151,8 +151,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -161,8 +161,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -170,14 +170,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e h1:Elxv5MwEkCI9f5SkoL6afed6NTdxaGoAo39eANBwHL8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/id/id.go b/id/id.go similarity index 100% rename from pkg/id/id.go rename to id/id.go diff --git a/pkg/id/id_test.go b/id/id_test.go similarity index 100% rename from pkg/id/id_test.go rename to id/id_test.go diff --git a/id/object_id_test.go b/id/object_id_test.go deleted file mode 100644 index 56a2c104e000756640eefc978be025c01757d13b..0000000000000000000000000000000000000000 --- a/id/object_id_test.go +++ /dev/null @@ -1,265 +0,0 @@ -package id - -import ( - "testing" - - "git.perx.ru/perxis/perxis-go/pkg/items" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_ParseID(t *testing.T) { - tests := []struct { - name string - id any - result *ObjectId - wantError bool - }{ - { - name: "SpaceId", - id: "/spaces/<space_id>", - result: MustObjectId("/spaces/<space_id>"), - }, - { - name: "ServiceID", - id: "/services/<service_id>", - result: MustObjectId("/services/<service_id>"), - }, - { - name: "UserID", - id: "/users/<user_id>", - result: MustObjectId("/users/<user_id>"), - }, - { - name: "OrganizationID", - id: "/orgs/<org_id>", - result: MustObjectId("/orgs/<org_id>"), - }, - { - name: "ClientID", - id: "/spaces/<space_id>/clients/<client_id>", - result: MustObjectId("/spaces/<space_id>/clients/<client_id>"), - }, - { - name: "RoleID", - id: "/spaces/<space_id>/roles/<role_id>", - result: MustObjectId("/spaces/<space_id>/roles/<role_id>"), - }, - { - name: "LocaleID", - id: "/spaces/<space_id>/locales/<locale_id>", - result: MustObjectId("/spaces/<space_id>/locales/<locale_id>"), - }, - { - name: "EnvironmentID", - id: "/spaces/<space_id>/envs/<env_id>", - result: MustObjectId("/spaces/<space_id>/envs/<env_id>"), - }, - { - name: "CollectionId", - id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>", - result: MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>"), - }, - { - name: "SchemaID", - id: "/spaces/<space_id>/envs/<env_id>/schema/<collection_id>", - result: MustObjectId("/spaces/<space_id>/envs/<env_id>/schema/<collection_id>"), - }, - { - name: "ItemId", - id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>", - result: MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>"), - }, - { - name: "RevisionID", - id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/revs/<rev_id>", - result: MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/revs/<rev_id>"), - }, - { - name: "FieldId", - id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/fields/<field_name>", - result: MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/fields/<field_name>"), - }, - { - name: "With error #1: no backslash in the beginning of id", - id: "spaces/<space_id>", - result: nil, - wantError: true, - }, - { - name: "With error #2: backslash in the end of id", - id: "/spaces/<space_id>/", - result: nil, - wantError: true, - }, - { - name: "With error #3: typo in 'spaces'", - id: "/space/<space_id>", - result: nil, - wantError: true, - }, - { - name: "With error #4: no space_id in id", - id: "/spaces", - result: nil, - wantError: true, - }, - { - name: "With error #5: multiple backslashes in the end of id", - id: "/spaces/<space_id>///", - result: nil, - wantError: true, - }, - { - name: "With error #6: nil value", - id: nil, - wantError: true, - }, - { - name: "With error #7: nil object value", - id: (*items.Item)(nil), - wantError: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - id, err := NewObjectId(tt.id) - if tt.wantError { - require.Error(t, err) - return - } - require.NoError(t, err) - require.Equal(t, tt.result, id) - require.Equal(t, tt.id, id.String()) - }) - } -} - -func Test_Map(t *testing.T) { - tests := []struct { - name string - id *ObjectId - }{ - { - name: "ServiceID", - id: &ObjectId{Descriptor: &ServiceId{ServiceID: "<service_id>"}}, - }, - { - name: "UserID", - id: &ObjectId{Descriptor: &UserId{UserID: "<user_id>"}}, - }, - { - name: "OrganizationID", - id: &ObjectId{Descriptor: &OrganizationId{OrganizationID: "<org_id>"}}, - }, - { - name: "SpaceId", - id: &ObjectId{Descriptor: &SpaceId{SpaceID: "<space_id>"}}, - }, - { - name: "ClientID", - id: &ObjectId{Descriptor: &ClientId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - ClientID: "<client_id>", - }}, - }, - { - name: "RoleID", - id: &ObjectId{Descriptor: &RoleId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - RoleID: "<role_id>", - }}, - }, - { - name: "LocaleID", - id: &ObjectId{Descriptor: &LocaleID{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - LocaleID: "<locale_id>", - }}, - }, - { - name: "EnvironmentID", - id: &ObjectId{Descriptor: &EnvironmentId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - EnvironmentID: "<env_id>", - }}, - }, - { - name: "CollectionId", - id: &ObjectId{Descriptor: &CollectionId{ - EnvironmentId: EnvironmentId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - EnvironmentID: "<env_id>", - }, - CollectionID: "<collection_id>", - }}, - }, - { - name: "Schema ID", - id: &ObjectId{Descriptor: &SchemaId{ - EnvironmentId: EnvironmentId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - EnvironmentID: "<env_id>", - }, - CollectionID: "<collection_id>", - }}, - }, - { - name: "ItemId", - id: &ObjectId{Descriptor: &ItemId{ - CollectionId: CollectionId{ - EnvironmentId: EnvironmentId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - EnvironmentID: "<env_id>", - }, - CollectionID: "<collection_id>", - }, - ItemID: "<item_id>", - }}, - }, - { - name: "RevisionID", - id: &ObjectId{Descriptor: &RevisionId{ - ItemId: ItemId{ - CollectionId: CollectionId{ - EnvironmentId: EnvironmentId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - EnvironmentID: "<env_id>", - }, - CollectionID: "<collection_id>", - }, - ItemID: "<item_id>", - }, - RevisionID: "<rev_id>", - }}, - }, - { - name: "FieldId", - id: &ObjectId{Descriptor: &FieldId{ - ItemId: ItemId{ - CollectionId: CollectionId{ - EnvironmentId: EnvironmentId{ - SpaceId: SpaceId{SpaceID: "<space_id>"}, - EnvironmentID: "<env_id>", - }, - CollectionID: "<collection_id>", - }, - ItemID: "<item_id>", - }, - Field: "<field_name>", - }}, - }, - { - name: "SystemID", - id: &ObjectId{Descriptor: &SystemId{}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - v, err := FromMap(tt.id.Map()) - require.NoError(t, err) - assert.Equal(t, tt.id, v, "проверка FromMap для типа ID, должен быть равен исходному значению") - assert.Equal(t, v.Map(), tt.id.Map()) - }) - } -} diff --git a/id/test/object_id_test.go b/id/test/object_id_test.go index e29328ddf25f799cbb56707fa292762f69c39207..2f01fa125e376623ceb710bbe594235b8434d853 100644 --- a/id/test/object_id_test.go +++ b/id/test/object_id_test.go @@ -14,6 +14,7 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/roles" "git.perx.ru/perxis/perxis-go/pkg/spaces" "git.perx.ru/perxis/perxis-go/pkg/users" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -886,3 +887,259 @@ func Test_LocaleId(t *testing.T) { }) } } + +func Test_ParseID(t *testing.T) { + tests := []struct { + name string + id any + result *id.ObjectId + wantError bool + }{ + { + name: "SpaceId", + id: "/spaces/<space_id>", + result: id.MustObjectId("/spaces/<space_id>"), + }, + { + name: "ServiceID", + id: "/services/<service_id>", + result: id.MustObjectId("/services/<service_id>"), + }, + { + name: "UserID", + id: "/users/<user_id>", + result: id.MustObjectId("/users/<user_id>"), + }, + { + name: "OrganizationID", + id: "/orgs/<org_id>", + result: id.MustObjectId("/orgs/<org_id>"), + }, + { + name: "ClientID", + id: "/spaces/<space_id>/clients/<client_id>", + result: id.MustObjectId("/spaces/<space_id>/clients/<client_id>"), + }, + { + name: "RoleID", + id: "/spaces/<space_id>/roles/<role_id>", + result: id.MustObjectId("/spaces/<space_id>/roles/<role_id>"), + }, + { + name: "LocaleID", + id: "/spaces/<space_id>/locales/<locale_id>", + result: id.MustObjectId("/spaces/<space_id>/locales/<locale_id>"), + }, + { + name: "EnvironmentID", + id: "/spaces/<space_id>/envs/<env_id>", + result: id.MustObjectId("/spaces/<space_id>/envs/<env_id>"), + }, + { + name: "CollectionId", + id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>", + result: id.MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>"), + }, + { + name: "SchemaID", + id: "/spaces/<space_id>/envs/<env_id>/schema/<collection_id>", + result: id.MustObjectId("/spaces/<space_id>/envs/<env_id>/schema/<collection_id>"), + }, + { + name: "ItemId", + id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>", + result: id.MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>"), + }, + { + name: "RevisionID", + id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/revs/<rev_id>", + result: id.MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/revs/<rev_id>"), + }, + { + name: "FieldId", + id: "/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/fields/<field_name>", + result: id.MustObjectId("/spaces/<space_id>/envs/<env_id>/cols/<collection_id>/items/<item_id>/fields/<field_name>"), + }, + { + name: "With error #1: no backslash in the beginning of id", + id: "spaces/<space_id>", + result: nil, + wantError: true, + }, + { + name: "With error #2: backslash in the end of id", + id: "/spaces/<space_id>/", + result: nil, + wantError: true, + }, + { + name: "With error #3: typo in 'spaces'", + id: "/space/<space_id>", + result: nil, + wantError: true, + }, + { + name: "With error #4: no space_id in id", + id: "/spaces", + result: nil, + wantError: true, + }, + { + name: "With error #5: multiple backslashes in the end of id", + id: "/spaces/<space_id>///", + result: nil, + wantError: true, + }, + { + name: "With error #6: nil value", + id: nil, + wantError: true, + }, + { + name: "With error #7: nil object value", + id: (*items.Item)(nil), + wantError: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + id, err := id.NewObjectId(tt.id) + if tt.wantError { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.result, id) + require.Equal(t, tt.id, id.String()) + }) + } +} + +func Test_Map(t *testing.T) { + tests := []struct { + name string + id *id.ObjectId + }{ + { + name: "ServiceID", + id: &id.ObjectId{Descriptor: &id.ServiceId{ServiceID: "<service_id>"}}, + }, + { + name: "UserID", + id: &id.ObjectId{Descriptor: &id.UserId{UserID: "<user_id>"}}, + }, + { + name: "OrganizationID", + id: &id.ObjectId{Descriptor: &id.OrganizationId{OrganizationID: "<org_id>"}}, + }, + { + name: "SpaceId", + id: &id.ObjectId{Descriptor: &id.SpaceId{SpaceID: "<space_id>"}}, + }, + { + name: "ClientID", + id: &id.ObjectId{Descriptor: &id.ClientId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + ClientID: "<client_id>", + }}, + }, + { + name: "RoleID", + id: &id.ObjectId{Descriptor: &id.RoleId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + RoleID: "<role_id>", + }}, + }, + { + name: "LocaleID", + id: &id.ObjectId{Descriptor: &id.LocaleID{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + LocaleID: "<locale_id>", + }}, + }, + { + name: "EnvironmentID", + id: &id.ObjectId{Descriptor: &id.EnvironmentId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + EnvironmentID: "<env_id>", + }}, + }, + { + name: "CollectionId", + id: &id.ObjectId{Descriptor: &id.CollectionId{ + EnvironmentId: id.EnvironmentId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + EnvironmentID: "<env_id>", + }, + CollectionID: "<collection_id>", + }}, + }, + { + name: "Schema ID", + id: &id.ObjectId{Descriptor: &id.SchemaId{ + EnvironmentId: id.EnvironmentId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + EnvironmentID: "<env_id>", + }, + CollectionID: "<collection_id>", + }}, + }, + { + name: "ItemId", + id: &id.ObjectId{Descriptor: &id.ItemId{ + CollectionId: id.CollectionId{ + EnvironmentId: id.EnvironmentId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + EnvironmentID: "<env_id>", + }, + CollectionID: "<collection_id>", + }, + ItemID: "<item_id>", + }}, + }, + { + name: "RevisionID", + id: &id.ObjectId{Descriptor: &id.RevisionId{ + ItemId: id.ItemId{ + CollectionId: id.CollectionId{ + EnvironmentId: id.EnvironmentId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + EnvironmentID: "<env_id>", + }, + CollectionID: "<collection_id>", + }, + ItemID: "<item_id>", + }, + RevisionID: "<rev_id>", + }}, + }, + { + name: "FieldId", + id: &id.ObjectId{Descriptor: &id.FieldId{ + ItemId: id.ItemId{ + CollectionId: id.CollectionId{ + EnvironmentId: id.EnvironmentId{ + SpaceId: id.SpaceId{SpaceID: "<space_id>"}, + EnvironmentID: "<env_id>", + }, + CollectionID: "<collection_id>", + }, + ItemID: "<item_id>", + }, + Field: "<field_name>", + }}, + }, + { + name: "SystemID", + id: &id.ObjectId{Descriptor: &id.SystemId{}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v, err := id.FromMap(tt.id.Map()) + require.NoError(t, err) + assert.Equal(t, tt.id, v, "проверка FromMap для типа ID, должен быть равен исходному значению") + assert.Equal(t, v.Map(), tt.id.Map()) + }) + } +} diff --git a/images/convert/convert.go b/images/convert/convert.go index b704055dd7399eb4629d1804cd51574befff49c6..0903f19f4e5c3808f750e9c4e3bc4b7b0f81c409 100644 --- a/images/convert/convert.go +++ b/images/convert/convert.go @@ -3,6 +3,7 @@ package convert import ( "image" "io" + "mime" "os" "strings" @@ -69,5 +70,23 @@ func FormatFromExtension(ext string) (Format, error) { if f, ok := formatExtensions[ext]; ok { return f, nil } - return "", errors.Errorf("unsupported format") + return "", errors.Errorf("unsupported format: %s", ext) +} + +func FormatFromMIMEType(typ string) (Format, error) { + extensions, err := mime.ExtensionsByType(typ) + if err != nil { + return "", errors.Wrap(err, "get extensions by mime type") + } + if len(extensions) == 0 { + return "", errors.Errorf("unknown mime type: %s", typ) + } + for _, extension := range extensions { + var format Format + format, err = FormatFromExtension(extension) + if err == nil { + return format, nil + } + } + return "", err } diff --git a/images/convert/convert_test.go b/images/convert/convert_test.go index b7a759eac8dba586d985806bb587975e07a93403..e48930e7de8000e8a43ecc7277c808340a1fb553 100644 --- a/images/convert/convert_test.go +++ b/images/convert/convert_test.go @@ -57,6 +57,55 @@ func TestFormatFromExtension(t *testing.T) { } } +func TestFormatFromMIMEType(t *testing.T) { + var tests = []struct { + name string + input string + output Format + wantErr bool + }{ + { + name: "correct jpeg", + input: "image/jpeg", + output: JPEG, + wantErr: false, + }, + { + name: "correct png", + input: "image/png", + output: PNG, + wantErr: false, + }, + { + name: "unsupported mime type", + input: "application/json", + wantErr: true, + }, + { + name: "unknown mime type", + input: "application/perxis", + wantErr: true, + }, + { + name: "no mime type", + input: "", + wantErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + format, err := FormatFromMIMEType(tc.input) + if tc.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.output, format) + } + }) + } +} + func TestEncode(t *testing.T) { var tests = []struct { name string diff --git a/images/transport/client.microgen.go b/images/transport/client.go similarity index 68% rename from images/transport/client.microgen.go rename to images/transport/client.go index d8b9342e08a9770c17cbc81ead84eddf57dd16fa..bfa7487ca160b8098337e4ebb885c74424aecd24 100644 --- a/images/transport/client.microgen.go +++ b/images/transport/client.go @@ -4,12 +4,9 @@ package transport import ( "context" - "errors" images "git.perx.ru/perxis/perxis-go/images" files "git.perx.ru/perxis/perxis-go/pkg/files" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Get(arg0 context.Context, arg1 *files.File, arg2 *images.GetOptions) (res0 *files.File, res1 error) { @@ -19,9 +16,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 *files.File, arg2 *images } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Result, res1 diff --git a/images/transport/grpc/client.go b/images/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..167b69288bc0642221a70bce8a1e1f236ef48db9 --- /dev/null +++ b/images/transport/grpc/client.go @@ -0,0 +1,17 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/images/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + } +} diff --git a/images/transport/grpc/protobuf_type_converters.microgen.go b/images/transport/grpc/protobuf_type_converters.microgen.go index 48a13510667582f7858cbc04ff517598eb17772d..51f6d68668be2c416501fadbe14dbaeead5308df 100644 --- a/images/transport/grpc/protobuf_type_converters.microgen.go +++ b/images/transport/grpc/protobuf_type_converters.microgen.go @@ -18,7 +18,7 @@ func PtrFileFileToProto(source *file.File) (*pbfile.File, error) { pbFile := &pbfile.File{ Id: source.ID, Name: source.Name, - Size: int32(source.Size), + Size: source.Size, MimeType: source.MimeType, Url: source.URL, } @@ -32,7 +32,7 @@ func ProtoToPtrFileFile(protoSource *pbfile.File) (*file.File, error) { file := &file.File{ ID: protoSource.Id, Name: protoSource.Name, - Size: int(protoSource.Size), + Size: protoSource.Size, MimeType: protoSource.MimeType, URL: protoSource.Url, } diff --git a/images/transport/grpc/server.go b/images/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..c36a57b0eadbd8878539d22d33cf57f7329b6b65 --- /dev/null +++ b/images/transport/grpc/server.go @@ -0,0 +1,17 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/images" + "git.perx.ru/perxis/perxis-go/images/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + pb "git.perx.ru/perxis/perxis-go/proto/images" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc images.Images, opts ...grpckit.ServerOption) pb.ImagesServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/logs/log.go b/logs/log.go index 2de45a30cd98bbd5ce840726b862dbca52fc8480..60f88d3a21869fef323c489af6e45858b3960124 100644 --- a/logs/log.go +++ b/logs/log.go @@ -27,17 +27,18 @@ func (l Level) String() string { } type Entry struct { - ID string `json:"id" bson:"_id" mapstructure:"id"` - Timestamp time.Time `json:"timestamp,omitempty" bson:"timestamp,omitempty" mapstructure:"timestamp,omitempty"` - Level Level `json:"level,omitempty" bson:"level,omitempty" mapstructure:"level,omitempty"` - Message string `json:"message,omitempty" bson:"message,omitempty" mapstructure:"message,omitempty"` - Category string `json:"category,omitempty" bson:"category,omitempty" mapstructure:"category,omitempty"` - Component string `json:"component,omitempty" bson:"component,omitempty" mapstructure:"component,omitempty"` - Event string `json:"event,omitempty" bson:"event,omitempty" mapstructure:"event,omitempty"` - ObjectID *id.ObjectId `json:"object_id,omitempty" bson:"object_id,omitempty" mapstructure:"object_id,omitempty"` - CallerID *id.ObjectId `json:"caller_id,omitempty" bson:"caller_id,omitempty" mapstructure:"caller_id,omitempty"` - Attr interface{} `json:"attr,omitempty" bson:"attr,omitempty" mapstructure:"attr,omitempty"` - Tags []string `json:"tags,omitempty" bson:"tags,omitempty" mapstructure:"tags,omitempty"` + ID string `json:"id" bson:"_id" mapstructure:"id"` + Timestamp time.Time `json:"timestamp,omitempty" bson:"timestamp,omitempty" mapstructure:"timestamp,omitempty"` + Level Level `json:"level,omitempty" bson:"level,omitempty" mapstructure:"level,omitempty"` + Message string `json:"message,omitempty" bson:"message,omitempty" mapstructure:"message,omitempty"` + Category string `json:"category,omitempty" bson:"category,omitempty" mapstructure:"category,omitempty"` + Component string `json:"component,omitempty" bson:"component,omitempty" mapstructure:"component,omitempty"` + Event string `json:"event,omitempty" bson:"event,omitempty" mapstructure:"event,omitempty"` + ObjectID *id.ObjectId `json:"object_id,omitempty" bson:"object_id,omitempty" mapstructure:"object_id,omitempty"` + CallerID *id.ObjectId `json:"caller_id,omitempty" bson:"caller_id,omitempty" mapstructure:"caller_id,omitempty"` + Attr interface{} `json:"attr,omitempty" bson:"attr,omitempty" mapstructure:"attr,omitempty"` + Tags []string `json:"tags,omitempty" bson:"tags,omitempty" mapstructure:"tags,omitempty"` + SearchScore float64 `json:"searchScore,omitempty" bson:"search_score,omitempty"` } //func convertInterfaceToAny(v interface{}) (*any.Any, error) { @@ -52,15 +53,16 @@ type Entry struct { func EntryToPB(entry *Entry) *pb.LogEntry { logEntry := &pb.LogEntry{ - Id: entry.ID, - Timestamp: timestamppb.New(entry.Timestamp), - Level: pb.LogLevel(entry.Level), - Message: entry.Message, - Category: entry.Category, - Component: entry.Component, - Event: entry.Event, - Attr: nil, //implement - Tags: entry.Tags, + Id: entry.ID, + Timestamp: timestamppb.New(entry.Timestamp), + Level: pb.LogLevel(entry.Level), + Message: entry.Message, + Category: entry.Category, + Component: entry.Component, + Event: entry.Event, + Attr: nil, //implement + Tags: entry.Tags, + SearchScore: entry.SearchScore, } if entry.ObjectID != nil { logEntry.ObjectId = entry.ObjectID.String() @@ -74,13 +76,14 @@ func EntryToPB(entry *Entry) *pb.LogEntry { func EntryFromPB(request *pb.LogEntry) *Entry { logEntry := &Entry{ - ID: request.Id, - Timestamp: request.Timestamp.AsTime(), - Level: Level(request.Level), - Message: request.Message, - Category: request.Category, - Component: request.Component, - Event: request.Event, + ID: request.Id, + Timestamp: request.Timestamp.AsTime(), + Level: Level(request.Level), + Message: request.Message, + Category: request.Category, + Component: request.Component, + Event: request.Event, + SearchScore: request.SearchScore, } if request.ObjectId != "" { diff --git a/logs/mocks/Service.go b/logs/mocks/Service.go index af4da73bc4d4c7b088fbfea7e7babc4c1ba30e36..0031c92c3b99e49348bf5c14c54a909f2e9736a7 100644 --- a/logs/mocks/Service.go +++ b/logs/mocks/Service.go @@ -5,7 +5,7 @@ package mocks import ( context "context" - log2 "git.perx.ru/perxis/perxis-go/logs" + logs "git.perx.ru/perxis/perxis-go/logs" mock "github.com/stretchr/testify/mock" options "git.perx.ru/perxis/perxis-go/pkg/options" @@ -17,7 +17,7 @@ type Service struct { } // Delete provides a mock function with given fields: ctx, filter -func (_m *Service) Delete(ctx context.Context, filter *log2.Filter) error { +func (_m *Service) Delete(ctx context.Context, filter *logs.Filter) error { ret := _m.Called(ctx, filter) if len(ret) == 0 { @@ -25,7 +25,7 @@ func (_m *Service) Delete(ctx context.Context, filter *log2.Filter) error { } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *log2.Filter) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, *logs.Filter) error); ok { r0 = rf(ctx, filter) } else { r0 = ret.Error(0) @@ -35,27 +35,27 @@ func (_m *Service) Delete(ctx context.Context, filter *log2.Filter) error { } // Find provides a mock function with given fields: ctx, filter, _a2 -func (_m *Service) Find(ctx context.Context, filter *log2.Filter, _a2 *options.FindOptions) (*log2.FindResult, error) { +func (_m *Service) Find(ctx context.Context, filter *logs.Filter, _a2 *options.FindOptions) (*logs.FindResult, error) { ret := _m.Called(ctx, filter, _a2) if len(ret) == 0 { panic("no return value specified for Find") } - var r0 *log2.FindResult + var r0 *logs.FindResult var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *log2.Filter, *options.FindOptions) (*log2.FindResult, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *logs.Filter, *options.FindOptions) (*logs.FindResult, error)); ok { return rf(ctx, filter, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, *log2.Filter, *options.FindOptions) *log2.FindResult); ok { + if rf, ok := ret.Get(0).(func(context.Context, *logs.Filter, *options.FindOptions) *logs.FindResult); ok { r0 = rf(ctx, filter, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*log2.FindResult) + r0 = ret.Get(0).(*logs.FindResult) } } - if rf, ok := ret.Get(1).(func(context.Context, *log2.Filter, *options.FindOptions) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *logs.Filter, *options.FindOptions) error); ok { r1 = rf(ctx, filter, _a2) } else { r1 = ret.Error(1) @@ -65,7 +65,7 @@ func (_m *Service) Find(ctx context.Context, filter *log2.Filter, _a2 *options.F } // Log provides a mock function with given fields: ctx, entries -func (_m *Service) Log(ctx context.Context, entries []*log2.Entry) error { +func (_m *Service) Log(ctx context.Context, entries []*logs.Entry) error { ret := _m.Called(ctx, entries) if len(ret) == 0 { @@ -73,7 +73,7 @@ func (_m *Service) Log(ctx context.Context, entries []*log2.Entry) error { } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []*log2.Entry) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, []*logs.Entry) error); ok { r0 = rf(ctx, entries) } else { r0 = ret.Error(0) diff --git a/logs/mocks/Storage.go b/logs/mocks/Storage.go index 87a6376d47ee44ece2f9d2458ee05e48a162b8ca..e341b0263c2570f508c4088ed1d9d2408b313e18 100644 --- a/logs/mocks/Storage.go +++ b/logs/mocks/Storage.go @@ -5,7 +5,7 @@ package mocks import ( context "context" - log2 "git.perx.ru/perxis/perxis-go/logs" + logs "git.perx.ru/perxis/perxis-go/logs" mock "github.com/stretchr/testify/mock" options "git.perx.ru/perxis/perxis-go/pkg/options" @@ -17,7 +17,7 @@ type Storage struct { } // Delete provides a mock function with given fields: ctx, filter -func (_m *Storage) Delete(ctx context.Context, filter *log2.Filter) error { +func (_m *Storage) Delete(ctx context.Context, filter *logs.Filter) error { ret := _m.Called(ctx, filter) if len(ret) == 0 { @@ -25,7 +25,7 @@ func (_m *Storage) Delete(ctx context.Context, filter *log2.Filter) error { } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *log2.Filter) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, *logs.Filter) error); ok { r0 = rf(ctx, filter) } else { r0 = ret.Error(0) @@ -35,34 +35,34 @@ func (_m *Storage) Delete(ctx context.Context, filter *log2.Filter) error { } // Find provides a mock function with given fields: ctx, filter, _a2 -func (_m *Storage) Find(ctx context.Context, filter *log2.Filter, _a2 *options.FindOptions) ([]*log2.Entry, int, error) { +func (_m *Storage) Find(ctx context.Context, filter *logs.Filter, _a2 *options.FindOptions) ([]*logs.Entry, int, error) { ret := _m.Called(ctx, filter, _a2) if len(ret) == 0 { panic("no return value specified for Find") } - var r0 []*log2.Entry + var r0 []*logs.Entry var r1 int var r2 error - if rf, ok := ret.Get(0).(func(context.Context, *log2.Filter, *options.FindOptions) ([]*log2.Entry, int, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *logs.Filter, *options.FindOptions) ([]*logs.Entry, int, error)); ok { return rf(ctx, filter, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, *log2.Filter, *options.FindOptions) []*log2.Entry); ok { + if rf, ok := ret.Get(0).(func(context.Context, *logs.Filter, *options.FindOptions) []*logs.Entry); ok { r0 = rf(ctx, filter, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*log2.Entry) + r0 = ret.Get(0).([]*logs.Entry) } } - if rf, ok := ret.Get(1).(func(context.Context, *log2.Filter, *options.FindOptions) int); ok { + if rf, ok := ret.Get(1).(func(context.Context, *logs.Filter, *options.FindOptions) int); ok { r1 = rf(ctx, filter, _a2) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(context.Context, *log2.Filter, *options.FindOptions) error); ok { + if rf, ok := ret.Get(2).(func(context.Context, *logs.Filter, *options.FindOptions) error); ok { r2 = rf(ctx, filter, _a2) } else { r2 = ret.Error(2) @@ -90,7 +90,7 @@ func (_m *Storage) Init(ctx context.Context) error { } // Log provides a mock function with given fields: ctx, entry -func (_m *Storage) Log(ctx context.Context, entry []*log2.Entry) error { +func (_m *Storage) Log(ctx context.Context, entry []*logs.Entry) error { ret := _m.Called(ctx, entry) if len(ret) == 0 { @@ -98,7 +98,7 @@ func (_m *Storage) Log(ctx context.Context, entry []*log2.Entry) error { } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []*log2.Entry) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, []*logs.Entry) error); ok { r0 = rf(ctx, entry) } else { r0 = ret.Error(0) diff --git a/logs/zap/buffered_write_syncer.go b/logs/zap/buffered_write_syncer.go index e862a79d115ecd82bc09622276d4194d39715345..42fae2b134e958045ba2a5986499eac4834862f3 100644 --- a/logs/zap/buffered_write_syncer.go +++ b/logs/zap/buffered_write_syncer.go @@ -71,28 +71,40 @@ func (ws *BufferedWriteSyncer) start() { ws.buffer = make([]*logs.Entry, 0, ws.MaxBufferSize) ws.syncQueue = make(chan []*logs.Entry, ws.MaxSyncQueueSize) ws.flushStop = make(chan struct{}) + ws.started = true ws.wg.Add(2) go ws.syncLoop() go ws.flushLoop() - - ws.started = true } +// Stop останавливает все фоновые работы и синхронизирует оставшиеся записи func (ws *BufferedWriteSyncer) Stop() error { - ws.mu.Lock() - defer ws.mu.Unlock() + // Создаем новую область видимости для блокировки мьютекса только в указанной секции + // Это необходимо, чтобы предотвратить возможный deadlock, который может возникнуть + // если после блокировки мьютекса при остановке будет вызван Sync внутри flushLoop(), + // который будет ожидать освобождения мьютекса + stopped, err := func() (bool, error) { + ws.mu.Lock() + defer ws.mu.Unlock() + + if !ws.started || ws.stopped { + return false, nil + } + ws.stopped = true - if !ws.started || ws.stopped { - return nil - } - ws.stopped = true + close(ws.flushStop) // завершаем flushLoop + + err := ws.flush() // очищаем оставшиеся записи - close(ws.flushStop) // завершаем flushLoop + close(ws.syncQueue) // завершаем syncLoop - err := ws.flush() // очищаем оставшиеся записи + return true, err + }() - close(ws.syncQueue) // завершаем syncLoop + if !stopped { + return nil + } ws.wg.Wait() // дожидаемся завершения flushLoop и syncLoop @@ -127,7 +139,7 @@ func (ws *BufferedWriteSyncer) Sync() error { ws.mu.Lock() defer ws.mu.Unlock() - if ws.started { + if ws.started && !ws.stopped { return ws.flush() } diff --git a/logs/zap/entry_encoder.go b/logs/zap/entry_encoder.go index d7db9b301a7a41c9b869ddcc0c06146afafe9780..e53171c69dc21a0f9b0b0c82e91f087e780c8017 100644 --- a/logs/zap/entry_encoder.go +++ b/logs/zap/entry_encoder.go @@ -4,9 +4,8 @@ import ( "fmt" "slices" - oid "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/id" "git.perx.ru/perxis/perxis-go/logs" - "git.perx.ru/perxis/perxis-go/pkg/id" "git.perx.ru/perxis/perxis-go/zap" "go.uber.org/zap/zapcore" ) @@ -60,9 +59,9 @@ func (enc *entryEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field case "event": ent.Event = clone.fields[i].String case "object": - ent.ObjectID, _ = clone.fields[i].Interface.(*oid.ObjectId) + ent.ObjectID, _ = clone.fields[i].Interface.(*id.ObjectId) case "caller": - ent.CallerID, _ = clone.fields[i].Interface.(*oid.ObjectId) + ent.CallerID, _ = clone.fields[i].Interface.(*id.ObjectId) case "attr": ent.Attr = clone.fields[i].Interface case "error": diff --git a/logs/zap/entry_encoder_slow.go b/logs/zap/entry_encoder_slow.go index 77bf275d93d242ac9ae38f04efe937fa986e5733..8c3f217d126c8ace9983c8de3c57ed11f16235f3 100644 --- a/logs/zap/entry_encoder_slow.go +++ b/logs/zap/entry_encoder_slow.go @@ -4,9 +4,8 @@ import ( "fmt" "maps" - oid "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/id" "git.perx.ru/perxis/perxis-go/logs" - "git.perx.ru/perxis/perxis-go/pkg/id" "go.uber.org/zap/zapcore" ) @@ -51,8 +50,8 @@ func (enc *entryEncoderSlow) EncodeEntry(entry zapcore.Entry, fields []zapcore.F ent.Category, _ = clone.Fields["category"].(string) ent.Component, _ = clone.Fields["component"].(string) ent.Event, _ = clone.Fields["event"].(string) - ent.ObjectID, _ = clone.Fields["object"].(*oid.ObjectId) - ent.CallerID, _ = clone.Fields["caller"].(*oid.ObjectId) + ent.ObjectID, _ = clone.Fields["object"].(*id.ObjectId) + ent.CallerID, _ = clone.Fields["caller"].(*id.ObjectId) ent.Attr = clone.Fields["attr"] if err, _ := clone.Fields["error"].(error); err != nil { diff --git a/logs/zap/entry_encoder_test.go b/logs/zap/entry_encoder_test.go index c83656708d9aba2e4075acce9ad2d28b88dcbb39..13788bda5cea5718de6b33db1c7c251b5f6d1429 100644 --- a/logs/zap/entry_encoder_test.go +++ b/logs/zap/entry_encoder_test.go @@ -1,6 +1,7 @@ package zap import ( + "context" "fmt" "testing" @@ -35,7 +36,7 @@ func TestEntryEncoder_EncodeEntry(t *testing.T) { logzap.Component("Items.Service"), logzap.Event("Items.Create"), logzap.Object("/spaces/WPNN/envs/9VGP/cols/GxNv/items/W0fl"), - logzap.Caller("/users/PHVz"), + logzap.Caller(context.TODO(), logzap.WithObject("/users/PHVz")), logzap.Attr("any"), logzap.Tags("tag1", "tag2", "tag3"), }, @@ -70,7 +71,7 @@ func BenchmarkEntryEncoderSimple(b *testing.B) { fields := []zapcore.Field{ logzap.Event(items.EventCreate), logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)), - logzap.Caller("/system"), + logzap.Caller(context.TODO(), logzap.WithObject("/system")), logzap.Tags("tag1", "tag2", "tag3"), } @@ -84,7 +85,7 @@ func BenchmarkEntryEncoderUnknownFields(b *testing.B) { fields := []zapcore.Field{ logzap.Event(items.EventCreate), logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)), - logzap.Caller("/system"), + logzap.Caller(context.TODO(), logzap.WithObject("/system")), logzap.Tags("tag1", "tag2", "tag3"), } @@ -102,7 +103,7 @@ func BenchmarkEntryEncoderV2Simple(b *testing.B) { fields := []zapcore.Field{ logzap.Event(items.EventCreate), logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)), - logzap.Caller("/system"), + logzap.Caller(context.TODO(), logzap.WithObject("/system")), logzap.Tags("tag1", "tag2", "tag3"), } @@ -116,7 +117,7 @@ func BenchmarkEntryEncoderV2UnknownFields(b *testing.B) { fields := []zapcore.Field{ logzap.Event(items.EventCreate), logzap.Object(items.NewItem("WPNN", "9VGP", "GxNv", "W0fl", nil, nil)), - logzap.Caller("/system"), + logzap.Caller(context.TODO(), logzap.WithObject("/system")), logzap.Tags("tag1", "tag2", "tag3"), } diff --git a/logs/zap/example_test.go b/logs/zap/example_test.go index 7e27fa307fcabe62ad45b6b2f465fdea1b9a2d21..dc182fb0fb764b9b7ca3a232678564c8878a72b0 100644 --- a/logs/zap/example_test.go +++ b/logs/zap/example_test.go @@ -77,7 +77,7 @@ func TestExample(t *testing.T) { logger.Info("Item created", logzap.Event(items.EventCreate), logzap.Object(item), - logzap.CallerFromContext(ctx, item.SpaceID), + logzap.Caller(ctx, logzap.WithSpace(item.SpaceID)), logzap.Tags("tag1", "tag2", "tag3"), ) @@ -85,7 +85,7 @@ func TestExample(t *testing.T) { logger.Warn("Item updated", logzap.Event(items.EventUpdate), logzap.Object(item), - logzap.CallerFromContext(ctx, item.SpaceID), + logzap.Caller(ctx, logzap.WithSpace(item.SpaceID)), logzap.Attr(map[string]map[string]any{"title": {"old": "old title", "new": "new title"}}), ) } diff --git a/perxis-proto b/perxis-proto index f10336dc4a4f58111c12dd95afec82be18388803..b2ac7b057b6e815506d40f9ae41ad16733859d7b 160000 --- a/perxis-proto +++ b/perxis-proto @@ -1 +1 @@ -Subproject commit f10336dc4a4f58111c12dd95afec82be18388803 +Subproject commit b2ac7b057b6e815506d40f9ae41ad16733859d7b diff --git a/pkg/account/client.go b/pkg/account/client.go index 112a71f67fe130bb57c6483ad4793565bca8d0bd..5349ed2917ed691f6661930ea0ffce72a79ab814 100644 --- a/pkg/account/client.go +++ b/pkg/account/client.go @@ -34,10 +34,10 @@ func NewClient(conn *grpc.ClientConn, opts ...Option) *Account { c.logger = zap.NewNop() } - client.Members = membersTransport.NewGRPCClient(conn, "", c.clientOptions...) - client.Organizations = organizationsTransport.NewGRPCClient(conn, "", c.clientOptions...) - client.Users = usersTransport.NewGRPCClient(conn, "", c.clientOptions...) - client.MembersObserver = membersObserverTransport.NewGRPCClient(conn, "", c.clientOptions...) + client.Members = membersTransport.NewClient(conn, c.clientOptions...) + client.Organizations = organizationsTransport.NewClient(conn, c.clientOptions...) + client.Users = usersTransport.NewClient(conn, c.clientOptions...) + client.MembersObserver = membersObserverTransport.NewClient(conn, c.clientOptions...) if !c.noCache { client = WithCaching(client, DefaultCacheSize, DefaultCacheTTL) diff --git a/pkg/account/config.go b/pkg/account/config.go index cfa3f088e56829ad3917e274f6e59938fa0098d7..b86eb543931df7d52a8e19ab8db31b59e1db4b10 100644 --- a/pkg/account/config.go +++ b/pkg/account/config.go @@ -9,7 +9,6 @@ type config struct { noCache bool noLog bool accessLog bool - debug bool clientOptions []kitgrpc.ClientOption // todo: можно заменить на grpc-интерсепторы при соединении и избавиться здесь от go-kit logger *zap.Logger } diff --git a/pkg/content/versions/transport/client.microgen.go b/pkg/account/versions/transport/client.go similarity index 62% rename from pkg/content/versions/transport/client.microgen.go rename to pkg/account/versions/transport/client.go index ec9a69655fab437a4146b6cc61973197f415ff2c..0713d94abcaca463a18d5e129314c0b8769a3ba4 100644 --- a/pkg/content/versions/transport/client.microgen.go +++ b/pkg/account/versions/transport/client.go @@ -4,20 +4,14 @@ package transport import ( "context" - "errors" version "git.perx.ru/perxis/perxis-go/pkg/version" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Get(arg0 context.Context) (res0 *version.Version, res1 error) { request := GetRequest{} response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Version, res1 diff --git a/pkg/account/versions/transport/grpc/client.go b/pkg/account/versions/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..e5a94578ed037a87fbdfb5e7fdb324d401627f62 --- /dev/null +++ b/pkg/account/versions/transport/grpc/client.go @@ -0,0 +1,17 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/account/versions/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + } +} diff --git a/pkg/account/versions/transport/grpc/server.go b/pkg/account/versions/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..960a9d0fba0b36e8658b84a692170714b42e281f --- /dev/null +++ b/pkg/account/versions/transport/grpc/server.go @@ -0,0 +1,17 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/account/versions/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + versions "git.perx.ru/perxis/perxis-go/pkg/version" + pb "git.perx.ru/perxis/perxis-go/proto/versions/account" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc versions.Versions, opts ...grpckit.ServerOption) pb.VersionsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/auth/client.go b/pkg/auth/client.go index 2bb3a12f34c05dc7796165ee9f8e87c66cd91ef2..76645202645c3cd4bea87956329d88c2c6759cd3 100644 --- a/pkg/auth/client.go +++ b/pkg/auth/client.go @@ -50,7 +50,7 @@ func (c *ClientPrincipal) Format(f fmt.State, verb rune) { id = c.client.ID } - f.Write([]byte(fmt.Sprintf("ClientPrincipal{ID: '%s', Identity: {%s}}", id, identity))) + _, _ = f.Write([]byte(fmt.Sprintf("ClientPrincipal{ID: '%s', Identity: {%s}}", id, identity))) } func (c *ClientPrincipal) GetID(ctx context.Context) string { diff --git a/pkg/auth/grpc.go b/pkg/auth/grpc.go index e6cd00929f13a0cf702f1dee8bdb9dcd33768ab6..a947a33bab75da4c55ca9575e15d915fbc480b67 100644 --- a/pkg/auth/grpc.go +++ b/pkg/auth/grpc.go @@ -74,7 +74,7 @@ func ContextToGRPC() kitgrpc.ClientRequestFunc { } } -// PrincipalServerInterceptor - grpc-интерсептор, который используется для получения данных принципала из grpc-метаданы и добавления в контекст ''. В случае, если +// PrincipalServerInterceptor - grpc-интерсептор, который используется для получения данных принципала из grpc-метаданы и добавления в контекст ”. В случае, если // сервис не использует проверку прав 'Principal' к системе, в параметрах передается пустой объект '&PrincipalFactory{}' func PrincipalServerInterceptor(factory *PrincipalFactory) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { @@ -98,6 +98,13 @@ func PrincipalClientInterceptor() grpc.UnaryClientInterceptor { } } +func AddAccessInterceptor(id string) grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + ctx = metadata.AppendToOutgoingContext(ctx, AccessMetadata, id) + return invoker(ctx, method, req, reply, cc, opts...) + } +} + func AddAuthorizationInterceptor(auth string) grpc.UnaryClientInterceptor { return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { ctx = metadata.AppendToOutgoingContext(ctx, "authorization", auth) @@ -124,6 +131,15 @@ func WithOAuth2Credentials(ctx context.Context, tokenURL, clientID, clientSecret // WithTLSCredentials возвращает опции для создания grpc-соединения с TLS-сертификатами func WithTLSCredentials(ctx context.Context, cert, cacert, key []byte) (grpc.DialOption, error) { + creds, err := TLSCredentials(ctx, cert, cacert, key) + if err != nil { + return nil, err + } + return grpc.WithTransportCredentials(creds), nil +} + +// TLSCredentials возвращает TransportCredentials для создания grpc-соединения с TLS-сертификатами +func TLSCredentials(ctx context.Context, cert, cacert, key []byte) (credentials.TransportCredentials, error) { certPool := x509.NewCertPool() if !certPool.AppendCertsFromPEM(cacert) { return nil, errors.New("CA certificate not loaded") @@ -132,5 +148,5 @@ func WithTLSCredentials(ctx context.Context, cert, cacert, key []byte) (grpc.Dia if err != nil { return nil, err } - return grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{Certificates: []tls.Certificate{clientCert}, RootCAs: certPool})), nil + return credentials.NewTLS(&tls.Config{Certificates: []tls.Certificate{clientCert}, RootCAs: certPool}), nil } diff --git a/pkg/auth/user.go b/pkg/auth/user.go index 0bd08c62b4a2ae15b88808a8ad8025020d2f4343..33f7fb4c801f109ff7cad4811cc1d42d93a6ea8d 100644 --- a/pkg/auth/user.go +++ b/pkg/auth/user.go @@ -37,7 +37,7 @@ type UserPrincipal struct { } func (u UserPrincipal) Format(f fmt.State, verb rune) { - f.Write([]byte(fmt.Sprintf("UserPrincipal{ID: '%s', Identity: '%s'}", u.id, u.identity))) + _, _ = f.Write([]byte(fmt.Sprintf("UserPrincipal{ID: '%s', Identity: '%s'}", u.id, u.identity))) } func (u *UserPrincipal) GetID(ctx context.Context) string { diff --git a/pkg/cli/gracefull.go b/pkg/cli/gracefull.go index 8fd64a3d612d2e99e3d3d255a29e4dac00ebd8ea..64ecc3713a6e06de490d22a80c3490f3008110ff 100644 --- a/pkg/cli/gracefull.go +++ b/pkg/cli/gracefull.go @@ -14,23 +14,20 @@ func WaitForQuit(logger *zap.Logger, finailizer func()) { signal.Notify(sigc, syscall.SIGTERM, os.Interrupt) var signalsReceived uint go func() { - for { - select { - case s := <-sigc: - logger.Info("Signal received. Exiting", zap.String("Signal", s.String())) - signalsReceived++ + for s := range sigc { + logger.Info("Signal received. Exiting", zap.String("Signal", s.String())) + signalsReceived++ - if signalsReceived < 2 { - // After first Ctrl+C start quitting the worker gracefully - go func() { - finailizer() - close(donec) - }() - } else { - // Abort the program when user hits Ctrl+C second time in a row - logger.Info("Force exit") + if signalsReceived < 2 { + // After first Ctrl+C start quitting the worker gracefully + go func() { + finailizer() close(donec) - } + }() + } else { + // Abort the program when user hits Ctrl+C second time in a row + logger.Info("Force exit") + close(donec) } } }() diff --git a/pkg/clients/client.go b/pkg/clients/client.go index f38b5acc9b442be39139523bcd316947d5d54fe7..6c4c6735b8ec91f226ba5306b2649252390ffc67 100644 --- a/pkg/clients/client.go +++ b/pkg/clients/client.go @@ -45,6 +45,11 @@ type TLS struct { Key string `json:"key,omitempty"` } +// GetID возвращает идентификатор клиента +func (c Client) GetID() string { + return c.ID +} + func (c *Client) SetDisabled(b bool) *Client { c.Disabled = &b return c diff --git a/pkg/clients/events.go b/pkg/clients/events.go new file mode 100644 index 0000000000000000000000000000000000000000..98ece5ff8a62e11e14b3c23e873feafe3e1fcc38 --- /dev/null +++ b/pkg/clients/events.go @@ -0,0 +1,9 @@ +package clients + +const ( + EventCreate = "clients.create" + EventUpdate = "clients.update" + EventDelete = "clients.delete" + EventEnable = "clients.enable" + EventDisable = "clients.disable" +) diff --git a/pkg/clients/middleware/caching_middleware.go b/pkg/clients/middleware/caching_middleware.go index 08af3a47a7cd3f23b8ae07e4050f9e18f1be1ee3..0dd4f15b4e24affb13562c57a1d69b0e3adce33d 100644 --- a/pkg/clients/middleware/caching_middleware.go +++ b/pkg/clients/middleware/caching_middleware.go @@ -6,6 +6,7 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/cache" service "git.perx.ru/perxis/perxis-go/pkg/clients" + "git.perx.ru/perxis/perxis-go/pkg/data" ) func makeKey(ss ...string) string { @@ -30,7 +31,7 @@ func (m cachingMiddleware) Create(ctx context.Context, client *service.Client) ( cl, err = m.next.Create(ctx, client) if err == nil { - m.cache.Remove(cl.SpaceID) + _ = m.cache.Remove(cl.SpaceID) } return cl, err } @@ -40,16 +41,17 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId string, id string) ( key := makeKey(spaceId, id) value, e := m.cache.Get(key) if e == nil { - return value.(*service.Client), err + return value.(*service.Client).Clone(), nil } cl, err = m.next.Get(ctx, spaceId, id) if err == nil { - m.cache.Set(key, cl) + _ = m.cache.Set(key, cl) for _, key := range keysFromIdentities(spaceId, cl) { - m.cache.Set(key, cl) + _ = m.cache.Set(key, cl) } + return cl.Clone(), nil } - return cl, err + return nil, err } func (m cachingMiddleware) GetBy(ctx context.Context, spaceId string, params *service.GetByParams) (cl *service.Client, err error) { @@ -60,29 +62,31 @@ func (m cachingMiddleware) GetBy(ctx context.Context, spaceId string, params *se key := getIdentKey(spaceId, params) value, e := m.cache.Get(key) if e == nil { - return value.(*service.Client), err + return value.(*service.Client).Clone(), nil } cl, err = m.next.GetBy(ctx, spaceId, params) if err == nil { - m.cache.Set(makeKey(spaceId, cl.ID), cl) + _ = m.cache.Set(makeKey(spaceId, cl.ID), cl) for _, key := range keysFromIdentities(spaceId, cl) { - m.cache.Set(key, cl) + _ = m.cache.Set(key, cl) } + return cl.Clone(), nil } - return cl, err + return nil, err } func (m cachingMiddleware) List(ctx context.Context, spaceId string) (clients []*service.Client, err error) { value, e := m.cache.Get(spaceId) if e == nil { - return value.([]*service.Client), err + return data.CloneSlice(value.([]*service.Client)), nil } clients, err = m.next.List(ctx, spaceId) if err == nil { - m.cache.Set(spaceId, clients) + _ = m.cache.Set(spaceId, clients) + return data.CloneSlice(clients), nil } - return clients, err + return nil, err } func (m cachingMiddleware) Update(ctx context.Context, client *service.Client) (err error) { @@ -90,13 +94,13 @@ func (m cachingMiddleware) Update(ctx context.Context, client *service.Client) ( err = m.next.Update(ctx, client) if err == nil { - m.cache.Remove(client.SpaceID) + _ = m.cache.Remove(client.SpaceID) value, e := m.cache.Get(makeKey(client.SpaceID, client.ID)) if e == nil { client := value.(*service.Client) - m.cache.Remove(makeKey(client.SpaceID, client.ID)) + _ = m.cache.Remove(makeKey(client.SpaceID, client.ID)) for _, key := range keysFromIdentities(client.SpaceID, client) { - m.cache.Remove(key) + _ = m.cache.Remove(key) } } } @@ -110,12 +114,12 @@ func (m cachingMiddleware) Delete(ctx context.Context, spaceId string, id string value, e := m.cache.Get(makeKey(spaceId, id)) if e == nil { client := value.(*service.Client) - m.cache.Remove(makeKey(client.SpaceID, client.ID)) + _ = m.cache.Remove(makeKey(client.SpaceID, client.ID)) for _, key := range keysFromIdentities(client.SpaceID, client) { - m.cache.Remove(key) + _ = m.cache.Remove(key) } } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) } return err } @@ -127,12 +131,12 @@ func (m cachingMiddleware) Enable(ctx context.Context, spaceId string, id string value, e := m.cache.Get(makeKey(spaceId, id)) if e == nil { client := value.(*service.Client) - m.cache.Remove(makeKey(client.SpaceID, client.ID)) + _ = m.cache.Remove(makeKey(client.SpaceID, client.ID)) for _, key := range keysFromIdentities(client.SpaceID, client) { - m.cache.Remove(key) + _ = m.cache.Remove(key) } } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) } return err } diff --git a/pkg/clients/middleware/caching_middleware_test.go b/pkg/clients/middleware/caching_middleware_test.go index 2a90c1db2c322ca9509cb2bf9bdd63b252e67c68..821d2cb29579029f10e1726291212b6ccaeaceae 100644 --- a/pkg/clients/middleware/caching_middleware_test.go +++ b/pkg/clients/middleware/caching_middleware_test.go @@ -40,11 +40,13 @@ func TestClientsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша, после повторного запроса.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша, после повторного запроса.") + assert.NotSame(t, v1, v2) v3, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша при запросе по ClientID.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша при запросе по ClientID.") + assert.NotSame(t, v2, v3) cs.AssertExpectations(t) }) @@ -61,11 +63,13 @@ func TestClientsCache(t *testing.T) { v2, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша, после повторного запроса.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша, после повторного запроса.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша, после запроса Get.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша, после запроса Get.") + assert.NotSame(t, v2, v3) cs.AssertExpectations(t) }) @@ -82,7 +86,8 @@ func TestClientsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.AssertExpectations(t) }) @@ -102,11 +107,13 @@ func TestClientsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша по ClientID.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша по ClientID.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) @@ -114,7 +121,8 @@ func TestClientsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) assert.Len(t, vl2, 1) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.On("Update", mock.Anything, mock.Anything).Return(nil).Once() @@ -126,16 +134,17 @@ func TestClientsCache(t *testing.T) { vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается получение объектов из кэша, после повторного запроса.") v4, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.NotSame(t, v2, v4, "Ожидает что после обновления объект был удален из кэша и будет запрошен заново из сервиса.") + assert.NotEqual(t, v2, v4, "Ожидает что после обновления объект был удален из кэша и будет запрошен заново из сервиса.") v5, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) require.NoError(t, err) - assert.NotSame(t, v3, v5) - assert.Same(t, v4, v5, "Ожидается что после обновления объект был удален из кеша и после запроса Get в кеш попал объект запрошенный заново из сервиса.") + assert.NotEqual(t, v3, v5) + assert.Equal(t, v4, v5, "Ожидается что после обновления объект был удален из кеша и после запроса Get в кеш попал объект запрошенный заново из сервиса.") + assert.NotSame(t, v4, v5) cs.AssertExpectations(t) }) @@ -153,7 +162,8 @@ func TestClientsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) assert.Len(t, vl2, 1) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.On("Update", mock.Anything, mock.Anything).Return(nil).Once() @@ -164,7 +174,7 @@ func TestClientsCache(t *testing.T) { vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается получение объектов из кэша, после повторного запроса.") cs.AssertExpectations(t) }) @@ -182,18 +192,21 @@ func TestClientsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша по ClientID.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша по ClientID.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.On("Delete", mock.Anything, spaceID, cltID).Return(nil).Once() @@ -231,7 +244,8 @@ func TestClientsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.On("Delete", mock.Anything, spaceID, cltID).Return(nil).Once() @@ -259,7 +273,8 @@ func TestClientsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) assert.Len(t, vl2, 1, "Ожидается получение объектов из кэша.") cs.On("Create", mock.Anything, mock.Anything).Return(&clients.Client{ID: "cltID2", SpaceID: spaceID, Name: "client_2"}, nil).Once() @@ -290,18 +305,21 @@ func TestClientsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша по ClientID.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша по ClientID.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.On("Enable", mock.Anything, spaceID, cltID, tr).Return(nil).Once() @@ -314,14 +332,15 @@ func TestClientsCache(t *testing.T) { v4, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.NotSame(t, v2, v4, "Ожидается что после активации объект был удален из кэша и запрошен у сервиса.") + assert.NotEqual(t, v2, v4, "Ожидается что после активации объект был удален из кэша и запрошен у сервиса.") v5, err := svc.GetBy(ctx, spaceID, &clients.GetByParams{OAuthClientID: clientID}) - assert.NotSame(t, v3, v5, "Ожидается что после активации объект был удален из кеша и после запроса Get в кеш попал объект запрошенный заново из сервиса.") + require.NoError(t, err) + assert.NotEqual(t, v3, v5, "Ожидается что после активации объект был удален из кеша и после запроса Get в кеш попал объект запрошенный заново из сервиса.") vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается что после активации объекта, кеш будет очищен и объекты будут запрошены заново из сервиса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается что после активации объекта, кеш будет очищен и объекты будут запрошены заново из сервиса.") cs.AssertExpectations(t) }) @@ -339,7 +358,8 @@ func TestClientsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша, после повторного запроса.") + assert.NotSame(t, vl1[0], vl2[0]) cs.On("Enable", mock.Anything, spaceID, cltID, tr).Return(nil).Once() @@ -351,7 +371,7 @@ func TestClientsCache(t *testing.T) { vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается что после активации объекта, кеш будет очищен и объекты будут запрошены заново из сервиса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается что после активации объекта, кеш будет очищен и объекты будут запрошены заново из сервиса.") cs.AssertExpectations(t) }) @@ -368,13 +388,16 @@ func TestClientsCache(t *testing.T) { require.NoError(t, err) v2, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша после повторного запроса.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша после повторного запроса.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) v3, err := svc.Get(ctx, spaceID, cltID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается что элемент был удален из кэша по истечению ttl и будет запрошен заново из сервиса.") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) cs.AssertExpectations(t) }) diff --git a/pkg/clients/middleware/logging_middleware.go b/pkg/clients/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..8cc5e384fa8fcadee5dc86c84444dead233bcb81 --- /dev/null +++ b/pkg/clients/middleware/logging_middleware.go @@ -0,0 +1,145 @@ +package middleware + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/clients" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next clients.Clients +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next clients.Clients) clients.Clients { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Clients")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, client *clients.Client) (created *clients.Client, err error) { + logger := m.logger.With( + logzap.Caller(ctx, logzap.WithSpace(client.SpaceID)), + logzap.Event(clients.EventCreate), + ) + + created, err = m.next.Create(ctx, client) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(client)) + return + } + + logger.Info("Client created", logzap.Channels(logzap.Userlog), logzap.Object(created)) + + return created, err +} + +func (m *loggingMiddleware) Get(ctx context.Context, spaceId, clientId string) (client *clients.Client, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewClientId(spaceId, clientId)), + ) + + client, err = m.next.Get(ctx, spaceId, clientId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return client, err +} + +func (m *loggingMiddleware) GetBy(ctx context.Context, spaceId string, params *clients.GetByParams) (client *clients.Client, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + client, err = m.next.GetBy(ctx, spaceId, params) + if err != nil { + logger.Error("Failed to get by", zap.Error(err)) + return + } + + return client, err +} + +func (m *loggingMiddleware) List(ctx context.Context, spaceId string) (clients []*clients.Client, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + clients, err = m.next.List(ctx, spaceId) + if err != nil { + logger.Error("Failed to list", zap.Error(err)) + return + } + + return clients, err +} + +func (m *loggingMiddleware) Update(ctx context.Context, client *clients.Client) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(clients.EventUpdate), + logzap.Object(client), + ) + + err = m.next.Update(ctx, client) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Client updated", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, spaceId, clientId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(clients.EventDelete), + logzap.Object(id.NewClientId(spaceId, clientId)), + ) + + err = m.next.Delete(ctx, spaceId, clientId) + if err != nil { + logger.Error("Failed to delete", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Client deleted", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Enable(ctx context.Context, spaceId, clientId string, enable bool) (err error) { + event := clients.EventDisable + logMsg := "disable" + + if enable { + event = clients.EventEnable + logMsg = "enable" + } + + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(event), + logzap.Object(id.NewClientId(spaceId, clientId)), + ) + + err = m.next.Enable(ctx, spaceId, clientId, enable) + if err != nil { + logger.Error("Failed to "+logMsg, zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Client "+logMsg+"d", logzap.Channels(logzap.Userlog)) + return err +} diff --git a/pkg/clients/middleware/middleware.go b/pkg/clients/middleware/middleware.go index 0c72c1660e15f147a773e2da5e2f31b469b90260..945ae1f2afde7274140b6cbd3c84fff260d0b1cb 100644 --- a/pkg/clients/middleware/middleware.go +++ b/pkg/clients/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s clients.Clients, logger *zap.Logger, log_access bool) clients.Cli if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/clients/transport/client.microgen.go b/pkg/clients/transport/client.go similarity index 66% rename from pkg/clients/transport/client.microgen.go rename to pkg/clients/transport/client.go index 633855af4d1f7fe74260ec7b4ece23db6063ebfb..008f60b019deac5e9e86aff7a6687a3c3fe8361a 100644 --- a/pkg/clients/transport/client.microgen.go +++ b/pkg/clients/transport/client.go @@ -4,19 +4,13 @@ package transport import ( "context" - "errors" clients "git.perx.ru/perxis/perxis-go/pkg/clients" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *clients.Client) (res0 *clients.Client, res1 error) { request := CreateRequest{Client: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 @@ -29,9 +23,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string) (res } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Client, res1 @@ -44,9 +35,6 @@ func (set EndpointsSet) GetBy(arg0 context.Context, arg1 string, arg2 *clients.G } response, res1 := set.GetByEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetByResponse).Client, res1 @@ -56,9 +44,6 @@ func (set EndpointsSet) List(arg0 context.Context, arg1 string) (res0 []*clients request := ListRequest{SpaceId: arg1} response, res1 := set.ListEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListResponse).Clients, res1 @@ -68,9 +53,6 @@ func (set EndpointsSet) Update(arg0 context.Context, arg1 *clients.Client) (res0 request := UpdateRequest{Client: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -83,9 +65,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string, arg2 string) ( } _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -99,9 +78,6 @@ func (set EndpointsSet) Enable(arg0 context.Context, arg1 string, arg2 string, a } _, res0 = set.EnableEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/clients/transport/grpc/client.go b/pkg/clients/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..fe6ba6fc8a14622b002b7f96b73f124c2ff2d5b2 --- /dev/null +++ b/pkg/clients/transport/grpc/client.go @@ -0,0 +1,23 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/clients/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + GetByEndpoint: grpcerr.ClientMiddleware(c.GetByEndpoint), + ListEndpoint: grpcerr.ClientMiddleware(c.ListEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + EnableEndpoint: grpcerr.ClientMiddleware(c.EnableEndpoint), + } +} diff --git a/pkg/clients/transport/grpc/server.go b/pkg/clients/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..ee019551141c4e3c6af7d4805cb6924a19e4d010 --- /dev/null +++ b/pkg/clients/transport/grpc/server.go @@ -0,0 +1,23 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/clients" + "git.perx.ru/perxis/perxis-go/pkg/clients/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + pb "git.perx.ru/perxis/perxis-go/proto/clients" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc clients.Clients, opts ...grpckit.ServerOption) pb.ClientsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + GetByEndpoint: grpcerr.ServerMiddleware(eps.GetByEndpoint), + ListEndpoint: grpcerr.ServerMiddleware(eps.ListEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + EnableEndpoint: grpcerr.ServerMiddleware(eps.EnableEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/collaborators/collaborator.go b/pkg/collaborators/collaborator.go index 701d8e85b578dafc2036c281c204720080412ac5..5fe1b481c231568af13b9c9e827eede723312576 100644 --- a/pkg/collaborators/collaborator.go +++ b/pkg/collaborators/collaborator.go @@ -5,3 +5,11 @@ type Collaborator struct { Subject string `bson:"subject"` Role string `bson:"role"` } + +func (c Collaborator) Clone() *Collaborator { + return &Collaborator{ + SpaceID: c.SpaceID, + Subject: c.Subject, + Role: c.Role, + } +} diff --git a/pkg/collaborators/events.go b/pkg/collaborators/events.go new file mode 100644 index 0000000000000000000000000000000000000000..9f4a8b7c2493f2b65a690f675f5a27a7eb344533 --- /dev/null +++ b/pkg/collaborators/events.go @@ -0,0 +1,6 @@ +package collaborators + +const ( + EventSet = "collaborators.set" + EventRemove = "collaborators.remove" +) diff --git a/pkg/collaborators/middleware/caching_middleware.go b/pkg/collaborators/middleware/caching_middleware.go index 7533ae551ed47a421d3fe8ed643ce679e07fddc2..7faeb638b0ca2bb673de4852c21e75b7f1f9afc7 100644 --- a/pkg/collaborators/middleware/caching_middleware.go +++ b/pkg/collaborators/middleware/caching_middleware.go @@ -6,6 +6,7 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/cache" service "git.perx.ru/perxis/perxis-go/pkg/collaborators" + "git.perx.ru/perxis/perxis-go/pkg/data" ) func makeKey(ss ...string) string { @@ -30,8 +31,8 @@ func (m cachingMiddleware) Set(ctx context.Context, spaceId, subject, role strin err = m.next.Set(ctx, spaceId, subject, role) if err == nil { - m.cache.Remove(spaceId) - m.cache.Remove(subject) + _ = m.cache.Remove(spaceId) + _ = m.cache.Remove(subject) } return err } @@ -45,7 +46,7 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId, subject string) (ro } role, err = m.next.Get(ctx, spaceId, subject) if err == nil { - m.cache.Set(key, role) + _ = m.cache.Set(key, role) } return role, err } @@ -54,9 +55,9 @@ func (m cachingMiddleware) Remove(ctx context.Context, spaceId, subject string) err = m.next.Remove(ctx, spaceId, subject) if err == nil { - m.cache.Remove(makeKey(spaceId, subject)) - m.cache.Remove(spaceId) - m.cache.Remove(subject) + _ = m.cache.Remove(makeKey(spaceId, subject)) + _ = m.cache.Remove(spaceId) + _ = m.cache.Remove(subject) } return err } @@ -65,24 +66,26 @@ func (m cachingMiddleware) ListCollaborators(ctx context.Context, spaceId string value, e := m.cache.Get(spaceId) if e == nil { - return value.([]*service.Collaborator), err + return data.CloneSlice(value.([]*service.Collaborator)), nil } collaborators, err = m.next.ListCollaborators(ctx, spaceId) if err == nil { - m.cache.Set(spaceId, collaborators) + _ = m.cache.Set(spaceId, collaborators) + return data.CloneSlice(collaborators), nil } - return collaborators, err + return nil, err } func (m cachingMiddleware) ListSpaces(ctx context.Context, subject string) (collaborators []*service.Collaborator, err error) { value, e := m.cache.Get(subject) if e == nil { - return value.([]*service.Collaborator), err + return data.CloneSlice(value.([]*service.Collaborator)), nil } collaborators, err = m.next.ListSpaces(ctx, subject) if err == nil { - m.cache.Set(subject, collaborators) + _ = m.cache.Set(subject, collaborators) + return data.CloneSlice(collaborators), nil } - return collaborators, err + return nil, err } diff --git a/pkg/collaborators/middleware/caching_middleware_test.go b/pkg/collaborators/middleware/caching_middleware_test.go index ea2ccaddb2621c306e317d6d873a455489a6a2a6..6b96d0a8ff65dcc56d3139e2b99eac28720bb364 100644 --- a/pkg/collaborators/middleware/caching_middleware_test.go +++ b/pkg/collaborators/middleware/caching_middleware_test.go @@ -56,7 +56,8 @@ func TestCollaboratorsCache(t *testing.T) { require.NoError(t, err) v2, err := svc.ListCollaborators(ctx, spaceID) require.NoError(t, err) - assert.Same(t, v1[0], v2[0], "Ожидается получение объектов из кэша при повторном запросе.") + assert.Equal(t, v1[0], v2[0], "Ожидается получение объектов из кэша при повторном запросе.") + assert.NotSame(t, v1[0], v2[0]) cs.AssertExpectations(t) }) @@ -72,7 +73,8 @@ func TestCollaboratorsCache(t *testing.T) { require.NoError(t, err) v2, err := svc.ListSpaces(ctx, userID) require.NoError(t, err) - assert.Same(t, v1[0], v2[0], "Ожидается получение объектов из кэша при повторном запросе.") + assert.Equal(t, v1[0], v2[0], "Ожидается получение объектов из кэша при повторном запросе.") + assert.NotSame(t, v1[0], v2[0]) cs.AssertExpectations(t) }) @@ -98,13 +100,15 @@ func TestCollaboratorsCache(t *testing.T) { require.NoError(t, err) lc2, err := svc.ListCollaborators(ctx, spaceID) require.NoError(t, err) - assert.Same(t, lc1[0], lc2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, lc1[0], lc2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, lc1[0], lc2[0]) ls1, err := svc.ListSpaces(ctx, userID) require.NoError(t, err) ls2, err := svc.ListSpaces(ctx, userID) require.NoError(t, err) - assert.Same(t, ls1[0], ls2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, ls1[0], ls2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, ls1[0], ls2[0]) cs.On("Remove", mock.Anything, spaceID, userID).Return(nil).Once() @@ -113,6 +117,7 @@ func TestCollaboratorsCache(t *testing.T) { cs.On("ListSpaces", mock.Anything, userID).Return(nil, errNotFound).Once() err = svc.Remove(ctx, spaceID, userID) + require.NoError(t, err) rl, err = svc.Get(ctx, spaceID, userID) require.Error(t, err) @@ -152,13 +157,15 @@ func TestCollaboratorsCache(t *testing.T) { require.NoError(t, err) lc2, err := svc.ListCollaborators(ctx, spaceID) require.NoError(t, err) - assert.Same(t, lc1[0], lc2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, lc1[0], lc2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, lc1[0], lc2[0]) ls1, err := svc.ListSpaces(ctx, userID) require.NoError(t, err) ls2, err := svc.ListSpaces(ctx, userID) require.NoError(t, err) - assert.Same(t, ls1[0], ls2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, ls1[0], ls2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, ls1[0], ls2[0]) cs.On("Remove", mock.Anything, spaceID, userID).Return(nil).Once() @@ -167,6 +174,7 @@ func TestCollaboratorsCache(t *testing.T) { cs.On("ListSpaces", mock.Anything, userID).Return(nil, errNotFound).Once() err = svc.Remove(ctx, spaceID, userID) + require.NoError(t, err) rl, err = svc.Get(ctx, spaceID, userID) require.Error(t, err) diff --git a/pkg/collaborators/middleware/logging_middleware.go b/pkg/collaborators/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..645750f0ff7244275a70eaac24e98977d9702e0d --- /dev/null +++ b/pkg/collaborators/middleware/logging_middleware.go @@ -0,0 +1,103 @@ +package middleware + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/collaborators" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next collaborators.Collaborators +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next collaborators.Collaborators) collaborators.Collaborators { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Collaborators")), + } + } +} + +func (m *loggingMiddleware) Set(ctx context.Context, spaceId, subject, role string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(collaborators.EventSet), + logzap.Object(id.NewSpaceId(spaceId)), + ) + + err = m.next.Set(ctx, spaceId, subject, role) + if err != nil { + logger.Error(fmt.Sprintf("Failed to set user '%s' as a collaborator with role '%s'", subject, role), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("User '%s' assigned to role '%s'", subject, role), logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Get(ctx context.Context, spaceId, subject string) (role string, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + role, err = m.next.Get(ctx, spaceId, subject) + if err != nil { + logger.Error(fmt.Sprintf("Failed to get role for collaborator %s", subject), zap.Error(err)) + return + } + + return role, err +} + +func (m *loggingMiddleware) Remove(ctx context.Context, spaceId, subject string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(collaborators.EventRemove), + logzap.Object(id.NewSpaceId(spaceId)), + ) + + err = m.next.Remove(ctx, spaceId, subject) + if err != nil { + logger.Error(fmt.Sprintf("Failed to remove user '%s' from space", subject), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("User '%s' removed from space", subject), logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) ListCollaborators(ctx context.Context, spaceId string) (collaborators []*collaborators.Collaborator, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + collaborators, err = m.next.ListCollaborators(ctx, spaceId) + if err != nil { + logger.Error("Failed to list collaborators", zap.Error(err)) + return + } + + return collaborators, err +} + +func (m *loggingMiddleware) ListSpaces(ctx context.Context, subject string) (spaces []*collaborators.Collaborator, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + spaces, err = m.next.ListSpaces(ctx, subject) + if err != nil { + logger.Error("Failed to list spaces", zap.Error(err)) + return + } + + return spaces, err +} diff --git a/pkg/collaborators/middleware/middleware.go b/pkg/collaborators/middleware/middleware.go index 28f0bc687c5ee66f2395303efa502149f8394644..a336e089fc00e9984ba4ddb1c9d656a46d98c493 100644 --- a/pkg/collaborators/middleware/middleware.go +++ b/pkg/collaborators/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s collaborators.Collaborators, logger *zap.Logger, log_access bool) if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/collaborators/transport/client.microgen.go b/pkg/collaborators/transport/client.go similarity index 67% rename from pkg/collaborators/transport/client.microgen.go rename to pkg/collaborators/transport/client.go index eb0dbbe7bc1ea7bad07220fba5cdc6e3b1c9e503..1e6477a11347742e6cf250ff336d3ca7f89b5ac0 100644 --- a/pkg/collaborators/transport/client.microgen.go +++ b/pkg/collaborators/transport/client.go @@ -4,11 +4,8 @@ package transport import ( "context" - "errors" collaborators "git.perx.ru/perxis/perxis-go/pkg/collaborators" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Set(arg0 context.Context, arg1 string, arg2 string, arg3 string) (res0 error) { @@ -19,9 +16,6 @@ func (set EndpointsSet) Set(arg0 context.Context, arg1 string, arg2 string, arg3 } _, res0 = set.SetEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -34,9 +28,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string) (res } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Role, res1 @@ -49,9 +40,6 @@ func (set EndpointsSet) Remove(arg0 context.Context, arg1 string, arg2 string) ( } _, res0 = set.RemoveEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -61,9 +49,6 @@ func (set EndpointsSet) ListCollaborators(arg0 context.Context, arg1 string) (re request := ListCollaboratorsRequest{SpaceId: arg1} response, res1 := set.ListCollaboratorsEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListCollaboratorsResponse).Collaborators, res1 @@ -73,9 +58,6 @@ func (set EndpointsSet) ListSpaces(arg0 context.Context, arg1 string) (res0 []*c request := ListSpacesRequest{Subject: arg1} response, res1 := set.ListSpacesEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListSpacesResponse).Spaces, res1 diff --git a/pkg/collaborators/transport/grpc/client.go b/pkg/collaborators/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..ed7c951fe02289ce5d20e4ffec6d473024344591 --- /dev/null +++ b/pkg/collaborators/transport/grpc/client.go @@ -0,0 +1,21 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/collaborators/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + ListSpacesEndpoint: grpcerr.ClientMiddleware(c.ListSpacesEndpoint), + ListCollaboratorsEndpoint: grpcerr.ClientMiddleware(c.ListCollaboratorsEndpoint), + RemoveEndpoint: grpcerr.ClientMiddleware(c.RemoveEndpoint), + SetEndpoint: grpcerr.ClientMiddleware(c.SetEndpoint), + } +} diff --git a/pkg/collaborators/transport/grpc/server.go b/pkg/collaborators/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..fa96dd487e740a10eadc1efbf8c10509c06940cb --- /dev/null +++ b/pkg/collaborators/transport/grpc/server.go @@ -0,0 +1,21 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/collaborators" + "git.perx.ru/perxis/perxis-go/pkg/collaborators/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + pb "git.perx.ru/perxis/perxis-go/proto/collaborators" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc collaborators.Collaborators, opts ...grpckit.ServerOption) pb.CollaboratorsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + ListSpacesEndpoint: grpcerr.ServerMiddleware(eps.ListSpacesEndpoint), + ListCollaboratorsEndpoint: grpcerr.ServerMiddleware(eps.ListCollaboratorsEndpoint), + RemoveEndpoint: grpcerr.ServerMiddleware(eps.RemoveEndpoint), + SetEndpoint: grpcerr.ServerMiddleware(eps.SetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/collections/collection.go b/pkg/collections/collection.go index 85ab01999816f8ab986c69495d737ce3f1e8160e..b5d2418aac40332c99b08b31a5df128007e1b7a6 100644 --- a/pkg/collections/collection.go +++ b/pkg/collections/collection.go @@ -3,6 +3,7 @@ package collections import ( "time" + "git.perx.ru/perxis/perxis-go/pkg/data" "git.perx.ru/perxis/perxis-go/pkg/permission" "git.perx.ru/perxis/perxis-go/pkg/schema" ) @@ -51,16 +52,28 @@ func (a Access) Can(action permission.Action) bool { } type Collection struct { - ID string `json:"id" bson:"id"` - SpaceID string `json:"spaceId" bson:"-"` - EnvID string `json:"envId" bson:"-"` - Name string `json:"name" bson:"name"` - Single *bool `json:"single" bson:"single,omitempty"` // В коллекции может быть только один документ - System *bool `json:"system" bson:"system,omitempty"` // Системная коллекция - NoData *bool `json:"no_data" bson:"no_data"` // Коллекция не содержит элементы. Схема используется для включения в другие схемы - Hidden bool `json:"hidden" bson:"hidden"` // Коллекция скрыта в административном интерфейсе - Schema *schema.Schema `json:"schema" bson:"schema"` - Access *Access `json:"access" bson:"-"` // Ограничения на доступ к элементам коллекции. Отсутствие объекта означает неограниченный доступ + ID string `json:"id" bson:"id"` + SpaceID string `json:"spaceId" bson:"-"` + EnvID string `json:"envId" bson:"-"` + Name string `json:"name" bson:"name"` + Single *bool `json:"single" bson:"single,omitempty"` // В коллекции может быть только один документ + System *bool `json:"system" bson:"system,omitempty"` // Системная коллекция + NoData *bool `json:"no_data" bson:"no_data"` // Коллекция не содержит элементы. Схема используется для включения в другие схемы + Hidden bool `json:"hidden" bson:"hidden"` // Коллекция скрыта в административном интерфейсе + + NoArchive bool `json:"no_archive" bson:"no_archive,omitempty"` // Коллекция без архива + + NoRevisions bool `json:"no_revisions" bson:"no_revisions,omitempty"` // Не хранить историю изменений + MaxRevisions uint32 `json:"max_revisions" bson:"max_revisions,omitempty"` // Максимальное количество хранимых ревизий + RevisionTTL time.Duration `json:"revision_ttl" bson:"revision_ttl,omitempty"` // Время жизни ревизии + + // Все записи коллекции считаются опубликованными, функции публикации и снятия с публикации недоступны. + // При включении параметра коллекции "без публикации" все записи, независимо от статуса, будут считаться опубликованными. + // При отключении параметра "без публикации" статусы публикации будут восстановлены. + NoPublish bool `json:"no_publish" bson:"no_publish,omitempty"` + + Schema *schema.Schema `json:"schema" bson:"schema"` + Access *Access `json:"access" bson:"-"` // Ограничения на доступ к элементам коллекции. Отсутствие объекта означает неограниченный доступ // StateInfo отображает состояние коллекции: // - State: идентификатор состояния коллекции (new/preparing/ready/error/changed) @@ -79,6 +92,33 @@ type Collection struct { Config *Config `json:"-" bson:"-"` } +// GetID возвращает идентификатор коллекции +func (c Collection) GetID() string { + return c.ID +} + +// Equal сравнивает две коллекции, за исключением Schema, Access, StateInfo и Config +func (c Collection) Equal(other *Collection) bool { + if c.ID != other.ID || + c.SpaceID != other.SpaceID || + c.EnvID != other.EnvID || + c.Name != other.Name || + c.IsNoData() != other.IsNoData() || + c.IsSingle() != other.IsSingle() || + c.IsSystem() != other.IsSystem() || + c.Hidden != other.Hidden || + c.NoPublish != other.NoPublish || + c.NoArchive != other.NoArchive || + c.NoRevisions != other.NoRevisions || + c.MaxRevisions != other.MaxRevisions || + c.RevisionTTL != other.RevisionTTL || + !c.View.Equal(other.View) || + !data.ElementsMatch(c.Tags, other.Tags) { + return false + } + return true +} + type View struct { SpaceID string `json:"space_id" bson:"space_id"` // SpaceID оригинальной коллекции EnvID string `json:"environment_id" bson:"environment_id"` // EnvID оригинальной коллекции @@ -133,14 +173,18 @@ const ( ) func (c Collection) Clone() *Collection { - clone := &Collection{ - ID: c.ID, - SpaceID: c.SpaceID, - EnvID: c.EnvID, - Name: c.Name, - NoData: c.NoData, - Hidden: c.Hidden, + ID: c.ID, + SpaceID: c.SpaceID, + EnvID: c.EnvID, + Name: c.Name, + NoData: c.NoData, + Hidden: c.Hidden, + NoPublish: c.NoPublish, + NoArchive: c.NoArchive, + NoRevisions: c.NoRevisions, + MaxRevisions: c.MaxRevisions, + RevisionTTL: c.RevisionTTL, } if c.Single != nil { diff --git a/pkg/collections/marshal.go b/pkg/collections/marshal.go new file mode 100644 index 0000000000000000000000000000000000000000..21c7bed0c5a8edb83780a19d31045d8b8c07f9ef --- /dev/null +++ b/pkg/collections/marshal.go @@ -0,0 +1,92 @@ +package collections + +import ( + "reflect" + "strconv" + "time" + + "git.perx.ru/perxis/perxis-go/pkg/optional" + "git.perx.ru/perxis/perxis-go/pkg/schema" + jsoniter "github.com/json-iterator/go" +) + +// UnmarshalJSON implements json.Unmarshaler interface +func (c *Collection) UnmarshalJSON(b []byte) error { + type collection Collection + var cc, zero collection + + // Пытаемся распарсить как коллекцию + if err := jsoniter.Unmarshal(b, &cc); err != nil { + return err + } + + // Если это не пустая коллекция, то просто присваиваем + if !reflect.DeepEqual(cc, zero) { + *c = Collection(cc) + return nil + } + + // Пытаемся распарсить как схему + var s schema.Schema + if err := jsoniter.Unmarshal(b, &s); err != nil { + return err + } + *c = *FromSchema(&s) + return nil +} + +// FromSchema создает новую коллекцию из схемы +func FromSchema(sch *schema.Schema) *Collection { + if sch == nil { + return nil + } + + coll := &Collection{Schema: sch} + + coll.ID = sch.Metadata["collection_id"] + coll.Name = sch.Metadata["collection_name"] + + if single, ok := sch.Metadata["collection_single"]; ok && single == "true" { + coll.Single = optional.True + } + if system, ok := sch.Metadata["collection_system"]; ok && system == "true" { + coll.System = optional.True + } + if nodata, ok := sch.Metadata["collection_nodata"]; ok && nodata == "true" { + coll.NoData = optional.True + } + if hidden, ok := sch.Metadata["collection_hidden"]; ok && hidden == "true" { + coll.Hidden = true + } + if disablePublishing, ok := sch.Metadata["collection_no_publish"]; ok && disablePublishing == "true" { + coll.NoPublish = true + } + if noArchive, ok := sch.Metadata["collection_no_archive"]; ok && noArchive == "true" { + coll.NoArchive = true + } + + if noRevisions, ok := sch.Metadata["collection_no_revisions"]; ok && noRevisions == "true" { + coll.NoRevisions = true + } + if mr, ok := sch.Metadata["collection_max_revisions"]; ok { + if maxRevisions, err := strconv.ParseUint(mr, 10, 32); err == nil { + coll.MaxRevisions = uint32(maxRevisions) + } + } + if ttl, ok := sch.Metadata["collection_revisions_ttl"]; ok { + if revisionTTL, err := time.ParseDuration(ttl); err == nil { + coll.RevisionTTL = revisionTTL + } + } + + if _, ok := sch.Metadata["collection_view_id"]; ok { + coll.View = &View{ + SpaceID: sch.Metadata["collection_view_space"], + EnvID: sch.Metadata["collection_view_env"], + CollectionID: sch.Metadata["collection_view_id"], + Filter: sch.Metadata["collection_view_filter"], + } + } + + return coll +} diff --git a/pkg/collections/marshal_test.go b/pkg/collections/marshal_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2cc1bf52499422160d189a1e454144de39da4c95 --- /dev/null +++ b/pkg/collections/marshal_test.go @@ -0,0 +1,130 @@ +package collections + +import ( + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/optional" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + jsoniter "github.com/json-iterator/go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCollection_UnmarshalJSON(t *testing.T) { + sch := schema.New("a", field.String()).WithMetadata( + "collection_id", "collID", + "collection_name", "collName") + sch.ClearState() + + tests := []struct { + name string + in any + expect *Collection + wantErr bool + }{ + {name: "from schema", + in: sch, + expect: &Collection{Schema: sch, ID: "collID", Name: "collName"}, + wantErr: false}, + {name: "from collection", + in: &Collection{Schema: sch, ID: "id", Name: "name"}, + expect: &Collection{Schema: sch, ID: "id", Name: "name"}, + wantErr: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var c Collection + b, _ := jsoniter.Marshal(tt.in) + if err := jsoniter.Unmarshal(b, &c); (err != nil) != tt.wantErr { + t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + + assert.True(t, c.Equal(tt.expect)) + assert.True(t, c.Schema.Equal(tt.expect.Schema)) + }) + } +} + +func TestFromSchemaMetadata(t *testing.T) { + testCases := []struct { + name string + schema *schema.Schema + want *Collection + }{ + { + name: "Nil", + schema: nil, + want: nil, + }, + { + name: "Empty", + schema: &schema.Schema{}, + want: &Collection{Schema: &schema.Schema{}}, + }, + { + name: "Without metadata", + schema: schema.New("a", field.String()), + want: &Collection{Schema: schema.New("a", field.String())}, + }, + { + name: "With metadata", + schema: schema.New("a", field.String()).WithMetadata( + "collection_id", "collID", + "collection_name", "collName", + "collection_single", "true", + "collection_system", "true", + "collection_nodata", "true", + "collection_hidden", "true", + "collection_no_publish", "true", + "collection_no_archive", "true", + "collection_view_space", "viewSpaceID", + "collection_view_env", "viewEnvID", + "collection_view_id", "viewCollID", + "collection_view_filter", "viewFilter", + ), + want: &Collection{ + ID: "collID", + Name: "collName", + Single: optional.True, + System: optional.True, + NoData: optional.True, + Hidden: true, + NoPublish: true, + NoArchive: true, + Schema: schema.New("a", field.String()).WithMetadata("collection_id", "collID", "collection_name", "collName", "collection_single", "true", "collection_system", "true", "collection_nodata", "true", "collection_hidden", "true", "collection_no_publish", "true", "collection_no_archive", "true", "collection_view_space", "viewSpaceID", "collection_view_env", "viewEnvID", "collection_view_id", "viewCollID", "collection_view_filter", "viewFilter"), + View: &View{ + SpaceID: "viewSpaceID", + EnvID: "viewEnvID", + CollectionID: "viewCollID", + Filter: "viewFilter", + }, + }, + }, + { + name: "With metadata revisions settings", + schema: schema.New("a", field.String()).WithMetadata( + "collection_id", "collID", + "collection_name", "collName", + "collection_no_revisions", "true", + "collection_max_revisions", "10", + "collection_revisions_ttl", "1h", + ), + want: &Collection{ + ID: "collID", + Name: "collName", + NoRevisions: true, + MaxRevisions: 10, + RevisionTTL: 3600000000000, + Schema: schema.New("a", field.String()).WithMetadata("collection_id", "collID", "collection_name", "collName", "collection_no_revisions", "true", "collection_max_revisions", "10", "collection_revisions_ttl", "1h"), + }, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + result := FromSchema(tt.schema) + require.Equal(t, tt.want, result) + }) + } +} diff --git a/pkg/collections/middleware/caching_middleware.go b/pkg/collections/middleware/caching_middleware.go index de34d42af02f7259c66aea5799210c50c0e1961e..cb95d0d9a8772f91700f5f630fa9bb2631e51937 100644 --- a/pkg/collections/middleware/caching_middleware.go +++ b/pkg/collections/middleware/caching_middleware.go @@ -44,7 +44,7 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId string, envId string opts := service.MergeGetOptions(options...) value, e := m.cache.Get(makeKey(spaceId, envId, collectionId, opts.DisableSchemaIncludes)) if e == nil { - return value.(*service.Collection), err + return value.(*service.Collection).Clone(), nil } coll, err = m.next.Get(ctx, spaceId, envId, collectionId, options...) if err == nil { @@ -52,13 +52,13 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId string, envId string if err != nil { return nil, err } - m.cache.Set(makeKey(coll.SpaceID, env.ID, coll.ID, opts.DisableSchemaIncludes), coll) + _ = m.cache.Set(makeKey(coll.SpaceID, env.ID, coll.ID, opts.DisableSchemaIncludes), coll) for _, al := range env.Aliases { - m.cache.Set(makeKey(coll.SpaceID, al, coll.ID, opts.DisableSchemaIncludes), coll) + _ = m.cache.Set(makeKey(coll.SpaceID, al, coll.ID, opts.DisableSchemaIncludes), coll) } - + return coll.Clone(), nil } - return coll, err + return nil, err } func (m cachingMiddleware) List(ctx context.Context, spaceId, envId string, filter *service.Filter) (collections []*service.Collection, err error) { @@ -73,11 +73,11 @@ func (m cachingMiddleware) Update(ctx context.Context, coll *service.Collection) if err != nil { return err } - m.cache.Remove(makeKey(env.SpaceID, env.ID, coll.ID, true)) - m.cache.Remove(makeKey(env.SpaceID, env.ID, coll.ID, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, coll.ID, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, coll.ID, false)) for _, al := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, al, coll.ID, true)) - m.cache.Remove(makeKey(env.SpaceID, al, coll.ID, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, coll.ID, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, coll.ID, false)) } } return err @@ -90,11 +90,11 @@ func (m cachingMiddleware) SetSchema(ctx context.Context, spaceId, envId, collec if err != nil { return err } - m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, true)) - m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, false)) for _, al := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, al, collectionId, true)) - m.cache.Remove(makeKey(env.SpaceID, al, collectionId, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, collectionId, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, collectionId, false)) } } return err @@ -107,11 +107,11 @@ func (m cachingMiddleware) SetState(ctx context.Context, spaceId, envId, collect if err != nil { return err } - m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, true)) - m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, false)) for _, al := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, al, collectionId, true)) - m.cache.Remove(makeKey(env.SpaceID, al, collectionId, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, collectionId, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, collectionId, false)) } } return err @@ -125,11 +125,11 @@ func (m cachingMiddleware) Delete(ctx context.Context, spaceId string, envId str if err != nil { return err } - m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, true)) - m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID, collectionId, false)) for _, al := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, al, collectionId, true)) - m.cache.Remove(makeKey(env.SpaceID, al, collectionId, false)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, collectionId, true)) + _ = m.cache.Remove(makeKey(env.SpaceID, al, collectionId, false)) } } return err diff --git a/pkg/collections/middleware/caching_middleware_test.go b/pkg/collections/middleware/caching_middleware_test.go index ac284ce5464af7469fee9ad4a7babf377b9c335a..24646008ba32736ca45f7bcdc7e0a4845c43877d 100644 --- a/pkg/collections/middleware/caching_middleware_test.go +++ b/pkg/collections/middleware/caching_middleware_test.go @@ -46,11 +46,13 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша при повторном запросе по ID окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша при повторном запросе по ID окружения.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") + assert.Equal(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") + assert.NotSame(t, v3, v2) env.AssertExpectations(t) col.AssertExpectations(t) @@ -70,11 +72,13 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша при повторном запросе по Alias окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша при повторном запросе по Alias окружения.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") + assert.Equal(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") + assert.NotSame(t, v3, v2) env.AssertExpectations(t) col.AssertExpectations(t) @@ -115,12 +119,12 @@ func TestCollections_Cache(t *testing.T) { // vl2, err := svc.List(ctx, spaceID, envID, nil) // require.NoError(t, err) // assert.Len(t, vl2, 1) - // assert.Same(t, vl1[0], vl2[0], "При повторном запросе по ID окружения, ожидается получение списка объектов из кеша.") + // assert.Equal(t, vl1[0], vl2[0], "При повторном запросе по ID окружения, ожидается получение списка объектов из кеша.") // // vl3, err := svc.List(ctx, spaceID, envAlias, nil) // require.NoError(t, err) // assert.Len(t, vl3, 1) - // assert.Same(t, vl3[0], vl2[0], "При повторном запросе по Alias окружения, ожидается получение списка объектов из кеша.") + // assert.Equal(t, vl3[0], vl2[0], "При повторном запросе по Alias окружения, ожидается получение списка объектов из кеша.") // // env.AssertExpectations(t) // col.AssertExpectations(t) @@ -161,11 +165,13 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по ID окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по ID окружения.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) @@ -181,15 +187,16 @@ func TestCollections_Cache(t *testing.T) { v4, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.NotSame(t, v3, v4, "Ожидает что элемент после обновления был удален из кэша и будет запрошен заново из сервиса.") + assert.NotEqual(t, v3, v4, "Ожидает что элемент после обновления был удален из кэша и будет запрошен заново из сервиса.") v5, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v4, v5, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v4, v5, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v4, v5) vl2, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) - assert.NotSame(t, vl1[0], vl2[0], "Ожидает что после обновления элементы будут запрошены заново из сервиса.") + assert.NotEqual(t, vl1[0], vl2[0], "Ожидает что после обновления элементы будут запрошены заново из сервиса.") env.AssertExpectations(t) col.AssertExpectations(t) @@ -212,11 +219,13 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по ID окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по ID окружения.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID, envAlias, nil) require.NoError(t, err) @@ -234,15 +243,16 @@ func TestCollections_Cache(t *testing.T) { v4, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.NotSame(t, v3, v4, "Ожидает что элемент после обновления был удален из кэша и будет запрошен заново из сервиса.") + assert.NotEqual(t, v3, v4, "Ожидает что элемент после обновления был удален из кэша и будет запрошен заново из сервиса.") v5, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v4, v5, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v4, v5, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v4, v5) vl4, err := svc.List(ctx, spaceID, envAlias, nil) require.NoError(t, err) - assert.NotSame(t, vl1[0], vl4[0], "Ожидает что после обновления элементы будут запрошены заново из сервиса.") + assert.NotEqual(t, vl1[0], vl4[0], "Ожидает что после обновления элементы будут запрошены заново из сервиса.") env.AssertExpectations(t) col.AssertExpectations(t) @@ -264,11 +274,13 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по ID окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по ID окружения.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) @@ -276,7 +288,7 @@ func TestCollections_Cache(t *testing.T) { vl2, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) assert.Len(t, vl2, 1) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кеша по ID окружения.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кеша по ID окружения.") vl3, err := svc.List(ctx, spaceID, envAlias, nil) require.NoError(t, err) @@ -295,15 +307,16 @@ func TestCollections_Cache(t *testing.T) { v4, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.NotSame(t, v3, v4, "Ожидает что элемент после обновления схемы был удален из кэша и будет запрошен заново из сервиса.") + assert.NotEqual(t, v3, v4, "Ожидает что элемент после обновления схемы был удален из кэша и будет запрошен заново из сервиса.") v5, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v4, v5, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v4, v5, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v4, v5) vl4, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) - assert.NotSame(t, vl4[0], vl3[0], "Ожидает что после обновления схемы элементы будут запрошены заново из сервиса.") + assert.NotEqual(t, vl4[0], vl3[0], "Ожидает что после обновления схемы элементы будут запрошены заново из сервиса.") vl5, err := svc.List(ctx, spaceID, envAlias, nil) require.NoError(t, err) @@ -329,11 +342,13 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по ID окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по ID окружения.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias, colID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по Alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по Alias окружения.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) @@ -341,7 +356,7 @@ func TestCollections_Cache(t *testing.T) { vl2, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) assert.Len(t, vl2, 1) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кеша по ID окружения.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кеша по ID окружения.") vl3, err := svc.List(ctx, spaceID, envAlias, nil) require.NoError(t, err) @@ -391,7 +406,7 @@ func TestCollections_Cache(t *testing.T) { vl2, err := svc.List(ctx, spaceID, envID, nil) require.NoError(t, err) assert.Len(t, vl2, 1) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кеша по ID окружения.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кеша по ID окружения.") vl3, err := svc.List(ctx, spaceID, envAlias, nil) require.NoError(t, err) @@ -440,7 +455,8 @@ func TestCollections_Cache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) @@ -449,6 +465,8 @@ func TestCollections_Cache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID, colID) require.NoError(t, err) assert.NotSame(t, v3, v2, "Ожидает что элемент был удален из кэша и будет запрошен заново из сервиса.") + assert.Equal(t, v3, v2) + assert.NotSame(t, v3, v2) env.AssertExpectations(t) col.AssertExpectations(t) diff --git a/pkg/collections/middleware/logging_middleware.go b/pkg/collections/middleware/logging_middleware.go index 3c80eda411e9905791e59042a31f2af8f300cefd..92e2811bd2f30cd45eb0b1aa66da1d52cfbb2596 100644 --- a/pkg/collections/middleware/logging_middleware.go +++ b/pkg/collections/middleware/logging_middleware.go @@ -30,7 +30,7 @@ func (m *loggingMiddleware) Create(ctx context.Context, collection *collections. spaceID = collection.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(collections.EventCreate), ) @@ -46,7 +46,7 @@ func (m *loggingMiddleware) Create(ctx context.Context, collection *collections. func (m *loggingMiddleware) Delete(ctx context.Context, spaceId string, envId string, collectionId string) (err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), logzap.Event(collections.EventDelete), logzap.Object(id.NewCollectionId(spaceId, envId, collectionId)), ) @@ -63,7 +63,7 @@ func (m *loggingMiddleware) Delete(ctx context.Context, spaceId string, envId st func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, options ...*collections.GetOptions) (collection *collections.Collection, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) collection, err = m.next.Get(ctx, spaceId, envId, collectionId, options...) @@ -77,7 +77,7 @@ func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId strin func (m *loggingMiddleware) List(ctx context.Context, spaceId string, envId string, filter *collections.Filter) (collections []*collections.Collection, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) collections, err = m.next.List(ctx, spaceId, envId, filter) @@ -91,7 +91,7 @@ func (m *loggingMiddleware) List(ctx context.Context, spaceId string, envId stri func (m *loggingMiddleware) SetSchema(ctx context.Context, spaceId string, envId string, collectionId string, schema *schema.Schema) (err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), logzap.Event(collections.EventSetSchema), logzap.Object(id.NewCollectionId(spaceId, envId, collectionId)), ) @@ -108,7 +108,7 @@ func (m *loggingMiddleware) SetSchema(ctx context.Context, spaceId string, envId func (m *loggingMiddleware) SetState(ctx context.Context, spaceId string, envId string, collectionId string, state *collections.StateInfo) (err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) err = m.next.SetState(ctx, spaceId, envId, collectionId, state) @@ -127,7 +127,7 @@ func (m *loggingMiddleware) Update(ctx context.Context, coll *collections.Collec spaceID = coll.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(collections.EventUpdate), logzap.Object(coll), ) diff --git a/pkg/collections/observer.go b/pkg/collections/observer.go index 8d4a6b7d14ec687c97eec6b0406fcc32d515aca2..8df5c084312d9099e200997ed27a9cde921cbb72 100644 --- a/pkg/collections/observer.go +++ b/pkg/collections/observer.go @@ -14,8 +14,14 @@ type CollectionUpdatedObserver interface { OnCollectionUpdated(ctx context.Context, before, after *Collection) (delayedTaskID string, err error) } +// CollectionPreSetSchemaObserver интерфейс наблюдателя вызываемый перед изменением схемы коллекции. +// Инициировать оповещение наблюдателя может вызов методов `Collection.SetSchema` +type CollectionPreSetSchemaObserver interface { + OnCollectionPreSetSchema(ctx context.Context, before, coll *Collection) (delayedTaskID string, err error) +} + // CollectionSetSchemaObserver интерфейс наблюдателя вызываемый при изменении схемы коллекции. -// Инициировать оповещение наблюдателя может вызов методов `Collection.Schema` +// Инициировать оповещение наблюдателя может вызов методов `Collection.SetSchema` type CollectionSetSchemaObserver interface { OnCollectionSetSchema(ctx context.Context, before, coll *Collection) (delayedTaskID string, err error) } diff --git a/pkg/collections/transport/client.microgen.go b/pkg/collections/transport/client.go similarity index 71% rename from pkg/collections/transport/client.microgen.go rename to pkg/collections/transport/client.go index 7fd5b53f360a927e48c00edcd3f4dc7606dd47fe..2a430e6c8893236c73c7979654c282cb6094b807 100644 --- a/pkg/collections/transport/client.microgen.go +++ b/pkg/collections/transport/client.go @@ -4,21 +4,15 @@ package transport import ( "context" - "errors" collections "git.perx.ru/perxis/perxis-go/pkg/collections" schema "git.perx.ru/perxis/perxis-go/pkg/schema" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *collections.Collection) (res0 *collections.Collection, res1 error) { request := CreateRequest{Collection: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 @@ -33,9 +27,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string, arg3 } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Collection, res1 @@ -49,9 +40,6 @@ func (set EndpointsSet) List(arg0 context.Context, arg1 string, arg2 string, arg } response, res1 := set.ListEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListResponse).Collections, res1 @@ -61,9 +49,6 @@ func (set EndpointsSet) Update(arg0 context.Context, arg1 *collections.Collectio request := UpdateRequest{Coll: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -78,9 +63,6 @@ func (set EndpointsSet) SetSchema(arg0 context.Context, arg1 string, arg2 string } _, res0 = set.SetSchemaEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -98,9 +80,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string, arg2 string, a } _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/collections/transport/grpc/client.go b/pkg/collections/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..8051b9b97cecf06a603d60925145bb55a7162a9d --- /dev/null +++ b/pkg/collections/transport/grpc/client.go @@ -0,0 +1,22 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/collections/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + ListEndpoint: grpcerr.ClientMiddleware(c.ListEndpoint), + SetSchemaEndpoint: grpcerr.ClientMiddleware(c.SetSchemaEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + } +} diff --git a/pkg/collections/transport/grpc/protobuf_type_converters.microgen.go b/pkg/collections/transport/grpc/protobuf_type_converters.microgen.go index 0072506b7658a5591b09f914780706fcef88d034..b946a8969f863172f851a3eed83a1d1478ace45f 100644 --- a/pkg/collections/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/collections/transport/grpc/protobuf_type_converters.microgen.go @@ -13,6 +13,7 @@ import ( pb "git.perx.ru/perxis/perxis-go/proto/collections" commonpb "git.perx.ru/perxis/perxis-go/proto/common" jsoniter "github.com/json-iterator/go" + "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -61,16 +62,21 @@ func PtrCollectionToProto(coll *service.Collection) (*pb.Collection, error) { } } protoCollection := &pb.Collection{ - Id: coll.ID, - SpaceId: coll.SpaceID, - EnvId: coll.EnvID, - Name: coll.Name, - Single: coll.Single, - System: coll.System, - NoData: coll.NoData, - Access: access, - Hidden: coll.Hidden, - Tags: coll.Tags, + Id: coll.ID, + SpaceId: coll.SpaceID, + EnvId: coll.EnvID, + Name: coll.Name, + Single: coll.Single, + System: coll.System, + NoData: coll.NoData, + Access: access, + Hidden: coll.Hidden, + Tags: coll.Tags, + NoPublish: coll.NoPublish, + NoArchive: coll.NoArchive, + NoRevisions: coll.NoRevisions, + MaxRevisions: coll.MaxRevisions, + RevisionTtl: durationpb.New(coll.RevisionTTL), } if coll.StateInfo != nil { @@ -125,16 +131,21 @@ func ProtoToPtrCollection(protoCollection *pb.Collection) (*service.Collection, } } collection := &service.Collection{ - ID: protoCollection.Id, - SpaceID: protoCollection.SpaceId, - EnvID: protoCollection.EnvId, - Name: protoCollection.Name, - Single: protoCollection.Single, - System: protoCollection.System, - NoData: protoCollection.NoData, - Access: access, - Hidden: protoCollection.Hidden, - Tags: protoCollection.Tags, + ID: protoCollection.Id, + SpaceID: protoCollection.SpaceId, + EnvID: protoCollection.EnvId, + Name: protoCollection.Name, + Single: protoCollection.Single, + System: protoCollection.System, + NoData: protoCollection.NoData, + Access: access, + Hidden: protoCollection.Hidden, + Tags: protoCollection.Tags, + NoPublish: protoCollection.NoPublish, + NoArchive: protoCollection.NoArchive, + NoRevisions: protoCollection.NoRevisions, + MaxRevisions: protoCollection.MaxRevisions, + RevisionTTL: protoCollection.RevisionTtl.AsDuration(), } if protoCollection.StateInfo != nil { diff --git a/pkg/collections/transport/grpc/server.go b/pkg/collections/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..6482f1c416d7b0792b9ca2244a144de0bea627c1 --- /dev/null +++ b/pkg/collections/transport/grpc/server.go @@ -0,0 +1,22 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/collections" + "git.perx.ru/perxis/perxis-go/pkg/collections/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + pb "git.perx.ru/perxis/perxis-go/proto/collections" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc collections.Collections, opts ...grpckit.ServerOption) pb.CollectionsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + ListEndpoint: grpcerr.ServerMiddleware(eps.ListEndpoint), + SetSchemaEndpoint: grpcerr.ServerMiddleware(eps.SetSchemaEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/content/client.go b/pkg/content/client.go index bbdd62bb9474afd54ce63606055c244311478adc..adc5f784dff8fccd5b505867bf65efb373a9149d 100644 --- a/pkg/content/client.go +++ b/pkg/content/client.go @@ -47,14 +47,14 @@ func NewClient(conn *grpc.ClientConn, opts ...Option) *Content { } client.Spaces = spacesTransportGrpc.NewClient(conn, config.ClientOptions...) - client.Environments = environmentsTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) - client.Collections = collectionsTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) + client.Environments = environmentsTransportGrpc.NewClient(conn, config.ClientOptions...) + client.Collections = collectionsTransportGrpc.NewClient(conn, config.ClientOptions...) client.Items = itemsTransportGrpc.NewClient(conn, config.ClientOptions...) - client.Invitations = invitationsTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) - client.Collaborators = collaboratorsTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) - client.Clients = clientsTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) - client.Locales = localsTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) - client.Roles = rolesTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) + client.Invitations = invitationsTransportGrpc.NewClient(conn, config.ClientOptions...) + client.Collaborators = collaboratorsTransportGrpc.NewClient(conn, config.ClientOptions...) + client.Clients = clientsTransportGrpc.NewClient(conn, config.ClientOptions...) + client.Locales = localsTransportGrpc.NewClient(conn, config.ClientOptions...) + client.Roles = rolesTransportGrpc.NewClient(conn, config.ClientOptions...) client.References = referencesTransportGrpc.NewGRPCClient(conn, "", config.ClientOptions...) if !config.NoDecode { diff --git a/pkg/account/versions/transport/client.microgen.go b/pkg/content/versions/transport/client.go similarity index 62% rename from pkg/account/versions/transport/client.microgen.go rename to pkg/content/versions/transport/client.go index ec9a69655fab437a4146b6cc61973197f415ff2c..0713d94abcaca463a18d5e129314c0b8769a3ba4 100644 --- a/pkg/account/versions/transport/client.microgen.go +++ b/pkg/content/versions/transport/client.go @@ -4,20 +4,14 @@ package transport import ( "context" - "errors" version "git.perx.ru/perxis/perxis-go/pkg/version" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Get(arg0 context.Context) (res0 *version.Version, res1 error) { request := GetRequest{} response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Version, res1 diff --git a/pkg/content/versions/transport/grpc/client.go b/pkg/content/versions/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..ffa435b90b00b707f097021f39fcea705e647ed6 --- /dev/null +++ b/pkg/content/versions/transport/grpc/client.go @@ -0,0 +1,17 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/content/versions/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + } +} diff --git a/pkg/content/versions/transport/grpc/server.go b/pkg/content/versions/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..26b30d26150d8e8cb7cc4544f3d59f351ec4b56a --- /dev/null +++ b/pkg/content/versions/transport/grpc/server.go @@ -0,0 +1,17 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/content/versions/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + versions "git.perx.ru/perxis/perxis-go/pkg/version" + pb "git.perx.ru/perxis/perxis-go/proto/versions/content" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc versions.Versions, opts ...grpckit.ServerOption) pb.VersionsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/data/data.go b/pkg/data/data.go index 0540055ad4e213f666b0cf72019b9b4b9c39fbe8..14528479855b9993e6cdce218ac087b41f334c58 100644 --- a/pkg/data/data.go +++ b/pkg/data/data.go @@ -120,7 +120,7 @@ func DeleteMany(paths []string, value any, delim ...string) { return } for _, path := range paths { - Delete(path, value, delim...) + _ = Delete(path, value, delim...) } } @@ -245,7 +245,6 @@ func get(path []string, data any) (any, bool) { // The path is the sting with delim, for eg:, parent.child.key func Keep(paths []string, data any, delim ...string) { if len(paths) == 0 { - data = nil return } switch val := data.(type) { diff --git a/pkg/data/data_test.go b/pkg/data/data_test.go index 785eefbb868a68c9d8c6b2f75b8f861ab2041e11..463a4cbc01ad7cfd5c249a026a89f733f3c54e60 100644 --- a/pkg/data/data_test.go +++ b/pkg/data/data_test.go @@ -63,22 +63,23 @@ func TestDelete(t *testing.T) { }, "z": "2"}, }, // Решили что автоматически удалять пустые объекты/слайсы не нужно - //{ + // { // "empty object", // map[string]interface{}{"a": map[string]interface{}{"a": map[string]interface{}{}}}, // []string{"a", "a"}, // map[string]interface{}{}, - //}, { + // }, { // "empty array", // map[string]interface{}{"a": map[string]interface{}{"a": []interface{}{}}}, // []string{"a", "a"}, // map[string]interface{}{}, - //}, + // }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - Delete(tt.field, tt.in) + err := Delete(tt.field, tt.in) + assert.NoError(t, err) assert.Equal(t, tt.out, tt.in) }) } diff --git a/pkg/data/list.go b/pkg/data/list.go index e15a20cadcc2a22bc9c4797b8fa16413a511b5ab..4481a18861c3524c8636b4f9fbfbdf14efb6f711 100644 --- a/pkg/data/list.go +++ b/pkg/data/list.go @@ -184,3 +184,29 @@ func mergeMaps(a, b map[string]interface{}) map[string]interface{} { } return out } + +// CloneSlice возвращает копию среза с клонированными элементами +func CloneSlice[T interface{ Clone() T }](s []T) []T { + // Если s == nil, то возвращаем nil + if s == nil { + return nil + } + + result := make([]T, 0, len(s)) + for _, t := range s { + result = append(result, t.Clone()) + } + return result +} + +type Keyed[T comparable] interface { + Key() T +} + +func SliceToMap[K comparable, V Keyed[K]](s []V) map[K]V { + res := make(map[K]V, len(s)) + for _, elem := range s { + res[elem.Key()] = elem + } + return res +} diff --git a/pkg/data/list_test.go b/pkg/data/list_test.go index 8231aae992e91f09f50bb71fb1e028e148c35993..c77c226edc8ab885ebcae9cab023d496c175a486 100644 --- a/pkg/data/list_test.go +++ b/pkg/data/list_test.go @@ -139,3 +139,18 @@ keyB2: val20 }) } } + +type KV struct { + K string + V string +} + +func (kv *KV) Key() string { + return kv.K +} + +func TestSliceToMap(t *testing.T) { + s := []*KV{{"a", "1"}, {"b", "2"}, {"c", "3"}} + m := SliceToMap(s) + assert.Equal(t, map[string]*KV{"a": {"a", "1"}, "b": {"b", "2"}, "c": {"c", "3"}}, m) +} diff --git a/pkg/data/translit.go b/pkg/data/translit.go index 654ae90dd305be0ffd20bfcd58c782229a27156b..11679e37cf4da7e17f81d77c10077b7533ccef98 100644 --- a/pkg/data/translit.go +++ b/pkg/data/translit.go @@ -45,7 +45,7 @@ func TableEncode(s string, tlm map[rune]string) string { } if unicode.IsUpper(r) { - tr = strings.Title(tr) + tr = strings.Title(tr) //nolint:staticcheck // Для обработки основных языков достаточно правил работы функции strings.Title } out.WriteString(tr) diff --git a/pkg/delivery/service/service.go b/pkg/delivery/service/service.go index ed1b5091c553853ec78f9f20bc3b54b3e0239834..be71148108f3296ce5a66d6a6f1f347a81671999 100644 --- a/pkg/delivery/service/service.go +++ b/pkg/delivery/service/service.go @@ -34,7 +34,17 @@ type deliveryService struct { } func (s deliveryService) ListLocales(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) { - return s.Locales.List(ctx, spaceId) + res, err := s.Locales.List(ctx, spaceId) + if err != nil { + return nil, err + } + for _, l := range res { + if l.NoPublish || l.Disabled { + continue + } + locales = append(locales, l) + } + return locales, nil } func (s deliveryService) GetEnvironment(ctx context.Context, spaceId, envId string) (env *environments.Environment, err error) { diff --git a/pkg/delivery/service/service_test.go b/pkg/delivery/service/service_test.go new file mode 100644 index 0000000000000000000000000000000000000000..88bcc16f63b3e00c84c8e02cd2939600339400d4 --- /dev/null +++ b/pkg/delivery/service/service_test.go @@ -0,0 +1,57 @@ +package service + +import ( + "context" + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/locales" + "git.perx.ru/perxis/perxis-go/pkg/locales/mocks" + "github.com/stretchr/testify/assert" +) + +func Test_deliveryService_ListLocales(t *testing.T) { + tests := []struct { + name string + mockcall func(locSvs *mocks.Locales) + wantLocales []*locales.Locale + wantErr bool + }{ + { + name: "Returned locales without NoPublish and Disabled", + mockcall: func(locSvs *mocks.Locales) { + locSvs.On("List", context.Background(), "space").Return([]*locales.Locale{ + {ID: "en_EN", SpaceID: "space", Name: "english", Code: "en", NoPublish: false, Disabled: false}, + {ID: "de_DE", SpaceID: "space", Name: "deutsch", Code: "de", NoPublish: false, Disabled: false}, + {ID: "ru_RU", SpaceID: "space", Name: "russian", Code: "ru", NoPublish: false, Disabled: false}, + {ID: "by_BY", SpaceID: "space", Name: "belarus", Code: "by", NoPublish: true, Disabled: false}, + {ID: "es_ES", SpaceID: "space", Name: "spain", Code: "by", NoPublish: false, Disabled: true}}, nil) + }, + wantLocales: []*locales.Locale{ + {ID: "en_EN", SpaceID: "space", Name: "english", Code: "en", NoPublish: false, Disabled: false}, + {ID: "de_DE", SpaceID: "space", Name: "deutsch", Code: "de", NoPublish: false, Disabled: false}, + {ID: "ru_RU", SpaceID: "space", Name: "russian", Code: "ru", NoPublish: false, Disabled: false}, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + localesService := &mocks.Locales{} + if tt.mockcall != nil { + tt.mockcall(localesService) + } + s := deliveryService{ + Locales: localesService, + } + + gotLocales, err := s.ListLocales(context.Background(), "space") + if tt.wantErr { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.wantLocales, gotLocales) + localesService.AssertExpectations(t) + }) + } +} diff --git a/pkg/delivery/transport/client.microgen.go b/pkg/delivery/transport/client.go similarity index 74% rename from pkg/delivery/transport/client.microgen.go rename to pkg/delivery/transport/client.go index 8f2e1216f49441cf14afe4fe2fe509ba9898bca9..39c110029c1c78df3ccf4c01ef1073612fbba2c7 100644 --- a/pkg/delivery/transport/client.microgen.go +++ b/pkg/delivery/transport/client.go @@ -4,23 +4,17 @@ package transport import ( "context" - "errors" collections "git.perx.ru/perxis/perxis-go/pkg/collections" environments "git.perx.ru/perxis/perxis-go/pkg/environments" items "git.perx.ru/perxis/perxis-go/pkg/items" locales "git.perx.ru/perxis/perxis-go/pkg/locales" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) ListLocales(arg0 context.Context, arg1 string) (res0 []*locales.Locale, res1 error) { request := ListLocalesRequest{SpaceId: arg1} response, res1 := set.ListLocalesEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListLocalesResponse).Locales, res1 @@ -33,9 +27,6 @@ func (set EndpointsSet) GetEnvironment(arg0 context.Context, arg1 string, arg2 s } response, res1 := set.GetEnvironmentEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetEnvironmentResponse).Env, res1 @@ -45,9 +36,6 @@ func (set EndpointsSet) ListEnvironments(arg0 context.Context, arg1 string) (res request := ListEnvironmentsRequest{SpaceId: arg1} response, res1 := set.ListEnvironmentsEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListEnvironmentsResponse).Envs, res1 @@ -61,9 +49,6 @@ func (set EndpointsSet) GetCollection(arg0 context.Context, arg1 string, arg2 st } response, res1 := set.GetCollectionEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetCollectionResponse).Collection, res1 @@ -76,9 +61,6 @@ func (set EndpointsSet) ListCollections(arg0 context.Context, arg1 string, arg2 } response, res1 := set.ListCollectionsEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListCollectionsResponse).Collections, res1 @@ -94,9 +76,6 @@ func (set EndpointsSet) GetItem(arg0 context.Context, arg1 string, arg2 string, } response, res1 := set.GetItemEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetItemResponse).Item, res1 @@ -112,9 +91,6 @@ func (set EndpointsSet) FindItems(arg0 context.Context, arg1 string, arg2 string } response, res2 := set.FindItemsEndpoint(arg0, &request) if res2 != nil { - if e, ok := status.FromError(res2); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res2 = errors.New(e.Message()) - } return } return response.(*FindItemsResponse).Items, response.(*FindItemsResponse).Total, res2 @@ -130,9 +106,6 @@ func (set EndpointsSet) Aggregate(arg0 context.Context, arg1 string, arg2 string } response, res1 := set.AggregateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*AggregateResponse).Result, res1 diff --git a/pkg/delivery/transport/grpc/client.go b/pkg/delivery/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..18c8b75e6e68d0b71759c4bbfba3507c7bb78dfa --- /dev/null +++ b/pkg/delivery/transport/grpc/client.go @@ -0,0 +1,24 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/delivery/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + AggregateEndpoint: grpcerr.ClientMiddleware(c.AggregateEndpoint), + FindItemsEndpoint: grpcerr.ClientMiddleware(c.FindItemsEndpoint), + GetCollectionEndpoint: grpcerr.ClientMiddleware(c.GetCollectionEndpoint), + GetEnvironmentEndpoint: grpcerr.ClientMiddleware(c.GetEnvironmentEndpoint), + GetItemEndpoint: grpcerr.ClientMiddleware(c.GetItemEndpoint), + ListCollectionsEndpoint: grpcerr.ClientMiddleware(c.ListCollectionsEndpoint), + ListEnvironmentsEndpoint: grpcerr.ClientMiddleware(c.ListEnvironmentsEndpoint), + ListLocalesEndpoint: grpcerr.ClientMiddleware(c.ListLocalesEndpoint), + } +} diff --git a/pkg/delivery/transport/grpc/protobuf_type_converters.microgen.go b/pkg/delivery/transport/grpc/protobuf_type_converters.microgen.go index 6961c709da405a34710e76ff6c1ad6f34c218f1b..7067dc51722117ddc00dd6208de6da9bd8a8e9bd 100644 --- a/pkg/delivery/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/delivery/transport/grpc/protobuf_type_converters.microgen.go @@ -24,10 +24,10 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" ) -func ListPtrLocalesLocaleToProto(locales []*locales.Locale) ([]*localespb.Locale, error) { - protoLocales := make([]*localespb.Locale, 0, len(locales)) - for _, l := range locales { - protoLocales = append(protoLocales, &localespb.Locale{Id: l.ID, Name: l.Name, SpaceId: l.SpaceID}) +func ListPtrLocalesLocaleToProto(ls []*locales.Locale) ([]*localespb.Locale, error) { + protoLocales := make([]*localespb.Locale, 0, len(ls)) + for _, l := range ls { + protoLocales = append(protoLocales, locales.LocaleToProto(l)) } return protoLocales, nil } @@ -35,7 +35,7 @@ func ListPtrLocalesLocaleToProto(locales []*locales.Locale) ([]*localespb.Locale func ProtoToListPtrLocalesLocale(protoLocales []*localespb.Locale) ([]*locales.Locale, error) { ls := make([]*locales.Locale, 0, len(protoLocales)) for _, pl := range protoLocales { - ls = append(ls, &locales.Locale{ID: pl.Id, Name: pl.Name, SpaceID: pl.SpaceId}) + ls = append(ls, locales.LocaleFromProto(pl)) } return ls, nil } @@ -190,33 +190,11 @@ func PtrItemsItemToProto(item *items.Item) (*itemspb.Item, error) { return nil, nil } - protoItem := &itemspb.Item{ - Id: item.ID, - SpaceId: item.SpaceID, - EnvId: item.EnvID, - CollectionId: item.CollectionID, - State: itemspb.Item_State(item.State), - CreatedBy: item.CreatedBy, - UpdatedBy: item.UpdatedBy, - RevisionId: item.RevisionID, - Locale: item.Locale, - //Hidden, Template, Deleted - не передается для delivery - } - - var err error - protoItem.Data, err = MapStringInterfaceToProto(item.Data) - if err != nil { - return nil, err - } - protoItem.Translations, err = MapStringMapStringInterfaceToProto(item.Translations) - if err != nil { - return nil, err - } - //protoItem.Permissions - не передается для delivery - - protoItem.CreatedRevAt = timestamppb.New(item.CreatedRevAt) - protoItem.CreatedAt = timestamppb.New(item.CreatedAt) - protoItem.UpdatedAt = timestamppb.New(item.UpdatedAt) + protoItem := items.ItemToProto(item) + protoItem.Permissions = nil + protoItem.Hidden = false + protoItem.Template = false + protoItem.Deleted = false return protoItem, nil } @@ -226,26 +204,11 @@ func ProtoToPtrItemsItem(protoItem *itemspb.Item) (*items.Item, error) { return nil, nil } - item := &items.Item{ - ID: protoItem.Id, - SpaceID: protoItem.SpaceId, - EnvID: protoItem.EnvId, - CollectionID: protoItem.CollectionId, - State: items.State(protoItem.State), - CreatedBy: protoItem.CreatedBy, - UpdatedBy: protoItem.UpdatedBy, - RevisionID: protoItem.RevisionId, - Locale: protoItem.Locale, - //Hidden, Template, Deleted - не передается для delivery - } - - item.Data, _ = ProtoToMapStringInterface(protoItem.Data) - item.Translations, _ = ProtoToMapStringMapStringInterface(protoItem.Translations) - //item.Permissions - не передается для delivery - - item.CreatedRevAt = protoItem.CreatedRevAt.AsTime() - item.CreatedAt = protoItem.CreatedAt.AsTime() - item.UpdatedAt = protoItem.UpdatedAt.AsTime() + item := items.ItemFromProto(protoItem) + item.Permissions = nil + item.Hidden = false + item.Template = false + item.Deleted = false return item, nil } diff --git a/pkg/delivery/transport/grpc/server.go b/pkg/delivery/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..e2db4e5642d8066364bec55b99427f4cdb8107f3 --- /dev/null +++ b/pkg/delivery/transport/grpc/server.go @@ -0,0 +1,24 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/delivery" + "git.perx.ru/perxis/perxis-go/pkg/delivery/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + pb "git.perx.ru/perxis/perxis-go/proto/delivery" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc delivery.Delivery, opts ...grpckit.ServerOption) pb.DeliveryServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + AggregateEndpoint: grpcerr.ServerMiddleware(eps.AggregateEndpoint), + FindItemsEndpoint: grpcerr.ServerMiddleware(eps.FindItemsEndpoint), + GetCollectionEndpoint: grpcerr.ServerMiddleware(eps.GetCollectionEndpoint), + GetEnvironmentEndpoint: grpcerr.ServerMiddleware(eps.GetEnvironmentEndpoint), + GetItemEndpoint: grpcerr.ServerMiddleware(eps.GetItemEndpoint), + ListCollectionsEndpoint: grpcerr.ServerMiddleware(eps.ListCollectionsEndpoint), + ListEnvironmentsEndpoint: grpcerr.ServerMiddleware(eps.ListEnvironmentsEndpoint), + ListLocalesEndpoint: grpcerr.ServerMiddleware(eps.ListLocalesEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/environments/environment.go b/pkg/environments/environment.go index e9d2b96e8337ac2ad94315b671aeea42e54c47cb..3e0f7bb62a0be1d2fbef334322a6cb315060af8a 100644 --- a/pkg/environments/environment.go +++ b/pkg/environments/environment.go @@ -6,6 +6,18 @@ const ( DefaultEnvironment = "master" ) +var ( + ReadAllowedStates = []State{ + StateNew, + StateReady, + } + + WriteAllowedStates = []State{ + StateNew, + StateReady, + } +) + type State int const ( @@ -91,4 +103,4 @@ func (e Environment) Clone() *Environment { } return clone -} \ No newline at end of file +} diff --git a/pkg/environments/events.go b/pkg/environments/events.go new file mode 100644 index 0000000000000000000000000000000000000000..169b0ac05ffb28ec4cf9722ec48f002e1a44536d --- /dev/null +++ b/pkg/environments/events.go @@ -0,0 +1,8 @@ +package environments + +const ( + EventCreate = "environments.create" + EventUpdate = "environments.update" + EventDelete = "environments.delete" + EventMigrate = "environments.migrate" +) diff --git a/pkg/environments/middleware/caching_middleware.go b/pkg/environments/middleware/caching_middleware.go index 0801730a0e93947c847352a9710a02f85ae94ee0..c53f45e8bdcdb61f59f1af0acf11bc0f412c2629 100644 --- a/pkg/environments/middleware/caching_middleware.go +++ b/pkg/environments/middleware/caching_middleware.go @@ -5,6 +5,7 @@ import ( "strings" "git.perx.ru/perxis/perxis-go/pkg/cache" + "git.perx.ru/perxis/perxis-go/pkg/data" service "git.perx.ru/perxis/perxis-go/pkg/environments" ) @@ -30,7 +31,7 @@ func (m cachingMiddleware) Create(ctx context.Context, env *service.Environment) environment, err = m.next.Create(ctx, env) if err == nil { - m.cache.Remove(environment.SpaceID) + _ = m.cache.Remove(environment.SpaceID) } return environment, err } @@ -39,29 +40,31 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId string, envId string value, e := m.cache.Get(makeKey(spaceId, envId)) if e == nil { - return value.(*service.Environment), err + return value.(*service.Environment).Clone(), nil } environment, err = m.next.Get(ctx, spaceId, envId) if err == nil { - m.cache.Set(makeKey(spaceId, environment.ID), environment) + _ = m.cache.Set(makeKey(spaceId, environment.ID), environment) for _, a := range environment.Aliases { - m.cache.Set(makeKey(spaceId, a), environment) + _ = m.cache.Set(makeKey(spaceId, a), environment) } + return environment.Clone(), nil } - return environment, err + return nil, err } func (m cachingMiddleware) List(ctx context.Context, spaceId string) (environments []*service.Environment, err error) { value, e := m.cache.Get(spaceId) if e == nil { - return value.([]*service.Environment), err + return data.CloneSlice(value.([]*service.Environment)), nil } environments, err = m.next.List(ctx, spaceId) if err == nil { - m.cache.Set(spaceId, environments) + _ = m.cache.Set(spaceId, environments) + return data.CloneSlice(environments), nil } - return environments, err + return nil, err } func (m cachingMiddleware) Update(ctx context.Context, env *service.Environment) (err error) { @@ -71,12 +74,12 @@ func (m cachingMiddleware) Update(ctx context.Context, env *service.Environment) value, e := m.cache.Get(makeKey(env.SpaceID, env.ID)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } - m.cache.Remove(env.SpaceID) + _ = m.cache.Remove(env.SpaceID) } return err } @@ -88,12 +91,12 @@ func (m cachingMiddleware) Delete(ctx context.Context, spaceId string, envId str value, e := m.cache.Get(makeKey(spaceId, envId)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) } return err } @@ -105,21 +108,21 @@ func (m cachingMiddleware) SetAlias(ctx context.Context, spaceId string, envId s value, e := m.cache.Get(makeKey(spaceId, alias)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } value, e = m.cache.Get(makeKey(spaceId, envId)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) } return err } @@ -128,22 +131,22 @@ func (m cachingMiddleware) RemoveAlias(ctx context.Context, spaceId string, envI err = m.next.RemoveAlias(ctx, spaceId, envId, alias) if err == nil { - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) value, e := m.cache.Get(makeKey(spaceId, alias)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } value, e = m.cache.Get(makeKey(spaceId, envId)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } } @@ -157,11 +160,11 @@ func (m cachingMiddleware) Migrate(ctx context.Context, spaceId, envId string, o value, e := m.cache.Get(makeKey(spaceId, envId)) if e == nil { env := value.(*service.Environment) - m.cache.Remove(makeKey(env.SpaceID, env.ID)) + _ = m.cache.Remove(makeKey(env.SpaceID, env.ID)) for _, a := range env.Aliases { - m.cache.Remove(makeKey(env.SpaceID, a)) + _ = m.cache.Remove(makeKey(env.SpaceID, a)) } } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) return err } diff --git a/pkg/environments/middleware/caching_middleware_test.go b/pkg/environments/middleware/caching_middleware_test.go index 784ce35632e2bcd74993ce499f4ec1db329041d7..cbac396352657115e96d98b6715aa7e371a353a8 100644 --- a/pkg/environments/middleware/caching_middleware_test.go +++ b/pkg/environments/middleware/caching_middleware_test.go @@ -40,11 +40,13 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша при повторном запросе по ID.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша при повторном запросе по ID.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias) require.NoError(t, err) - assert.Same(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") + assert.Equal(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") + assert.NotSame(t, v3, v2) envs.AssertExpectations(t) }) @@ -61,11 +63,13 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша по alias.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша по alias.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") + assert.Equal(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") + assert.NotSame(t, v3, v2) envs.AssertExpectations(t) }) @@ -82,7 +86,8 @@ func TestEnvironmentsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) envs.AssertExpectations(t) }) @@ -102,14 +107,16 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) err = svc.SetAlias(ctx, spaceID, envID, envAlias) require.NoError(t, err) @@ -123,11 +130,12 @@ func TestEnvironmentsCache(t *testing.T) { v5, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v4, v5, "Ожидается получение объекта из кэша по ID.") + assert.Equal(t, v4, v5, "Ожидается получение объекта из кэша по ID.") + assert.NotSame(t, v4, v5) vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") envs.AssertExpectations(t) }) @@ -146,18 +154,21 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша по ID.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша по ID.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша по Alias.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша по Alias.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) err = svc.RemoveAlias(ctx, spaceID, envID, envAlias) require.NoError(t, err) @@ -172,11 +183,11 @@ func TestEnvironmentsCache(t *testing.T) { v4, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.NotSame(t, v3, v4, "Ожидает что элемент был удален из кеша и получен из сервиса по ID.") + assert.NotEqual(t, v3, v4, "Ожидает что элемент был удален из кеша и получен из сервиса по ID.") vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") envs.AssertExpectations(t) }) @@ -195,18 +206,21 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша по Alias.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша по Alias.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) err = svc.Update(ctx, &environments.Environment{ID: envID, SpaceID: spaceID, Description: "EnvironmentUPD", Aliases: []string{envAlias}}) require.NoError(t, err) @@ -219,15 +233,16 @@ func TestEnvironmentsCache(t *testing.T) { v4, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.NotSame(t, v2, v4, "Ожидает что элемент был удален из кэша и будет запрошен заново из сервиса.") + assert.NotEqual(t, v2, v4, "Ожидает что элемент был удален из кэша и будет запрошен заново из сервиса.") v5, err := svc.Get(ctx, spaceID, envAlias) require.NoError(t, err) - assert.Same(t, v4, v5, "Ожидается получение объекта из кэша по Alias после обновления объекта и получения по ID.") + assert.Equal(t, v4, v5, "Ожидается получение объекта из кэша по Alias после обновления объекта и получения по ID.") + assert.NotSame(t, v4, v5) vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") envs.AssertExpectations(t) }) @@ -245,7 +260,8 @@ func TestEnvironmentsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) err = svc.Update(ctx, &environments.Environment{ID: envID, SpaceID: spaceID, Description: "EnvironmentUPD", Aliases: []string{envAlias}}) require.NoError(t, err) @@ -254,7 +270,7 @@ func TestEnvironmentsCache(t *testing.T) { vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидает что объекты будут удалены из кэша и запрошены из сервиса.") envs.AssertExpectations(t) }) @@ -273,18 +289,21 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, spaceID, envAlias) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша по Alias.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша по Alias.") + assert.NotSame(t, v2, v3) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) err = svc.Delete(ctx, spaceID, envID) require.NoError(t, err) @@ -320,7 +339,8 @@ func TestEnvironmentsCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) envs.On("Create", mock.Anything, mock.Anything).Return(&environments.Environment{ID: "envID2", SpaceID: spaceID, Description: "Environment2"}, nil).Once() _, err = svc.Create(ctx, &environments.Environment{ID: "envID2", SpaceID: spaceID, Description: "Environment2"}) @@ -349,15 +369,16 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, "envID2") require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") - + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) _, err = svc.Get(ctx, spaceID, envID) require.NoError(t, err) v5, err := svc.Get(ctx, spaceID, "envID2") require.NoError(t, err) assert.NotSame(t, v2, v5, "Ожидает что объект был удален из кэша и будет запрошен заново из сервиса.") - + assert.Equal(t, v2, v5) + assert.NotSame(t, v2, v5) envs.AssertExpectations(t) }) @@ -372,7 +393,8 @@ func TestEnvironmentsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) @@ -380,6 +402,8 @@ func TestEnvironmentsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидает что объект был удален из кэша и будет запрошен заново из сервиса.") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) envs.AssertExpectations(t) }) diff --git a/pkg/environments/middleware/logging_middleware.go b/pkg/environments/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..2cb0112956df53f7d89c489427997e35ddad2c96 --- /dev/null +++ b/pkg/environments/middleware/logging_middleware.go @@ -0,0 +1,159 @@ +package middleware + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/environments" + + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next environments.Environments +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next environments.Environments) environments.Environments { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Environments")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, env *environments.Environment) (created *environments.Environment, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(environments.EventCreate), + ) + + created, err = m.next.Create(ctx, env) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(env)) + return + } + + logger.Info("Environment created", logzap.Channels(logzap.Userlog), logzap.Object(created)) + + return created, err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, spaceId string, envId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(environments.EventDelete), + logzap.Object(id.NewEnvironmentId(spaceId, envId)), + ) + + err = m.next.Delete(ctx, spaceId, envId) + if err != nil { + logger.Error("Failed to delete", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Environment deleted", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId string) (env *environments.Environment, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewEnvironmentId(spaceId, envId)), + ) + + env, err = m.next.Get(ctx, spaceId, envId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return env, err +} + +func (m *loggingMiddleware) List(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + envs, err = m.next.List(ctx, spaceId) + if err != nil { + logger.Error("Failed to list", zap.Error(err)) + return + } + + return envs, err +} + +func (m *loggingMiddleware) Migrate(ctx context.Context, spaceId string, envId string, options ...*environments.MigrateOptions) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(environments.EventMigrate), + logzap.Object(id.NewEnvironmentId(spaceId, envId)), + ) + + err = m.next.Migrate(ctx, spaceId, envId, options...) + if err != nil { + logger.Error("Failed to migrate", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + // Информация о миграции будет отправлена в сервис логирования внутри самого сервиса. + + return err +} + +func (m *loggingMiddleware) RemoveAlias(ctx context.Context, spaceId string, envId string, alias string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(environments.EventUpdate), + logzap.Object(id.NewEnvironmentId(spaceId, envId)), + ) + + err = m.next.RemoveAlias(ctx, spaceId, envId, alias) + if err != nil { + logger.Error(fmt.Sprintf("Failed to remove alias '%s'", alias), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("Environment alias '%s' removed", alias), logzap.Channels(logzap.Userlog)) + return err +} + +func (m *loggingMiddleware) SetAlias(ctx context.Context, spaceId string, envId string, alias string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(environments.EventUpdate), + logzap.Object(id.NewEnvironmentId(spaceId, envId)), + ) + + err = m.next.SetAlias(ctx, spaceId, envId, alias) + if err != nil { + logger.Error(fmt.Sprintf("Failed to set alias '%s'", alias), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("Environment alias '%s' set", alias), logzap.Channels(logzap.Userlog)) + return err +} + +func (m *loggingMiddleware) Update(ctx context.Context, env *environments.Environment) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(environments.EventUpdate), + logzap.Object(env), + ) + + err = m.next.Update(ctx, env) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Environment updated", logzap.Channels(logzap.Userlog)) + return err +} diff --git a/pkg/environments/middleware/middleware.go b/pkg/environments/middleware/middleware.go index 7c887417848d7cdea79681b73d7c1954318ad009..d8e2816928241555275aa14a87f03d35ae99bcf7 100644 --- a/pkg/environments/middleware/middleware.go +++ b/pkg/environments/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s environments.Environments, logger *zap.Logger, log_access bool) e if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/environments/service.go b/pkg/environments/service.go index cd0a37f449819a4b92239f8d8b38a3a0036ec8d8..920fc043704f9d7dcf51d83032d98292be758550 100644 --- a/pkg/environments/service.go +++ b/pkg/environments/service.go @@ -2,6 +2,11 @@ package environments import ( "context" + "slices" + "time" + + "git.perx.ru/perxis/perxis-go/pkg/errors" + "github.com/avast/retry-go/v4" ) // Environments @@ -18,3 +23,51 @@ type Environments interface { RemoveAlias(ctx context.Context, spaceId, envId, alias string) (err error) Migrate(ctx context.Context, spaceId, envId string, options ...*MigrateOptions) (err error) } + +const ( + RetryDelay = 1 * time.Second + RetryAttempts uint = 1200 +) + +// IsAvailable проверяет доступность окружения. +// Если окружение недоступно, возвращает ошибку ErrEnvironmentUnavailable +func IsAvailable(ctx context.Context, svc Environments, spaceID string, environmentID string) error { + env, err := svc.Get(ctx, spaceID, environmentID) + if err != nil { + return err + } + if env.StateInfo == nil || slices.Contains(WriteAllowedStates, env.StateInfo.State) { + return nil + } + return errors.WithContext(ErrEnvironmentUnavailable, "state", env.StateInfo.State) +} + +// WaitForAvailable периодически проверяет состояние окружения, пока оно не станет доступным. +// Если окружение становится доступным, функция возвращает nil. +// Если достигнуто максимальное количество попыток, функция возвращает ошибку. +// +// Через необязательные параметры можно, например, настроить задержку между попытками (по умолчанию равную RetryDelay) и максимальное количество попыток (по умолчанию равное RetryAttempts), +// но опции retry.Context и retry.RetryIf будут проигнорированы. +func WaitForAvailable(ctx context.Context, svc Environments, spaceID string, environmentID string, opts ...retry.Option) error { + opts = slices.Concat( + []retry.Option{ + retry.DelayType(retry.FixedDelay), + retry.Delay(RetryDelay), + retry.Attempts(RetryAttempts), + }, + opts, + // Чтобы предотвратить изменение параметров пользователем, размещаем их в конце списка. + []retry.Option{ + retry.Context(ctx), + retry.RetryIf(func(err error) bool { + return errors.Is(err, ErrEnvironmentUnavailable) + }), + }, + ) + return retry.Do( + func() error { + return IsAvailable(ctx, svc, spaceID, environmentID) + }, + opts..., + ) +} diff --git a/pkg/environments/service_test.go b/pkg/environments/service_test.go new file mode 100644 index 0000000000000000000000000000000000000000..9a3e6b06ec81e3ab8e84cefdfb20aec22c7213af --- /dev/null +++ b/pkg/environments/service_test.go @@ -0,0 +1,111 @@ +package environments + +import ( + "context" + "testing" + "time" + + "github.com/avast/retry-go/v4" + "github.com/stretchr/testify/assert" +) + +type dummyEnvironments struct { + Environments + environment *Environment + sleep time.Duration +} + +func (t *dummyEnvironments) Get(ctx context.Context, _ string, _ string) (*Environment, error) { + if t.sleep != 0 { + time.Sleep(t.sleep) + if err := ctx.Err(); err != nil { + return nil, err + } + } + return t.environment, nil +} + +func TestIsAvailable(t *testing.T) { + tests := []struct { + name string + environment *Environment + wantErr bool + }{ + { + "Environment has nil StateInfo: available", + &Environment{ID: "env-id", SpaceID: "space-id"}, + false, + }, + { + "Environment state is StateReady: available", + &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StateReady}}, + false, + }, + { + "Environment state is StatePreparing: not available", + &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StatePreparing}}, + true, + }, + { + "Environment state is StateError: not available", + &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StateError}}, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + environments := &dummyEnvironments{environment: tt.environment} + if err := IsAvailable(context.Background(), environments, "space-id", "master"); (err != nil) != tt.wantErr { + t.Errorf("IsAvailable() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestWaitForAvailable(t *testing.T) { + t.Run("Success", func(t *testing.T) { + env := &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StatePreparing}} + environments := &dummyEnvironments{environment: env} + + // Имитируем завершение подготовки окружения через 1 секунду + go func() { + time.Sleep(1 * time.Second) + env.StateInfo = &StateInfo{State: StateReady} + }() + + err := WaitForAvailable(context.Background(), environments, "space-id", "master") + assert.NoError(t, err) + }) + t.Run("Overwritten retry options", func(t *testing.T) { + env := &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StatePreparing}} + environments := &dummyEnvironments{environment: env} + + err := WaitForAvailable(context.Background(), environments, "space-id", "master", retry.Attempts(1)) + assert.Error(t, err, "За одну попытку окружение не стало доступным, получаем ошибку") + }) + t.Run("External context was canceled", func(t *testing.T) { + env := &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StatePreparing}} + environments := &dummyEnvironments{environment: env} + + ctx, cancel := context.WithCancel(context.Background()) + + // Отменяем контекст через 1 секунду + go func() { + time.Sleep(1 * time.Second) + cancel() + }() + + err := WaitForAvailable(ctx, environments, "space-id", "master") + assert.ErrorIs(t, err, context.Canceled) + }) + t.Run("External context was deadline exceeded", func(t *testing.T) { + env := &Environment{ID: "env-id", SpaceID: "space-id", StateInfo: &StateInfo{State: StatePreparing}} + environments := &dummyEnvironments{environment: env} + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + err := WaitForAvailable(ctx, environments, "space-id", "master") + assert.ErrorIs(t, err, context.DeadlineExceeded) + }) +} diff --git a/pkg/environments/transport/client.microgen.go b/pkg/environments/transport/client.go similarity index 66% rename from pkg/environments/transport/client.microgen.go rename to pkg/environments/transport/client.go index 96094fda943e407d0264a8abc738fd5c3afe440e..d562acc24da13a6e0de05bedf6d78e419bdc2386 100644 --- a/pkg/environments/transport/client.microgen.go +++ b/pkg/environments/transport/client.go @@ -4,20 +4,14 @@ package transport import ( "context" - "errors" environments "git.perx.ru/perxis/perxis-go/pkg/environments" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *environments.Environment) (res0 *environments.Environment, res1 error) { request := CreateRequest{Env: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 @@ -30,9 +24,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string) (res } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Env, res1 @@ -42,9 +33,6 @@ func (set EndpointsSet) List(arg0 context.Context, arg1 string) (res0 []*environ request := ListRequest{SpaceId: arg1} response, res1 := set.ListEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListResponse).Envs, res1 @@ -54,9 +42,6 @@ func (set EndpointsSet) Update(arg0 context.Context, arg1 *environments.Environm request := UpdateRequest{Env: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -69,9 +54,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string, arg2 string) ( } _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -85,9 +67,6 @@ func (set EndpointsSet) SetAlias(arg0 context.Context, arg1 string, arg2 string, } _, res0 = set.SetAliasEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -101,9 +80,6 @@ func (set EndpointsSet) RemoveAlias(arg0 context.Context, arg1 string, arg2 stri } _, res0 = set.RemoveAliasEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -117,9 +93,6 @@ func (set EndpointsSet) Migrate(arg0 context.Context, arg1 string, arg2 string, } _, res0 = set.MigrateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/environments/transport/grpc/client.go b/pkg/environments/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..c882782b3cb880317bc4a2e043f96c517136f3c3 --- /dev/null +++ b/pkg/environments/transport/grpc/client.go @@ -0,0 +1,24 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + transport "git.perx.ru/perxis/perxis-go/pkg/environments/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + ListEndpoint: grpcerr.ClientMiddleware(c.ListEndpoint), + MigrateEndpoint: grpcerr.ClientMiddleware(c.MigrateEndpoint), + RemoveAliasEndpoint: grpcerr.ClientMiddleware(c.RemoveAliasEndpoint), + SetAliasEndpoint: grpcerr.ClientMiddleware(c.SetAliasEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + } +} diff --git a/pkg/environments/transport/grpc/server.go b/pkg/environments/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..ed25b89f33790c7fedff28aed7868d2a6172af88 --- /dev/null +++ b/pkg/environments/transport/grpc/server.go @@ -0,0 +1,24 @@ +package transportgrpc + +import ( + "git.perx.ru/perxis/perxis-go/pkg/environments" + "git.perx.ru/perxis/perxis-go/pkg/environments/transport" + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + pb "git.perx.ru/perxis/perxis-go/proto/environments" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc environments.Environments, opts ...grpckit.ServerOption) pb.EnvironmentsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + ListEndpoint: grpcerr.ServerMiddleware(eps.ListEndpoint), + MigrateEndpoint: grpcerr.ServerMiddleware(eps.MigrateEndpoint), + RemoveAliasEndpoint: grpcerr.ServerMiddleware(eps.RemoveAliasEndpoint), + SetAliasEndpoint: grpcerr.ServerMiddleware(eps.SetAliasEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/errors/code.go b/pkg/errors/code.go index fdb94194b49508cc0f1e3610c41fc93d2c271bdf..08a87d477f66b2309ea58ad3a880a4f6e66dfdd5 100644 --- a/pkg/errors/code.go +++ b/pkg/errors/code.go @@ -30,7 +30,7 @@ func (e *codeError) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, e.Error()) + _, _ = io.WriteString(s, e.Error()) case 'q': fmt.Fprintf(s, "%q", e.Error()) } diff --git a/pkg/errors/detail.go b/pkg/errors/detail.go index a82ec3f8ad5fb7fd52f0ce0acdeeb833065e6ffa..556bf443ca81effa067748ac3f0f0e514d7e3665 100644 --- a/pkg/errors/detail.go +++ b/pkg/errors/detail.go @@ -27,7 +27,7 @@ func (w *withDetail) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/domain.go b/pkg/errors/domain.go index 35642c34e9537d236a83092855089804164a90de..20e3a25fd95ad4ff7d0b307729e4701151d6d5d3 100644 --- a/pkg/errors/domain.go +++ b/pkg/errors/domain.go @@ -31,7 +31,7 @@ func (w *withDomain) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/field.go b/pkg/errors/field.go index 891863f0471ab0215229f1eb848f8fb3822e1334..2c40756a65d4b7d3eb76fa907198e2fc9648ff83 100644 --- a/pkg/errors/field.go +++ b/pkg/errors/field.go @@ -31,7 +31,7 @@ func (w *withField) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/hint.go b/pkg/errors/hint.go index f654d4024936cdf19e65b89aaca2fef3070fb5bb..f327cd0784d3dbf40266f706cdaaa86451489b61 100644 --- a/pkg/errors/hint.go +++ b/pkg/errors/hint.go @@ -27,7 +27,7 @@ func (w *withHint) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/id.go b/pkg/errors/id.go index 9d9804882e0892c92998560b9be4ae7ec0fe1558..6483ced353452810b384bf8e76eb300700a168fd 100644 --- a/pkg/errors/id.go +++ b/pkg/errors/id.go @@ -29,7 +29,7 @@ func (w *withId) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/multi.go b/pkg/errors/multi.go index d27392c7a96ec2a8b653699052d9cbf7ee679ba8..f804cbd4420a8a8bef4ae137242dc60bb390b9b2 100644 --- a/pkg/errors/multi.go +++ b/pkg/errors/multi.go @@ -35,7 +35,7 @@ func (w *withMultiError) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/source.go b/pkg/errors/source.go index c43df751c063b7c2e419071e22812aa890074b42..dd5b6354aee8aea6a3ef47c6c47b8fd04c01c612 100644 --- a/pkg/errors/source.go +++ b/pkg/errors/source.go @@ -47,7 +47,7 @@ func (w *withSource) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/errors/status.go b/pkg/errors/status.go index 04b8261296574fb72e5750edc100d8c2e805f9ff..952995a7147df6522b7b48243b2e9c39d71b7d8e 100644 --- a/pkg/errors/status.go +++ b/pkg/errors/status.go @@ -32,7 +32,7 @@ func (w *withStatusError) Format(s fmt.State, verb rune) { } fallthrough case 's': - io.WriteString(s, w.Error()) + _, _ = io.WriteString(s, w.Error()) case 'q': fmt.Fprintf(s, "%q", w.Error()) } diff --git a/pkg/expr/context.go b/pkg/expr/context.go index 4049d96f5f62a94219b247b09a4337b474112224..ef653f65d527b737b1949ca9e63987e86b37ce3d 100644 --- a/pkg/expr/context.go +++ b/pkg/expr/context.go @@ -51,6 +51,6 @@ func WithEnvKV(ctx context.Context, kv ...interface{}) context.Context { } func GetEnv(ctx context.Context) map[string]interface{} { - ctx, c := getContext(ctx) + _, c := getContext(ctx) return c.Env } diff --git a/pkg/expr/format.go b/pkg/expr/format.go index 730388d2d1e654549f8dae00332c6958efb26a65..647d4eba1a6df77e3eacbd76fd8e48749b59c67e 100644 --- a/pkg/expr/format.go +++ b/pkg/expr/format.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "git.perx.ru/perxis/perxis-go/pkg/id" + "git.perx.ru/perxis/perxis-go/id" "github.com/gosimple/slug" ) diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go index bb4187dda74adce707798781b77d23a648db0eb1..5a503a7ee76eaa7a7d0197b955868a298b5fad73 100644 --- a/pkg/expr/mongo.go +++ b/pkg/expr/mongo.go @@ -23,6 +23,7 @@ var geoTypes = map[string]string{ type MongoExprConfig struct { Env map[string]any IdentifierRenameFn func(s string) string + Visitors []ast.Visitor Ops []expr.Option } @@ -55,6 +56,7 @@ func convertToMongo(ctx context.Context, config *MongoExprConfig, tree *parser.T env[EnvContextKey] = ctx exprConfig := GetDefaultConfig(env) + exprConfig.Visitors = config.Visitors for _, op := range config.Ops { op(exprConfig) @@ -62,13 +64,16 @@ func convertToMongo(ctx context.Context, config *MongoExprConfig, tree *parser.T env = exprConfig.Env.(map[string]interface{}) - if len(exprConfig.Visitors) >= 0 { - for _, v := range exprConfig.Visitors { - ast.Walk(&tree.Node, v) - } + c := &compiler{ + tree: tree, + env: env, + config: exprConfig, + identifierRenameFn: config.IdentifierRenameFn, + visitors: config.Visitors, + } + for _, v := range c.visitors { + ast.Walk(&tree.Node, v) } - - c := &compiler{tree: tree, env: env, config: exprConfig, identifierRenameFn: config.IdentifierRenameFn} v, ok := c.compile(tree.Node).(bson.M) if !ok || v == nil { return nil, fmt.Errorf("invalid expression") @@ -81,6 +86,7 @@ type compiler struct { tree *parser.Tree config *conf.Config identifierRenameFn func(string) string + visitors []ast.Visitor } func (c *compiler) eval(node ast.Node) interface{} { @@ -162,43 +168,43 @@ func (c *compiler) IdentifierNode(node *ast.IdentifierNode) string { func (c *compiler) IntegerNode(node *ast.IntegerNode) int { return node.Value - //t := node.Type() - //if t == nil { + // t := node.Type() + // if t == nil { // c.emitPush(node.Value) // return - //} + // } // - //switch t.Kind() { - //case reflect.Float32: + // switch t.Kind() { + // case reflect.Float32: // c.emitPush(float32(node.Value)) - //case reflect.Float64: + // case reflect.Float64: // c.emitPush(float64(node.Value)) // - //case reflect.Int: + // case reflect.Int: // c.emitPush(int(node.Value)) - //case reflect.Int8: + // case reflect.Int8: // c.emitPush(int8(node.Value)) - //case reflect.Int16: + // case reflect.Int16: // c.emitPush(int16(node.Value)) - //case reflect.Int32: + // case reflect.Int32: // c.emitPush(int32(node.Value)) - //case reflect.Int64: + // case reflect.Int64: // c.emitPush(int64(node.Value)) // - //case reflect.Uint: + // case reflect.Uint: // c.emitPush(uint(node.Value)) - //case reflect.Uint8: + // case reflect.Uint8: // c.emitPush(uint8(node.Value)) - //case reflect.Uint16: + // case reflect.Uint16: // c.emitPush(uint16(node.Value)) - //case reflect.Uint32: + // case reflect.Uint32: // c.emitPush(uint32(node.Value)) - //case reflect.Uint64: + // case reflect.Uint64: // c.emitPush(uint64(node.Value)) // - //default: + // default: // c.emitPush(node.Value) - //} + // } } func (c *compiler) FloatNode(node *ast.FloatNode) float64 { @@ -277,32 +283,32 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) interface{} { case ">=": return bson.M{c.identifier(node.Left): bson.M{"$gte": c.eval(node.Right)}} - //case "+": + // case "+": // c.compile(node.Left) // c.compile(node.Right) // c.emit(OpAdd) // - //case "-": + // case "-": // c.compile(node.Left) // c.compile(node.Right) // c.emit(OpSubtract) // - //case "*": + // case "*": // c.compile(node.Left) // c.compile(node.Right) // c.emit(OpMultiply) // - //case "/": + // case "/": // c.compile(node.Left) // c.compile(node.Right) // c.emit(OpDivide) // - //case "%": + // case "%": // c.compile(node.Left) // c.compile(node.Right) // c.emit(OpModulo) // - //case "**": + // case "**": // c.compile(node.Left) // c.compile(node.Right) // c.emit(OpExponent) @@ -454,26 +460,26 @@ func (c *compiler) CallNode(node *ast.CallNode) interface{} { return bson.M{v: bson.M{"$regex": fmt.Sprintf(".*%s$", regexp.QuoteMeta(t)), "$options": "i"}} } panic("unsupported function") - //for _, arg := range node.Arguments { + // for _, arg := range node.Arguments { // c.compile(arg) - //} - //op := OpCall - //if node.Fast { + // } + // op := OpCall + // if node.Fast { // op = OpCallFast - //} - //c.emit(op, c.makeConstant(Call{Name: node.Name, Size: len(node.Arguments)})...) + // } + // c.emit(op, c.makeConstant(Call{Name: node.Name, Size: len(node.Arguments)})...) } func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { panic("unsupported builin node") - //switch node.Name { - //case "len": + // switch node.Name { + // case "len": // c.compile(node.Arguments[0]) // c.emit(OpLen) // c.emit(OpRot) // c.emit(OpPop) // - //case "all": + // case "all": // c.compile(node.Arguments[0]) // c.emit(OpBegin) // var loopBreak int @@ -486,7 +492,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.patchJump(loopBreak) // c.emit(OpEnd) // - //case "none": + // case "none": // c.compile(node.Arguments[0]) // c.emit(OpBegin) // var loopBreak int @@ -500,7 +506,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.patchJump(loopBreak) // c.emit(OpEnd) // - //case "any": + // case "any": // c.compile(node.Arguments[0]) // c.emit(OpBegin) // var loopBreak int @@ -513,7 +519,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.patchJump(loopBreak) // c.emit(OpEnd) // - //case "one": + // case "one": // count := c.makeConstant("count") // c.compile(node.Arguments[0]) // c.emit(OpBegin) @@ -530,7 +536,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.emit(OpEqual) // c.emit(OpEnd) // - //case "filter": + // case "filter": // count := c.makeConstant("count") // c.compile(node.Arguments[0]) // c.emit(OpBegin) @@ -550,7 +556,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.emit(OpEnd) // c.emit(OpArray) // - //case "map": + // case "map": // c.compile(node.Arguments[0]) // c.emit(OpBegin) // size := c.emitLoop(func() { @@ -560,7 +566,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.emit(OpEnd) // c.emit(OpArray) // - //case "count": + // case "count": // count := c.makeConstant("count") // c.compile(node.Arguments[0]) // c.emit(OpBegin) @@ -575,12 +581,12 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.emit(OpLoad, count...) // c.emit(OpEnd) // - //default: + // default: // panic(fmt.Sprintf("unknown builtin %v", node.Name)) - //} + // } } -//func (c *compiler) emitLoop(body func()) []byte { +// func (c *compiler) emitLoop(body func()) []byte { // i := c.makeConstant("i") // size := c.makeConstant("size") // array := c.makeConstant("array") @@ -607,7 +613,7 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} { // c.emit(OpPop) // // return size -//} +// } func (c *compiler) ClosureNode(node *ast.ClosureNode) interface{} { return c.compile(node.Node) @@ -615,25 +621,25 @@ func (c *compiler) ClosureNode(node *ast.ClosureNode) interface{} { func (c *compiler) PointerNode(node *ast.PointerNode) interface{} { panic("unsupported pointer node") - //c.emit(OpLoad, c.makeConstant("array")...) - //c.emit(OpLoad, c.makeConstant("i")...) - //c.emit(OpIndex) + // c.emit(OpLoad, c.makeConstant("array")...) + // c.emit(OpLoad, c.makeConstant("i")...) + // c.emit(OpIndex) } func (c *compiler) ConditionalNode(node *ast.ConditionalNode) interface{} { panic("unsupported conditional node") - //c.compile(node.Cond) - //otherwise := c.emit(OpJumpIfFalse, c.placeholder()...) + // c.compile(node.Cond) + // otherwise := c.emit(OpJumpIfFalse, c.placeholder()...) // - //c.emit(OpPop) - //c.compile(node.Exp1) - //end := c.emit(OpJump, c.placeholder()...) + // c.emit(OpPop) + // c.compile(node.Exp1) + // end := c.emit(OpJump, c.placeholder()...) // - //c.patchJump(otherwise) - //c.emit(OpPop) - //c.compile(node.Exp2) + // c.patchJump(otherwise) + // c.emit(OpPop) + // c.compile(node.Exp2) // - //c.patchJump(end) + // c.patchJump(end) } func (c *compiler) VariableDeclaratorNode(node *ast.VariableDeclaratorNode) int { @@ -642,28 +648,28 @@ func (c *compiler) VariableDeclaratorNode(node *ast.VariableDeclaratorNode) int func (c *compiler) ArrayNode(node *ast.ArrayNode) interface{} { panic("unsupported array node") - //for _, node := range node.Nodes { + // for _, node := range node.Nodes { // c.compile(node) - //} + // } // - //c.emitPush(len(node.Nodes)) - //c.emit(OpArray) + // c.emitPush(len(node.Nodes)) + // c.emit(OpArray) } func (c *compiler) MapNode(node *ast.MapNode) interface{} { panic("unsupported map node") - //for _, pair := range node.Pairs { + // for _, pair := range node.Pairs { // c.compile(pair) - //} + // } // - //c.emitPush(len(node.Pairs)) - //c.emit(OpMap) + // c.emitPush(len(node.Pairs)) + // c.emit(OpMap) } func (c *compiler) PairNode(node *ast.PairNode) interface{} { panic("unsupported pair node") - //c.compile(node.Key) - //c.compile(node.Value) + // c.compile(node.Key) + // c.compile(node.Value) } // handleLenNode получает узел AST и возвращает запрос для mongo, @@ -731,6 +737,9 @@ func (c *compiler) handleTryNode(node *ast.CallNode) (result interface{}) { if err != nil { panic(err) } + for _, v := range c.visitors { + ast.Walk(&tree.Node, v) + } subcompiler := &compiler{tree: tree, env: c.env, config: c.config, identifierRenameFn: c.identifierRenameFn} result = subcompiler.compile(tree.Node).(bson.M) return diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go index 9a7df77d00a8c006327b5b2645818a014d86d9b7..587f25769e4a850d29d00fff3c93c09c6e647eb5 100644 --- a/pkg/expr/mongo_test.go +++ b/pkg/expr/mongo_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "git.perx.ru/perxis/perxis-go/pkg/id" + "git.perx.ru/perxis/perxis-go/id" "github.com/expr-lang/expr" "github.com/expr-lang/expr/ast" "github.com/stretchr/testify/assert" diff --git a/pkg/extension/action.go b/pkg/extension/action.go index 55827d81e6c5b2237b1f2ee188f88293ea22c08b..feb19d9a7ec4b8f93b1749bf1bfeb3f4be18cc59 100644 --- a/pkg/extension/action.go +++ b/pkg/extension/action.go @@ -18,6 +18,7 @@ type ( ActionRequest struct { Extension string `json:"extension,omitempty"` Action string `json:"action"` + LocaleID string `json:"locale_id,omitempty"` SpaceID string `json:"space_id,omitempty"` EnvID string `json:"env_id,omitempty"` CollectionID string `json:"collection_id,omitempty"` @@ -143,6 +144,7 @@ func ActionRequestToPB(req *ActionRequest) *pb.ActionRequest { return &pb.ActionRequest{ Extension: req.Extension, Action: req.Action, + LocaleId: req.LocaleID, SpaceId: req.SpaceID, EnvId: req.EnvID, CollectionId: req.CollectionID, @@ -162,6 +164,7 @@ func ActionRequestFromPB(req *pb.ActionRequest) *ActionRequest { return &ActionRequest{ Extension: req.Extension, Action: req.Action, + LocaleID: req.LocaleId, SpaceID: req.SpaceId, EnvID: req.EnvId, CollectionID: req.CollectionId, diff --git a/pkg/extension/extension.go b/pkg/extension/extension.go index ae7878d56de53f423ea86c28fa2f263cef6cbd03..15b92676be86b1782eb0ca8e5feb98bf1f8ba186 100644 --- a/pkg/extension/extension.go +++ b/pkg/extension/extension.go @@ -3,6 +3,9 @@ package extension import ( "context" + "go.uber.org/zap" + + "git.perx.ru/perxis/perxis-go" "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/errors" @@ -17,30 +20,29 @@ const ( StateInstalled = pb.State_INSTALLED StateInProgress = pb.State_IN_PROGRESS StateFail = pb.State_FAIL - - MetadataKey = "extension" + MetadataKey = "extension" ) type ( - InstallRequest = pb.InstallRequest - CheckRequest = pb.CheckRequest - UninstallRequest = pb.UninstallRequest - + InstallRequest = pb.InstallRequest + CheckRequest = pb.CheckRequest + UninstallRequest = pb.UninstallRequest ExtensionDescriptor = pb.ExtensionDescriptor State = pb.State ) var ( - ErrStart = errors.New("start failed") - ErrStop = errors.New("stop failed") - - ErrInstall = errors.New("install failed") - ErrUpdate = errors.New("update failed") - ErrCheck = errors.New("check failed") - ErrUninstall = errors.New("uninstall failed") - + ErrStart = errors.New("start failed") + ErrStop = errors.New("stop failed") + ErrInstall = errors.New("install failed") + ErrUpdate = errors.New("update failed") + ErrCheck = errors.New("check failed") + ErrUninstall = errors.New("uninstall failed") ErrNotInstalled = errors.New("not installed") ErrUnknownExtension = errors.New("unknown extension") + + ManifestAssets = perxis.NewAssets[*ExtensionDescriptor]() + ManifestFromFile = ManifestAssets.MustOneFrom ) // Runnable описывает интерфейс сервиса с запуском и остановкой. Вызывается сервером расширений @@ -75,7 +77,8 @@ func CheckInstalled(ctx context.Context, content *content.Content, spaceID, envI return status.State == StateInstalled, nil } -func isMetadataEqual(s1, s2 *schema.Schema) bool { +// isSameExtension возвращает true, если значение метаданных для ключа расширения совпадает +func isSameExtension(s1, s2 *schema.Schema) bool { if s1.Metadata == nil && s2.Metadata == nil { return true } @@ -85,13 +88,16 @@ func isMetadataEqual(s1, s2 *schema.Schema) bool { return s1.Metadata[MetadataKey] == s2.Metadata[MetadataKey] } -// UpdateCollectionStrategy В дополнение к стратегии по умолчанию делает проверку, что обновляемая -// коллекция была установлена расширением. Если в метаданных схемы отсутствует специальный ключ `MetadataKey`, -// это означает, что коллекция была создана пользователем и отношения к расширению не имеет - вернется ошибка. -func UpdateCollectionStrategy(s *setup.Setup, exist, collection *collections.Collection) (*collections.Collection, bool, bool, error) { - if !s.IsForce() && !collection.IsView() && !exist.IsView() && !isMetadataEqual(collection.Schema, exist.Schema) { - return nil, false, false, errors.WithDetailf(collections.ErrAlreadyExists, "Коллекция с идентификатором '%s' "+ - "уже существует. Удалите ее или вызовите установку расширения с флагом Force", collection.ID) +// UpdateExtensionCollections возвращает опцию для обновления коллекций расширения +func UpdateExtensionCollections() setup.CollectionOption { + return func(e *setup.Collection) { + next := e.UpdateFunc + e.UpdateFunc = func(s *setup.Setup, old, new *collections.Collection) (*collections.Collection, bool) { + if !s.IsForce() && !new.IsView() && !old.IsView() && !isSameExtension(new.Schema, old.Schema) { + s.Logger().Warn("Collection is already exists and not updated", zap.String("ID", new.ID)) + return nil, false + } + return next(s, old, new) + } } - return setup.DefaultUpdateCollectionStrategyFn(s, exist, collection) } diff --git a/pkg/extension/extension_test.go b/pkg/extension/extension_test.go index 4c552b394f7a67cc9de5bb4aa25e90d22fe6058a..1e5755e67fe17d02d6d7b7fbf239da49e402ceb0 100644 --- a/pkg/extension/extension_test.go +++ b/pkg/extension/extension_test.go @@ -3,8 +3,11 @@ package extension import ( "testing" + "go.uber.org/zap" + + "go.uber.org/zap/zaptest/observer" + "git.perx.ru/perxis/perxis-go/pkg/collections" - "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/schema/field" "git.perx.ru/perxis/perxis-go/pkg/setup" @@ -45,69 +48,80 @@ func Test_isMetadataEqual(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, isMetadataEqual(tt.s1, tt.s2), "isMetadataExtensionEqual(%v, %v)", tt.s1, tt.s2) + assert.Equalf(t, tt.want, isSameExtension(tt.s1, tt.s2), "isMetadataExtensionEqual(%v, %v)", tt.s1, tt.s2) }) } } -func TestDefaultUpdateCollectionStrategyFn(t *testing.T) { +func TestDefaultUpdate_ExtensionCollections(t *testing.T) { tests := []struct { name string exist *collections.Collection collection *collections.Collection force bool - wantErr func(err error) + update bool + wantLogs int }{ { - name: "collection belongs to extension", + name: "Same extension", exist: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, collection: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "new name", Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, - wantErr: nil, + update: true, + }, + { + name: "Other extension", + exist: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", + Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, + collection: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "new name", + Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-2")}, + update: false, + wantLogs: 1, }, { - name: "collection belongs to another extension", + name: "Other extension force", exist: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, collection: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "new name", Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-2")}, - wantErr: func(err error) { - assert.ErrorIs(t, err, collections.ErrAlreadyExists) - assert.Equal(t, "Коллекция с идентификатором 'coll' уже существует. Удалите ее или "+ - "вызовите установку расширения с флагом Force", errors.GetDetail(err)) - }, + force: true, + update: true, }, { - name: "collection was created by user", + name: "User collection", exist: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("name", field.String())}, collection: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "new name", Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, - wantErr: func(err error) { - assert.ErrorIs(t, err, collections.ErrAlreadyExists) - assert.Equal(t, "Коллекция с идентификатором 'coll' уже существует. Удалите ее или "+ - "вызовите установку расширения с флагом Force", errors.GetDetail(err)) - }, + update: false, + wantLogs: 1, }, { - name: "collection was created by user with force", + name: "User collection force", exist: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", - Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, + Schema: schema.New("name", field.String())}, collection: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "new name", Schema: schema.New("name", field.String()).WithMetadata("extension", "extension-1")}, - force: true, - wantErr: nil, + force: true, + update: true, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - set := setup.NewSetup(nil, "sp", "env", nil).WithForce(tt.force) - _, _, _, err := UpdateCollectionStrategy(set, tt.exist, tt.collection) - if tt.wantErr != nil { - tt.wantErr(err) - return - } + cfg := setup.NewConfig() + cfg.Collections.Add(tt.collection, UpdateExtensionCollections()) + + core, ob := observer.New(zap.DebugLevel) + logger := zap.New(core) + set := setup.NewSetup(nil, "sp", "env", logger).WithForce(tt.force) + _, update := cfg.Collections[0].UpdateFunc(set, tt.exist, tt.collection) + + assert.Equal(t, tt.update, update) + logs := ob.TakeAll() + assert.Len(t, logs, tt.wantLogs) + }) } } diff --git a/pkg/extension/manager.go b/pkg/extension/manager.go index 9de5dc4e71c1160a7277181a64085ebf6ab86032..9d4def7ce9e6c24c8e9ac257066606e16db80afb 100644 --- a/pkg/extension/manager.go +++ b/pkg/extension/manager.go @@ -55,7 +55,7 @@ func (e *ExtensionConnector) Connect() error { return nil } - conn, err := grpc.Dial( + conn, err := grpc.NewClient( e.Descriptor.Url, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithChainUnaryInterceptor( diff --git a/pkg/extension/manager_client.go b/pkg/extension/manager_client.go index d15d0dd0dd9eb53c5183f1faacc655c01dd494a1..3adbf804204de244552d42875edf1fdf95c06350 100644 --- a/pkg/extension/manager_client.go +++ b/pkg/extension/manager_client.go @@ -16,7 +16,7 @@ type ManagerClient struct { } func NewManagerClientWithAddr(addr string) (*ManagerClient, error) { - cc, err := grpc.Dial(addr, + cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(auth.PrincipalClientInterceptor()), ) diff --git a/pkg/extension/schema.go b/pkg/extension/schema.go index 521ebad6428dbd308228090469f369367e65068d..83a0f14275f552f4ee7a2f3eefd813e47789540d 100644 --- a/pkg/extension/schema.go +++ b/pkg/extension/schema.go @@ -63,7 +63,7 @@ func NewActionsCollection(spaceID, envID string) *collections.Collection { SetDescription("Выполняется переход пользователя в пользовательском интерфейсе"). WithUI(&field.UI{Widget: "Checkbox"}), "navigation_route", field.String().SetTitle("Путь в интерфейсе (Deprecated)"), - ) + ).SetSingleLocale(true) // Includes sch.SetIncludes( @@ -124,7 +124,7 @@ func NewExtensionsCollection(spaceID, envID string) *collections.Collection { validate.EnumOpt{Name: StateInProgress.String(), Value: float64(StateInProgress)}, ), ).SetTitle("Состояние").WithUI(&field.UI{Widget: "Select"}), - ) + ).SetSingleLocale(true) // UI sch.Field.UI.ListView = &field.View{Options: map[string]interface{}{ diff --git a/pkg/extension/schema_test.go b/pkg/extension/schema_test.go index 20648678a159b6703d05687530ba8e16ded4c8f2..4b4f235ae6a43bbb7e9c39a56b45c51b530d7103 100644 --- a/pkg/extension/schema_test.go +++ b/pkg/extension/schema_test.go @@ -47,6 +47,8 @@ func TestEqualSchema(t *testing.T) { require.NoError(t, err) s2 := schema.New() err = json.Unmarshal(b, s2) + s1.ClearState() + s2.ClearState() require.NoError(t, err) require.Equal(t, s1.Field, s2.Field) } diff --git a/pkg/extension/service/extension.go b/pkg/extension/service/extension.go index 45ed0524f855f888d7baf9befb9080392185dfc1..5d57e56c86190403cfe18a8084c902497280c993 100644 --- a/pkg/extension/service/extension.go +++ b/pkg/extension/service/extension.go @@ -5,6 +5,7 @@ import ( "fmt" "git.perx.ru/perxis/perxis-go/pkg/clients" + "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/extension" "git.perx.ru/perxis/perxis-go/pkg/roles" @@ -29,7 +30,6 @@ type Extension struct { setupFunc SetupFunc Content *content.Content Logger *zap.Logger - manager extension.Manager router extension.ActionRouter withClient bool @@ -98,7 +98,7 @@ func (s *Extension) setupExtensionClient(set *setup.Setup, spaceID string) { role := *s.role role.SpaceID = spaceID - set.AddRole(&role, setup.DeleteRoleIfRemove()) + set.AddRole(&role, setup.DeleteRoleIfRemoveFlag()) if s.client == nil { s.client = &clients.Client{} @@ -130,11 +130,15 @@ func (s *Extension) setupExtensionClient(set *setup.Setup, spaceID string) { } } - set.AddClient(&client, setup.OverwriteClient(), setup.DeleteClientIfRemove()) + set.AddClient(&client, setup.OverwriteClient(), setup.DeleteClientIfRemoveFlag()) } func (s *Extension) GetSetup(spaceID, envID string) (*setup.Setup, error) { set := s.setupFunc(spaceID, envID) + set.Config.Collections.WithOptions( + func(c *collections.Collection) bool { return true }, + setup.AddMetadata(extension.MetadataKey, s.GetName()), + ) if set.HasErrors() { s.Logger.Error("Invalid setup config", zap.Errors("Errors", set.Errors())) return nil, set.Error() @@ -184,13 +188,13 @@ func (s *Extension) Action(ctx context.Context, in *extension.ActionRequest) (*e // мы так и не договорились, но проверка появилась // пусть решает каждое расширение само // - //ok, err := extension.CheckInstalled(ctx, s.Content, in.SpaceId, in.EnvId, ext) - //if err != nil { + // ok, err := extension.CheckInstalled(ctx, s.Content, in.SpaceId, in.EnvId, ext) + // if err != nil { // return nil, errors.Wrap(err, "check extension installed") - //} - //if !ok { + // } + // if !ok { // return nil, errors.New("extension not installed") - //} + // } if url, err := extension.NewActionURL(in.Action); s.router != nil && err == nil && url != nil && s.isCorrectExtension(ctx, url, in) { if h, err := s.router(ctx, url, in); err == nil && h != nil { diff --git a/pkg/extension/service/registrar.go b/pkg/extension/service/registrar.go index 8a096ef2047058e70f355ece9136069b7d94d3af..28da7d37d7e3d5fd29d3dfc51ec8af3ecc83707f 100644 --- a/pkg/extension/service/registrar.go +++ b/pkg/extension/service/registrar.go @@ -8,7 +8,6 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/extension" retry "github.com/avast/retry-go/v4" "go.uber.org/zap" - "google.golang.org/grpc" ) const RegistrationDelay = time.Minute @@ -16,12 +15,11 @@ const RegistrationDelay = time.Minute // Registrar выполняет действия по регистрации и обновления регистрации расширений в менеджере расширений. Одновременно // выполняется регистрация одного или нескольких расширений type Registrar struct { - addr string - managerConn *grpc.ClientConn - manager extension.Manager - exts []extension.Extension - logger *zap.Logger - stopFn func() error + addr string + manager extension.Manager + exts []extension.Extension + logger *zap.Logger + stopFn func() error } func NewRegistrar(addr string, man extension.Manager, exts []extension.Extension, logger *zap.Logger) *Registrar { @@ -86,7 +84,7 @@ func (reg *Registrar) Start() error { for { select { case <-time.After(registrationDelay): - reg.register(regCtx, reg.manager, extList) + _ = reg.register(regCtx, reg.manager, extList) registrationDelay = RegistrationDelay case <-regCtx.Done(): reg.logger.Debug("Stop registration process") diff --git a/pkg/files/downloader.go b/pkg/files/downloader.go index 74aa91022906f794d07c314c5104011e4763caa9..2ec9f00d5feb2adaf7cf6a0d3305268b1f4f8717 100644 --- a/pkg/files/downloader.go +++ b/pkg/files/downloader.go @@ -50,7 +50,7 @@ func NewDummyDownloader() Downloader { func (d *dummyDownloader) Download(dst io.Writer, file *File) error { // png pixel 10x10 - pixel, err := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mNkYPhfz0AEYBxVSF+FAP5FDvcfRYWgAAAAAElFTkSuQmCC") - _, err = dst.Write(pixel) + pixel, _ := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mNkYPhfz0AEYBxVSF+FAP5FDvcfRYWgAAAAAElFTkSuQmCC") + _, err := dst.Write(pixel) return err } diff --git a/pkg/files/field.go b/pkg/files/field.go index 5ce4dc4ce72506fdd62e184b95487319f95e5122..ffb315d5522da6995b7a9a81040f47f933310df1 100644 --- a/pkg/files/field.go +++ b/pkg/files/field.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io" "net/url" "reflect" @@ -21,6 +22,27 @@ type FileParameters struct { func (p FileParameters) Type() field.Type { return p.t } func (p *FileParameters) Clone(reset bool) field.Parameters { return p } +func (p FileParameters) GetField(f *field.Field, name string) *field.Field { + var fld *field.Field + switch name { + case "id", "name", "mimeType", "url", "key": + fld = field.String() + case "size": + fld = field.Number(field.NumberFormatInt) + } + return f.SetFieldState(name, fld) +} + +func (p FileParameters) ListFields(f *field.Field, filter ...field.FieldFilterFunc) []*field.Field { + return []*field.Field{ + f.SetFieldState("id", field.String()), + f.SetFieldState("name", field.String()), + f.SetFieldState("mimeType", field.String()), + f.SetFieldState("size", field.Number(field.NumberFormatInt)), + f.SetFieldState("url", field.String()), + f.SetFieldState("key", field.String()), + } +} type FileType struct { fs Files @@ -65,14 +87,21 @@ func (t FileType) Encode(ctx context.Context, fld *field.Field, v interface{}) ( return nil, fmt.Errorf("FileField encode error: incorrect type: \"%s\", expected \"file\"", reflect.ValueOf(v).Kind()) } - if f.File != nil { // upload from file system + if f.Content != nil { + // По возможности устанавливаем указатель в начало, + // для избегания ошибки при повторном чтении + if seeker, ok := f.Content.(io.Seeker); ok { + _, _ = seeker.Seek(0, io.SeekStart) + } + upload, err := t.fs.Upload(ctx, f) if err != nil { return nil, err } - if err = t.uploader.Upload(f.File, upload); err != nil { + if err = t.uploader.Upload(f.Content, upload); err != nil { return nil, err } + f = &upload.File } @@ -137,17 +166,6 @@ func (t *FileType) IsEmpty(v interface{}) bool { return !ok || f.ID == "" } -func (p FileParameters) GetField(path string) (fld *field.Field) { - switch path { - case "id", "name", "mimeType", "url", "key": - return field.String() - case "size": - return field.Number(field.NumberFormatInt) - default: - return nil - } -} - func init() { // По умолчанию без FS // Если нужны подписанные URL, и загрузка на FS, нужно зарегистрировать корректный типа diff --git a/pkg/files/field_test.go b/pkg/files/field_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7b6317309654c9027ca0b373b2362b7d3aad54af --- /dev/null +++ b/pkg/files/field_test.go @@ -0,0 +1,34 @@ +package files + +import ( + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/schema" + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "github.com/stretchr/testify/assert" +) + +func TestFileField_Get(t *testing.T) { + sch := schema.New( + "a", field.String(), + "b", field.Object( + "file", Field(), + ), + "file", Field(), + ) + sch.ClearState() + + assert.Equal(t, field.String(), sch.GetField("file.id")) + assert.Equal(t, field.String(), sch.GetField("file.name")) + assert.Equal(t, field.String(), sch.GetField("file.mimeType")) + assert.Equal(t, field.String(), sch.GetField("file.url")) + assert.Equal(t, field.String(), sch.GetField("file.key")) + assert.Equal(t, field.Number(field.NumberFormatInt), sch.GetField("file.size")) + + assert.Equal(t, field.String(), sch.GetField("b.file.id")) + assert.Equal(t, field.String(), sch.GetField("b.file.name")) + assert.Equal(t, field.String(), sch.GetField("b.file.mimeType")) + assert.Equal(t, field.String(), sch.GetField("b.file.url")) + assert.Equal(t, field.String(), sch.GetField("b.file.key")) + assert.Equal(t, field.Number(field.NumberFormatInt), sch.GetField("b.file.size")) +} diff --git a/pkg/files/file.go b/pkg/files/file.go index d2236b83368e3d5efc763fd6f7e53664e15cc827..ce49d8e227cd8a71dbd2fd948fb9c4e8cecc382f 100644 --- a/pkg/files/file.go +++ b/pkg/files/file.go @@ -3,11 +3,11 @@ package files import ( "bytes" "fmt" - "io/fs" + "io" "strings" "text/template" - "git.perx.ru/perxis/perxis-go/pkg/id" + "git.perx.ru/perxis/perxis-go/id" ) const ( @@ -16,13 +16,13 @@ const ( // File - описание файла в системе хранения perxis type File struct { - ID string `mapstructure:"id,omitempty" json:"id" expr:"id"` // Уникальный идентификатор файла в хранилище - Name string `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty" expr:"name"` // Имя файла - Size int `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty" expr:"size"` // Размер файла - MimeType string `mapstructure:"mimeType,omitempty" json:"mimeType" bson:"mimeType,omitempty" expr:"mime_type"` // Mime-type файла - URL string `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty" expr:"url"` // Адрес для загрузки файла - Key string `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty" expr:"key"` // Ключ для хранения файла в хранилище - File fs.File `mapstructure:"-" json:"-" bson:"-"` // Файл для загрузки(из файловой системы) + ID string `mapstructure:"id,omitempty" json:"id" expr:"id"` // Уникальный идентификатор файла в хранилище + Name string `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty" expr:"name"` // Имя файла + Size uint64 `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty" expr:"size"` // Размер файла + MimeType string `mapstructure:"mimeType,omitempty" json:"mimeType" bson:"mimeType,omitempty" expr:"mime_type"` // Mime-type файла + URL string `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty" expr:"url"` // Адрес для загрузки файла + Key string `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty" expr:"key"` // Ключ для хранения файла в хранилище + Content io.Reader `mapstructure:"-" json:"-" bson:"-"` // Альтернативный способ задать содержимое файла } func (f File) Clone() *File { @@ -47,7 +47,7 @@ func (f *File) SetURLWithTemplate(t *template.Template) error { return nil } -func NewFile(name, mimeType string, size int, temp bool) *File { +func NewFile(name, mimeType string, size uint64, temp bool) *File { i := id.GenerateNewID() if temp { i = fmt.Sprintf("%s%s", TemporaryPrefix, i) @@ -64,7 +64,7 @@ func NewFile(name, mimeType string, size int, temp bool) *File { type MultipartUpload struct { File UploadID string `json:"upload_id"` // Идентификатор загрузки хранилища - PartSize int `json:"part_size"` // Размер блока для загрузки + PartSize uint64 `json:"part_size"` // Размер блока для загрузки PartURLs []string `json:"part_urls"` // Адреса для загрузки полного файла Parts []*CompletedPart `json:"parts"` // Идентификаторы загруженных блоков (S3 ETAGs) } diff --git a/pkg/files/file_test.go b/pkg/files/file_test.go index 617bed4c09ef95ab58874d856a36c5584abd4589..9a67b13c8861d4eaa75cee6cdaca8255e25be432 100644 --- a/pkg/files/file_test.go +++ b/pkg/files/file_test.go @@ -69,7 +69,7 @@ func TestFile_InExpr(t *testing.T) { }{ {"f.id", map[string]interface{}{"f": &File{ID: "some_id"}}, "some_id", false}, {"f.name", map[string]interface{}{"f": &File{Name: "some_name"}}, "some_name", false}, - {"f.size", map[string]interface{}{"f": &File{Size: 1}}, 1, false}, + {"f.size", map[string]interface{}{"f": &File{Size: uint64(1)}}, uint64(1), false}, {"f.mime_type", map[string]interface{}{"f": &File{MimeType: "some_mime_type"}}, "some_mime_type", false}, {"f.url", map[string]interface{}{"f": &File{URL: "some_url"}}, "some_url", false}, {"f.key", map[string]interface{}{"f": &File{Key: "some_key"}}, "some_key", false}, diff --git a/pkg/files/transport/client.microgen.go b/pkg/files/transport/client.go similarity index 66% rename from pkg/files/transport/client.microgen.go rename to pkg/files/transport/client.go index 6320c479808103ebdfef774c51c85fa1ea5f9cfe..09bf05fece9262b9811ed3cb9d0323f9aeb1267d 100644 --- a/pkg/files/transport/client.microgen.go +++ b/pkg/files/transport/client.go @@ -4,20 +4,14 @@ package transport import ( "context" - "errors" files "git.perx.ru/perxis/perxis-go/pkg/files" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) StartUpload(arg0 context.Context, arg1 *files.MultipartUpload) (res0 *files.MultipartUpload, res1 error) { request := StartUploadRequest{Upload: arg1} response, res1 := set.StartUploadEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*StartUploadResponse).U, res1 @@ -27,9 +21,6 @@ func (set EndpointsSet) CompleteUpload(arg0 context.Context, arg1 *files.Multipa request := CompleteUploadRequest{Upload: arg1} response, res1 := set.CompleteUploadEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CompleteUploadResponse).U, res1 @@ -39,9 +30,6 @@ func (set EndpointsSet) AbortUpload(arg0 context.Context, arg1 *files.MultipartU request := AbortUploadRequest{Upload: arg1} _, res0 = set.AbortUploadEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -51,9 +39,6 @@ func (set EndpointsSet) MoveUpload(arg0 context.Context, arg1 *files.MultipartUp request := MoveUploadRequest{Upload: arg1} response, res1 := set.MoveUploadEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*MoveUploadResponse).File, res1 @@ -63,9 +48,6 @@ func (set EndpointsSet) Upload(arg0 context.Context, arg1 *files.File) (res0 *fi request := UploadRequest{File: arg1} response, res1 := set.UploadEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*UploadResponse).U, res1 @@ -75,9 +57,6 @@ func (set EndpointsSet) GetFile(arg0 context.Context, arg1 *files.File) (res0 *f request := GetFileRequest{File: arg1} response, res1 := set.GetFileEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetFileResponse).F, res1 @@ -87,9 +66,6 @@ func (set EndpointsSet) DeleteFile(arg0 context.Context, arg1 *files.File) (res0 request := DeleteFileRequest{File: arg1} _, res0 = set.DeleteFileEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/files/transport/grpc/client.go b/pkg/files/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..e528e995661c010eaf46206f003fcdbf43635810 --- /dev/null +++ b/pkg/files/transport/grpc/client.go @@ -0,0 +1,23 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/files/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + AbortUploadEndpoint: grpcerr.ClientMiddleware(c.AbortUploadEndpoint), + CompleteUploadEndpoint: grpcerr.ClientMiddleware(c.CompleteUploadEndpoint), + DeleteFileEndpoint: grpcerr.ClientMiddleware(c.DeleteFileEndpoint), + GetFileEndpoint: grpcerr.ClientMiddleware(c.GetFileEndpoint), + MoveUploadEndpoint: grpcerr.ClientMiddleware(c.MoveUploadEndpoint), + StartUploadEndpoint: grpcerr.ClientMiddleware(c.StartUploadEndpoint), + UploadEndpoint: grpcerr.ClientMiddleware(c.UploadEndpoint), + } +} diff --git a/pkg/files/transport/grpc/protobuf_type_converters.microgen.go b/pkg/files/transport/grpc/protobuf_type_converters.microgen.go index 1240f9fc2e59251a6792fd04214455c6c75bb050..2bfdad9cc3df4dda0f30cbe7bf94941284a1ffe4 100644 --- a/pkg/files/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/files/transport/grpc/protobuf_type_converters.microgen.go @@ -15,7 +15,7 @@ func PtrMultipartUploadToProto(upload *files.MultipartUpload) (*pb.MultipartUplo } pbUpload := &pb.MultipartUpload{ UploadId: upload.UploadID, - PartSize: int32(upload.PartSize), + PartSize: upload.PartSize, PartUrls: upload.PartURLs, } pbUpload.Parts = make([]*pb.CompletedPart, 0, len(upload.Parts)) @@ -39,7 +39,7 @@ func ProtoToPtrMultipartUpload(protoUpload *pb.MultipartUpload) (*files.Multipar } upload := &files.MultipartUpload{ UploadID: protoUpload.UploadId, - PartSize: int(protoUpload.PartSize), + PartSize: protoUpload.PartSize, PartURLs: protoUpload.PartUrls, } upload.Parts = make([]*files.CompletedPart, 0, len(protoUpload.Parts)) @@ -96,7 +96,7 @@ func PtrFileToProto(file *files.File) (*pb.File, error) { pbFile := &pb.File{ Id: file.ID, Name: file.Name, - Size: int32(file.Size), + Size: file.Size, MimeType: file.MimeType, Url: file.URL, } @@ -110,7 +110,7 @@ func ProtoToPtrFile(protoFile *pb.File) (*files.File, error) { file := &files.File{ ID: protoFile.Id, Name: protoFile.Name, - Size: int(protoFile.Size), + Size: protoFile.Size, MimeType: protoFile.MimeType, URL: protoFile.Url, } diff --git a/pkg/files/transport/grpc/server.go b/pkg/files/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..dcfc07598dbd6b2e0adb04d804e1cb8f223e55bf --- /dev/null +++ b/pkg/files/transport/grpc/server.go @@ -0,0 +1,23 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/files" + "git.perx.ru/perxis/perxis-go/pkg/files/transport" + pb "git.perx.ru/perxis/perxis-go/proto/files" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc files.Files, opts ...grpckit.ServerOption) pb.FilesServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + AbortUploadEndpoint: grpcerr.ServerMiddleware(eps.AbortUploadEndpoint), + CompleteUploadEndpoint: grpcerr.ServerMiddleware(eps.CompleteUploadEndpoint), + DeleteFileEndpoint: grpcerr.ServerMiddleware(eps.DeleteFileEndpoint), + GetFileEndpoint: grpcerr.ServerMiddleware(eps.GetFileEndpoint), + MoveUploadEndpoint: grpcerr.ServerMiddleware(eps.MoveUploadEndpoint), + StartUploadEndpoint: grpcerr.ServerMiddleware(eps.StartUploadEndpoint), + UploadEndpoint: grpcerr.ServerMiddleware(eps.UploadEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/filter/filter.go b/pkg/filter/filter.go index 04ebf36d2b95e7bc86018e5539a68d6fc1ddead9..d75dc99886698a14342dc4f5ad4d9423fc26d893 100644 --- a/pkg/filter/filter.go +++ b/pkg/filter/filter.go @@ -1,6 +1,7 @@ package filter import ( + "context" "fmt" "reflect" "strings" @@ -60,7 +61,7 @@ type FilterHandler struct { func NewFilterHandler(sch ...*schema.Schema) *FilterHandler { return &FilterHandler{ schemas: sch, - //qbuilder: qb, + // qbuilder: qb, } } @@ -77,9 +78,7 @@ func (h *FilterHandler) removeFieldPrefix(f string) string { } func (h *FilterHandler) AddSchema(sch ...*schema.Schema) *FilterHandler { - for _, s := range sch { - h.schemas = append(h.schemas, s) - } + h.schemas = append(h.schemas, sch...) return h } @@ -129,7 +128,7 @@ func (h *FilterHandler) validate(sch *schema.Schema, f *Filter) (err error) { if f.Value, err = schema.Decode(nil, fld, f.Value); err != nil { return h.formatErr(f.Field, f.Op, err) } - if err = validate.Validate(nil, fld, f.Value); err != nil { + if err = validate.Validate(context.Background(), fld, f.Value); err != nil { return h.formatErr(f.Field, f.Op, err) } case In, NotIn: @@ -377,7 +376,7 @@ func (b *mongoQueryBuilder) field(f string) string { } // $text search ?? -//func (b *mongoQueryBuilder) textSearchQuery(filters ...*Filter) string { +// func (b *mongoQueryBuilder) textSearchQuery(filters ...*Filter) string { // cnt, notcnt := "", "" // for _, f := range filters { // val, ok := f.Value.(string) @@ -407,4 +406,4 @@ func (b *mongoQueryBuilder) field(f string) string { // cnt += " " + notcnt // } // return cnt -//} +// } diff --git a/pkg/invitations/events.go b/pkg/invitations/events.go new file mode 100644 index 0000000000000000000000000000000000000000..622f744796d5a24cac0bc078a48d62a6ba36a522 --- /dev/null +++ b/pkg/invitations/events.go @@ -0,0 +1,7 @@ +package invitations + +const ( + EventCreate = "invitations.create" + EventDelete = "invitations.delete" + EventAccept = "invitations.accept" +) diff --git a/pkg/invitations/invitation.go b/pkg/invitations/invitation.go index 5dc5913774fc5774076823309abdf52b195c87c2..a5b91ed006693748deb71877b8e555e485b0c6c8 100644 --- a/pkg/invitations/invitation.go +++ b/pkg/invitations/invitation.go @@ -14,3 +14,16 @@ type Invitation struct { CreatedAt *time.Time `bson:"createdAt"` ValidUntil *time.Time `bson:"validUntil"` } + +func (i Invitation) Clone() *Invitation { + return &Invitation{ + ID: i.ID, + Email: i.Email, + OrgID: i.OrgID, + SpaceID: i.SpaceID, + OwnerID: i.OwnerID, + Role: i.Role, + CreatedAt: i.CreatedAt, + ValidUntil: i.ValidUntil, + } +} diff --git a/pkg/invitations/middleware/caching_middleware.go b/pkg/invitations/middleware/caching_middleware.go index 5f2a1086a15c09d55b5461e029036b091d68dcfe..b14a155dc04022baed930f4252ec63caf47dab3b 100644 --- a/pkg/invitations/middleware/caching_middleware.go +++ b/pkg/invitations/middleware/caching_middleware.go @@ -30,20 +30,21 @@ func (m cachingMiddleware) Get(ctx context.Context, invitationId string) (inv *s value, e := m.cache.Get(invitationId) if e == nil { - return value.(*service.Invitation), err + return value.(*service.Invitation).Clone(), nil } inv, err = m.next.Get(ctx, invitationId) if err == nil { - m.cache.Set(invitationId, inv) + _ = m.cache.Set(invitationId, inv) + return inv.Clone(), nil } - return inv, err + return nil, err } func (m cachingMiddleware) Accept(ctx context.Context, invitationId string, userId string) (err error) { err = m.next.Accept(ctx, invitationId, userId) if err == nil { - m.cache.Remove(invitationId) + _ = m.cache.Remove(invitationId) } return err } @@ -56,7 +57,7 @@ func (m cachingMiddleware) Delete(ctx context.Context, invitationId string) (err err = m.next.Delete(ctx, invitationId) if err == nil { - m.cache.Remove(invitationId) + _ = m.cache.Remove(invitationId) } return err } diff --git a/pkg/invitations/middleware/caching_middleware_test.go b/pkg/invitations/middleware/caching_middleware_test.go index e7fac6f545463644ddd7476a43123f248b9a16b8..46d0a44342822a877be1feffbc396e37606e8157 100644 --- a/pkg/invitations/middleware/caching_middleware_test.go +++ b/pkg/invitations/middleware/caching_middleware_test.go @@ -41,7 +41,8 @@ func TestLocalesCache(t *testing.T) { v2, err := svc.Get(ctx, invID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.Equal(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.NotSame(t, v1, v2) inv.AssertExpectations(t) }) @@ -59,7 +60,8 @@ func TestLocalesCache(t *testing.T) { v2, err := svc.Get(ctx, invID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.Equal(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.NotSame(t, v1, v2) inv.On("Accept", mock.Anything, invID, usrID).Return(nil).Once() inv.On("Get", mock.Anything, invID).Return(nil, errNotFound).Once() @@ -86,7 +88,8 @@ func TestLocalesCache(t *testing.T) { v2, err := svc.Get(ctx, invID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.Equal(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.NotSame(t, v1, v2) inv.On("Delete", mock.Anything, invID).Return(nil).Once() inv.On("Get", mock.Anything, invID).Return(nil, errNotFound).Once() @@ -113,7 +116,8 @@ func TestLocalesCache(t *testing.T) { v2, err := svc.Get(ctx, invID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.Equal(t, v1, v2, "Ожидается что при повторном запросе объект будет получен из кэша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) @@ -122,6 +126,8 @@ func TestLocalesCache(t *testing.T) { v3, err := svc.Get(ctx, invID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается что при истечении ttl кеш будет очищен..") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) inv.AssertExpectations(t) }) diff --git a/pkg/invitations/middleware/logging_middleware.go b/pkg/invitations/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..f32fa01b32887a2ced9b2a702d9e8434e1fef3de --- /dev/null +++ b/pkg/invitations/middleware/logging_middleware.go @@ -0,0 +1,119 @@ +package middleware + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/pkg/invitations" + "git.perx.ru/perxis/perxis-go/pkg/options" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next invitations.Invitations +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next invitations.Invitations) invitations.Invitations { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Invitations")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, invitation *invitations.Invitation) (created *invitations.Invitation, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(invitations.EventCreate), + logzap.Object(id.NewSpaceId(invitation.SpaceID)), + ) + + created, err = m.next.Create(ctx, invitation) + if err != nil { + logger.Error("Failed to create invitation", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("Created invitation '%s'", created.ID), logzap.Channels(logzap.Userlog)) + + return created, err +} + +func (m *loggingMiddleware) Get(ctx context.Context, invitationId string) (invitation *invitations.Invitation, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + invitation, err = m.next.Get(ctx, invitationId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return invitation, err +} + +func (m *loggingMiddleware) Accept(ctx context.Context, invitationId, userId string) (err error) { + invitation, err := m.next.Get(ctx, invitationId) + if err != nil { + return errors.Wrap(err, "failed to get invitation") + } + + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(invitations.EventAccept), + logzap.Object(id.NewSpaceId(invitation.SpaceID)), + ) + + err = m.next.Accept(ctx, invitationId, userId) + if err != nil { + logger.Error(fmt.Sprintf("Failed to accept invitation '%s'", invitationId), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("Invitation '%s' accepted by user '%s'", invitationId, userId), logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Find(ctx context.Context, filter *invitations.Filter, opts *options.FindOptions) (invitations []*invitations.Invitation, total int, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + invitations, total, err = m.next.Find(ctx, filter, opts) + if err != nil { + logger.Error("Failed to find", zap.Error(err)) + return + } + + return invitations, total, err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, invitationId string) (err error) { + invitation, err := m.next.Get(ctx, invitationId) + if err != nil { + return errors.Wrap(err, "failed to get invitation") + } + + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(invitations.EventDelete), + logzap.Object(id.NewSpaceId(invitation.SpaceID)), + ) + + err = m.next.Delete(ctx, invitationId) + if err != nil { + logger.Error(fmt.Sprintf("Failed to delete invitation '%s' ", invitationId), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("Invitation '%s' deleted", invitationId), logzap.Channels(logzap.Userlog)) + + return err +} diff --git a/pkg/invitations/middleware/middleware.go b/pkg/invitations/middleware/middleware.go index f59604ba948ade1b4fe03bc3e3cadd8de6f7cfcd..47a2d84b987fcd760086ff6837cd25867945e574 100644 --- a/pkg/invitations/middleware/middleware.go +++ b/pkg/invitations/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s invitations.Invitations, logger *zap.Logger, log_access bool) inv if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/invitations/transport/client.microgen.go b/pkg/invitations/transport/client.go similarity index 67% rename from pkg/invitations/transport/client.microgen.go rename to pkg/invitations/transport/client.go index 6f896b0e67fa88a1eaa539c305a47fada11c9c8b..04ad55679775497da0ec7919450c8e8d54738a90 100644 --- a/pkg/invitations/transport/client.microgen.go +++ b/pkg/invitations/transport/client.go @@ -4,21 +4,15 @@ package transport import ( "context" - "errors" invitations "git.perx.ru/perxis/perxis-go/pkg/invitations" "git.perx.ru/perxis/perxis-go/pkg/options" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *invitations.Invitation) (res0 *invitations.Invitation, res1 error) { request := CreateRequest{Invitation: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 @@ -28,9 +22,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string) (res0 *invitation request := GetRequest{InvitationId: arg1} response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Invitation, res1 @@ -43,9 +34,6 @@ func (set EndpointsSet) Accept(arg0 context.Context, arg1 string, arg2 string) ( } _, res0 = set.AcceptEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -58,9 +46,6 @@ func (set EndpointsSet) Find(arg0 context.Context, arg1 *invitations.Filter, arg } response, res2 := set.FindEndpoint(arg0, &request) if res2 != nil { - if e, ok := status.FromError(res2); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res2 = errors.New(e.Message()) - } return } return response.(*FindResponse).Invitations, response.(*FindResponse).Total, res2 @@ -70,9 +55,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string) (res0 error) { request := DeleteRequest{InvitationId: arg1} _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/invitations/transport/grpc/client.go b/pkg/invitations/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..995dc563cc84f24b6f470de43531c6a6e62b90b2 --- /dev/null +++ b/pkg/invitations/transport/grpc/client.go @@ -0,0 +1,21 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/invitations/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + AcceptEndpoint: grpcerr.ClientMiddleware(c.AcceptEndpoint), + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + FindEndpoint: grpcerr.ClientMiddleware(c.FindEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + } +} diff --git a/pkg/invitations/transport/grpc/server.go b/pkg/invitations/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..f0a23fcd1d4f21c3f0dde9b72e7cee1757ace8b4 --- /dev/null +++ b/pkg/invitations/transport/grpc/server.go @@ -0,0 +1,21 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/invitations" + "git.perx.ru/perxis/perxis-go/pkg/invitations/transport" + pb "git.perx.ru/perxis/perxis-go/proto/invitations" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc invitations.Invitations, opts ...grpckit.ServerOption) pb.InvitationsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + AcceptEndpoint: grpcerr.ServerMiddleware(eps.AcceptEndpoint), + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + FindEndpoint: grpcerr.ServerMiddleware(eps.FindEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/items/errors.go b/pkg/items/errors.go index 2d6cc1cfb5bb047ccd1ec96bc073bb4de600ccef..9ade59dbbd11ce3c9fc1624f1c02a044b57e53a4 100644 --- a/pkg/items/errors.go +++ b/pkg/items/errors.go @@ -7,8 +7,10 @@ import ( ) var ( - ErrAccessDenied = service.ErrAccessDenied - ErrNotFound = service.ErrNotFound - ErrUniqueValueRequired = errors.New("unique value required") - ErrTextSearchNotAvaluble = errors.New("fulltext search is not available in this collection") + ErrAccessDenied = service.ErrAccessDenied + ErrNotFound = service.ErrNotFound + ErrUniqueValueRequired = errors.New("unique value required") + ErrTextSearchNotAvailable = errors.New("fulltext search is not available in this collection") + + ErrCreateLocalizedItem = errors.New("create only supports default locale") ) diff --git a/pkg/items/item.go b/pkg/items/item.go index c6fd3ad14cbe731c9d5f592f05d33cc2e7f5081b..d8271aae51369cde38e41121d211bda1a483695f 100644 --- a/pkg/items/item.go +++ b/pkg/items/item.go @@ -3,13 +3,14 @@ package items import ( "context" "fmt" - "reflect" "time" "git.perx.ru/perxis/perxis-go/pkg/data" "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/pkg/locales" "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "git.perx.ru/perxis/perxis-go/pkg/schema/localizer" pb "git.perx.ru/perxis/perxis-go/proto/items" "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" @@ -19,6 +20,7 @@ var ( ErrNotSystemField = errors.New("not a system field") ErrIncorrectValue = errors.New("incorrect value") ErrIncorrectField = errors.New("incorrect field") + ErrReservedField = errors.New("cannot use reserved field name") ) type State int @@ -72,10 +74,12 @@ var SystemFields = []string{ "revision_description", "data", "translations", - "locale", + "translations_ids", + "locale_id", "deleted", "hidden", "template", + "search_score", } type Permissions struct { @@ -87,24 +91,44 @@ type Permissions struct { } type Item struct { - ID string `json:"id" bson:"_id"` // ID - Идентификатор записи. Автоматически генерируется системой при сохранении первой ревизии. - SpaceID string `json:"spaceId" bson:"-"` - EnvID string `json:"envId" bson:"-"` - CollectionID string `json:"collectionId" bson:"-"` - State State `json:"state" bson:"state"` - CreatedRevAt time.Time `json:"createdRevAt,omitempty" bson:"created_rev_at,omitempty"` - CreatedBy string `json:"createdBy,omitempty" bson:"created_by,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty" bson:"created_at,omitempty"` - UpdatedAt time.Time `json:"updatedAt,omitempty" bson:"updated_at,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty" bson:"updated_by,omitempty"` - Data map[string]interface{} `json:"data" bson:"data"` - Locale string `json:"locale" bson:"-"` - Translations map[string]map[string]interface{} `json:"translations" bson:"translations,omitempty"` - RevisionID string `json:"revId,omitempty" bson:"revision_id"` - RevisionDescription string `json:"revDescription,omitempty" bson:"revision_description"` - Permissions *Permissions `json:"permissions,omitempty" bson:"-"` - - // Флаги записи + ID string `json:"id" bson:"_id"` // ID - Идентификатор записи. Автоматически генерируется системой при сохранении первой ревизии. + SpaceID string `json:"spaceId" bson:"-"` + EnvID string `json:"envId" bson:"-"` + CollectionID string `json:"collectionId" bson:"-"` + State State `json:"state" bson:"state"` + CreatedRevAt time.Time `json:"createdRevAt,omitempty" bson:"created_rev_at,omitempty"` + CreatedBy string `json:"createdBy,omitempty" bson:"created_by,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty" bson:"created_at,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty" bson:"updated_at,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty" bson:"updated_by,omitempty"` + Data map[string]interface{} `json:"data" bson:"data"` + + // При создании или обновлении идентификатор локали в котором создается запись, опционально. + // Если указан, то создается перевод для указанного языка, поле translations игнорируется + LocaleID string `json:"locale_id" bson:"-"` + + // Позволяет одновременно установить/получить несколько переводов и производить манипуляции с переводами + // Ключами является идентификатор локали, значениями - данные переводы + // При обновлении не происходит валидация или модификация каждого из переводов в соответствие со схемой, + // поэтому обновление через поле `translations` стоит выполнять с аккуратностью + // Для удаления переводов реализована следующая логика: + // - {"lang":nil|{}} - сброс перевода для языка + // - {"lang":map{...}} - установка перевода для языка + // - {"lang":map{...}, "*":nil} - установка перевода для языка, сброс остальных переводов + // - {"*":nil} - сброс всех переводов + Translations map[string]map[string]interface{} `json:"translations" bson:"translations,omitempty"` + + // Список идентификаторов локалей, для которых есть переводы. + // Соответствует ключам в translations + TranslationsIDs []string `json:"translations_ids" bson:"translations_ids,omitempty"` + + RevisionID string `json:"revId,omitempty" bson:"revision_id"` + RevisionDescription string `json:"revDescription,omitempty" bson:"revision_description"` + Permissions *Permissions `json:"permissions,omitempty" bson:"-"` + + // Релеватность элемента при полнотекстовом поиске + SearchScore float64 `json:"searchScore,omitempty" bson:"search_score,omitempty"` + Deleted bool `json:"deleted" bson:"deleted,omitempty"` Hidden bool `json:"hidden" bson:"hidden,omitempty"` Template bool `json:"template" bson:"template,omitempty"` @@ -123,6 +147,11 @@ func NewItem(spaceID, envID, collID, id string, data map[string]interface{}, tra } } +// GetID возвращает идентификатор записи +func (i *Item) GetID() string { + return i.ID +} + func (i *Item) Clone() *Item { itm := *i itm.Data = data.CloneMap(i.Data) @@ -152,142 +181,185 @@ func (i *Item) ToMap() map[string]interface{} { "revision_id": i.RevisionID, "revision_description": i.RevisionDescription, "data": i.Data, + "locale_id": i.LocaleID, "translations": i.Translations, - "locale": i.Locale, + "translations_ids": i.TranslationsIDs, "deleted": i.Deleted, "hidden": i.Hidden, "template": i.Template, + "search_score": i.SearchScore, } } -func (i *Item) SetData(locale string, data map[string]interface{}) { - if locale != "" { - if i.Translations == nil { - i.Translations = make(map[string]map[string]interface{}) - } - i.Translations[locale] = data +// SetData устанавливает перевод в нужное поле записи +func (i *Item) SetData(dt map[string]interface{}, localeID string) { + if localeID == "" || localeID == locales.DefaultID { + i.Data = dt return } - i.Data = data + if i.Translations == nil { + i.Translations = map[string]map[string]interface{}{localeID: dt} + if !data.Contains(localeID, i.TranslationsIDs) { + i.TranslationsIDs = append(i.TranslationsIDs, localeID) + } + } + return } -func (i *Item) GetData(locale string) map[string]interface{} { - if locale != "" && i.Translations != nil { - translation, _ := i.Translations[locale] - return MergeData(i.Data, translation) +// GetData возвращает полные локализованные данные записи +func (i *Item) GetData(localeID string) map[string]interface{} { + if localeID == "" || localeID == locales.DefaultID { + return i.Data } - return i.Data + if i.Translations != nil { + return i.Translations[localeID] + } + return nil } -func (i Item) Encode(ctx context.Context, s *schema.Schema) (*Item, error) { +func (i *Item) AddTranslations(translations map[string]map[string]interface{}) { + if i.Translations == nil { + i.Translations = make(map[string]map[string]interface{}, len(translations)) + } + for l, t := range translations { + i.Translations[l] = t + } + for k := range translations { + if !data.Contains(k, i.TranslationsIDs) { + i.TranslationsIDs = append(i.TranslationsIDs, k) + } + } +} + +func (i *Item) Localize(localizer *localizer.Localizer) (err error) { + if localizer == nil { + return nil + } + i.Data, err = localizer.Localize(i.Data, i.Translations) + if err != nil { + return err + } + i.LocaleID = localizer.LocaleID() + i.Translations = nil + return nil +} + +// // UnsetTranslation устанавливает значение перевода в nil, для сброса перевода для языка +// // "localeID":map{...}, "*":nil} - установка перевода для языка, сброс остальных переводов +// // {"*":nil} -сброс всех переводов +// func (i *Item) UnsetTranslation(localeID string) { +// if i.Translations == nil { +// i.Translations = make(map[string]map[string]interface{}) +// } +// +// i.Translations[localeID] = nil +// } +// +// // SetTranslation устанавливает перевод для языка +// func (i *Item) SetTranslation(dt map[string]interface{}, localeID string) { +// if i.Translations == nil { +// i.Translations = make(map[string]map[string]interface{}) +// } +// +// i.Translations[localeID] = dt +// } + +func (i *Item) Encode(ctx context.Context, s *schema.Schema) (*Item, error) { + res := *i if i.Data != nil { - dt, err := schema.Encode(nil, s, i.Data) + dt, err := schema.Encode(ctx, s, i.Data) if err != nil { - //return errors.WithField(err, "data") + // return errors.WithField(err, "data") return nil, err } - i.Data = dt.(map[string]interface{}) + res.Data = dt.(map[string]interface{}) } if len(i.Translations) > 0 { + res.Translations = make(map[string]map[string]interface{}, len(i.Translations)) for l, v := range i.Translations { - dt, err := schema.Encode(nil, s, v) + if len(v) == 0 { + res.Translations[l] = v + continue + } + dt, err := schema.Encode(ctx, s, v) if err != nil { - //return errors.WithField(err, fmt.Sprintf("translations.%s", l)) return nil, err } - i.Translations[l] = dt.(map[string]interface{}) + res.Translations[l] = dt.(map[string]interface{}) } } - return &i, nil + return &res, nil } -func (i Item) Decode(ctx context.Context, s *schema.Schema) (res *Item, err error) { - +func (i *Item) Decode(ctx context.Context, s *schema.Schema) (*Item, error) { + res := *i + var err error if i.Data != nil { - i.Data, err = s.Decode(ctx, i.Data) + res.Data, err = s.Decode(ctx, i.Data) if err != nil { return nil, err - //return errors.WithField(err, "data") } } - - return &i, nil -} - -// MergeData дополняет отсутствующие данные из оригинальных данных -func MergeData(data ...map[string]interface{}) map[string]interface{} { - merge := make(map[string]interface{}) - for _, d := range data { - for k, v := range d { - merge[k] = v - } - } - return merge -} - -// ClearData убирает данные которые не изменились по сравнению с оригинальными данными -func ClearData(data ...map[string]interface{}) map[string]interface{} { - var clear map[string]interface{} - - for _, d := range data { - if clear == nil { - clear = d - continue - } - - for k, v := range d { - if reflect.DeepEqual(clear[k], v) { - delete(clear, k) + if len(i.Translations) > 0 { + res.Translations = make(map[string]map[string]interface{}, len(i.Translations)) + for l, v := range i.Translations { + if len(v) == 0 { + res.Translations[l] = v + continue + } + dt, err := schema.Decode(ctx, s, v) + if err != nil { + return nil, err } + res.Translations[l] = dt.(map[string]interface{}) } } - - return clear + return &res, nil } type ProcessDataFunc func(ctx context.Context, sch *schema.Schema, data map[string]interface{}) (map[string]interface{}, error) -func (i Item) ProcessData(ctx context.Context, sch *schema.Schema, fn ProcessDataFunc, locales ...string) (*Item, error) { +func (i *Item) ProcessData(ctx context.Context, sch *schema.Schema, fn ProcessDataFunc, locales ...*locales.Locale) (*Item, error) { + res := *i if i.Data != nil { - dt, err := fn(ctx, sch, i.Data) + dt, err := fn(ctx, sch, res.Data) if err != nil { return nil, errors.WithField(err, "data") } - i.Data = dt + res.Data = dt } tr := make(map[string]map[string]interface{}) for _, l := range locales { - - data := i.GetData(l) - - dt, err := fn(ctx, sch, data) + itm := *i + err := itm.Localize(localizer.NewLocalizer(localizer.Config{Schema: sch, Locales: locales, LocaleID: l.ID})) if err != nil { - return nil, errors.WithField(err, fmt.Sprintf("translations.%s", l)) + return nil, errors.WithField(err, fmt.Sprintf("translations.%s", l.ID)) } - tr[l] = dt + dt, err := fn(ctx, sch, itm.Data) + if err != nil { + return nil, errors.WithField(err, fmt.Sprintf("translations.%s", l.ID)) + } + tr[l.ID] = dt } - i.Translations = nil + res.Translations = nil if len(tr) > 0 { - i.Translations = tr + res.Translations = tr } - return &i, nil + return &res, nil } // IsSystemField возвращает являться ли поле системным func IsSystemField(field string) bool { - if data.Contains(field, SystemFields) { - return true - } - return false + return data.Contains(field, SystemFields) } // SetSystemField устанавливает значение системного поля func (i *Item) SetSystemField(field string, value interface{}) error { - ok := true + var ok bool switch field { case "id": i.ID, ok = value.(string) @@ -317,6 +389,8 @@ func (i *Item) SetSystemField(field string, value interface{}) error { i.Deleted, ok = value.(bool) case "template": i.Template, ok = value.(bool) + case "search_score": + i.SearchScore, ok = value.(float64) default: return ErrNotSystemField } @@ -328,7 +402,7 @@ func (i *Item) SetSystemField(field string, value interface{}) error { return nil } -// GetSystem устанавливает значение системного поля +// GetSystem возвращает значение системного поля func (i *Item) GetSystem(field string) (any, error) { switch field { case "id": @@ -359,6 +433,11 @@ func (i *Item) GetSystem(field string) (any, error) { return i.Deleted, nil case "template": return i.Template, nil + case "search_score": + return i.SearchScore, nil + case "state": + return i.State, nil + } return nil, ErrNotSystemField @@ -421,6 +500,10 @@ func GetSystemField(fld string) (*field.Field, error) { return field.String(), nil case "hidden", "deleted", "template": return field.Bool(), nil + case "search_score": + return field.Number(field.NumberFormatFloat), nil + case "state": + return field.Number(field.NumberFormatInt), nil } return nil, ErrNotSystemField @@ -467,10 +550,12 @@ func ItemToProto(item *Item) *pb.Item { UpdatedBy: item.UpdatedBy, RevisionId: item.RevisionID, RevisionDescription: item.RevisionDescription, - Locale: item.Locale, + LocaleId: item.LocaleID, + TranslationsIds: item.TranslationsIDs, Hidden: item.Hidden, Template: item.Template, Deleted: item.Deleted, + SearchScore: item.SearchScore, } if item.Data != nil { @@ -479,7 +564,11 @@ func ItemToProto(item *Item) *pb.Item { if item.Translations != nil { protoItem.Translations = make(map[string]*structpb.Struct, len(item.Translations)) for k, v := range item.Translations { - protoItem.Translations[k], _ = structpb.NewStruct(v) + var t *structpb.Struct + if v != nil { + t, _ = structpb.NewStruct(v) + } + protoItem.Translations[k] = t } } @@ -516,10 +605,12 @@ func ItemFromProto(protoItem *pb.Item) *Item { UpdatedBy: protoItem.UpdatedBy, RevisionID: protoItem.RevisionId, RevisionDescription: protoItem.RevisionDescription, - Locale: protoItem.Locale, + LocaleID: protoItem.LocaleId, + TranslationsIDs: protoItem.TranslationsIds, Hidden: protoItem.Hidden, Template: protoItem.Template, Deleted: protoItem.Deleted, + SearchScore: protoItem.SearchScore, } if protoItem.Data != nil { @@ -528,8 +619,16 @@ func ItemFromProto(protoItem *pb.Item) *Item { if protoItem.Translations != nil { item.Translations = make(map[string]map[string]interface{}, len(protoItem.Translations)) + } + if protoItem.Translations != nil { for k, v := range protoItem.Translations { - item.Translations[k] = v.AsMap() + // При proto.Marshal/Unmarshal `nil`-значение превращается в `Struct{}`, поэтому логика + // много смысла не несет, но хотя бы здесь сохраним различие пустого и nil значений + var t map[string]interface{} + if v != nil { + t = v.AsMap() + } + item.Translations[k] = t } } diff --git a/pkg/items/item_test.go b/pkg/items/item_test.go index dfcc16ee1c7b40441b5df54acc48a12b276669ca..05baa60a3c1e8eaae9534fe9026d7456d78ab36c 100644 --- a/pkg/items/item_test.go +++ b/pkg/items/item_test.go @@ -1,6 +1,7 @@ package items import ( + "context" "fmt" "testing" "time" @@ -8,19 +9,20 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/schema/field" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestItem_Set(t *testing.T) { item := &Item{} - item.Set("id", "id") + _ = item.Set("id", "id") assert.Equal(t, "id", item.ID) now := time.Now() - item.Set("created_at", now) + _ = item.Set("created_at", now) assert.Equal(t, now, item.CreatedAt) - item.Set("a.b.c", 101) + _ = item.Set("a.b.c", 101) assert.Equal(t, map[string]any{"a": map[string]any{"b": map[string]any{"c": 101}}}, item.Data) } @@ -70,6 +72,7 @@ func TestGetField(t *testing.T) { ), "arr", field.Array(field.Object("a", field.Time())), ) + sch.ClearState() tests := []struct { name string @@ -95,3 +98,169 @@ func TestGetField(t *testing.T) { }) } } + +func TestItem_Proto(t *testing.T) { + w := time.Now().UTC() + tests := []struct { + name string + item *Item + }{ + { + name: "All fields are filled", + item: &Item{ + ID: "id-1", + SpaceID: "space-1", + EnvID: "env-1", + CollectionID: "coll-1", + State: StateDraft, + CreatedRevAt: w.Add(time.Hour), + CreatedBy: "user-1", + CreatedAt: w, + UpdatedAt: w.Add(time.Hour), + UpdatedBy: "user-2", + Data: map[string]any{"a": "b", "c": "d", "x": nil}, + LocaleID: "ru", + Translations: map[string]map[string]interface{}{ + "ru": {"a": "B"}, + "en": nil, + }, + TranslationsIDs: []string{"ru", "en"}, + RevisionID: "rev-1", + RevisionDescription: "desc-1", + Permissions: PermissionsAllowAny, + SearchScore: 100.0, + Deleted: false, + Hidden: true, + Template: false, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.item, ItemFromProto(ItemToProto(tc.item))) + }) + } +} + +func TestItem_Encode_Decode(t *testing.T) { + w := time.Now().UTC() + tests := []struct { + name string + item *Item + }{ + { + name: "Data", + item: &Item{ + ID: "id-1", + SpaceID: "space-1", + EnvID: "env-1", + CollectionID: "coll-1", + State: StateDraft, + CreatedRevAt: w.Add(time.Hour), + CreatedBy: "user-1", + CreatedAt: w, + UpdatedAt: w.Add(time.Hour), + UpdatedBy: "user-2", + Data: map[string]any{ + "a": "text-a", + "b": 124.1, + "c": map[string]interface{}{"x": "y"}, + "d": []interface{}{"k", "l", "m"}, + }, + RevisionID: "rev-1", + RevisionDescription: "desc-1", + Permissions: PermissionsAllowAny, + SearchScore: 100.0, + Deleted: false, + Hidden: true, + Template: false, + }, + }, + { + name: "Data and Translations", + item: &Item{ + ID: "id-1", + SpaceID: "space-1", + EnvID: "env-1", + CollectionID: "coll-1", + State: StateDraft, + CreatedRevAt: w.Add(time.Hour), + CreatedBy: "user-1", + CreatedAt: w, + UpdatedAt: w.Add(time.Hour), + UpdatedBy: "user-2", + Data: map[string]any{ + "a": "text-a", + "b": 124.1, + "c": map[string]interface{}{"x": "y"}, + "d": []interface{}{"k", "l", "m"}, + }, + LocaleID: "ru", + Translations: map[string]map[string]interface{}{ + "ru": {"a": "ru-a"}, + "en": {"a": "en-a"}, + }, + TranslationsIDs: []string{"ru", "en"}, + RevisionID: "rev-1", + RevisionDescription: "desc-1", + Permissions: PermissionsAllowAny, + SearchScore: 100.0, + Deleted: false, + Hidden: false, + Template: false, + }, + }, + { + name: "Nil Translation", + item: &Item{ + ID: "id-1", + SpaceID: "space-1", + EnvID: "env-1", + CollectionID: "coll-1", + State: StateDraft, + CreatedRevAt: w.Add(time.Hour), + CreatedBy: "user-1", + CreatedAt: w, + UpdatedAt: w.Add(time.Hour), + UpdatedBy: "user-2", + Data: map[string]any{ + "a": "text-a", + "b": 124.1, + "c": map[string]interface{}{"x": "y"}, + "d": []interface{}{"k", "l", "m"}, + }, + LocaleID: "ru", + Translations: map[string]map[string]interface{}{ + "ru": {"a": "ru-a"}, + "en": nil, + }, + TranslationsIDs: []string{"ru", "en"}, + RevisionID: "rev-1", + RevisionDescription: "desc-1", + Permissions: PermissionsAllowAny, + SearchScore: 100.0, + Deleted: false, + Hidden: false, + Template: false, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + sch := schema.New( + "a", field.String(), + "b", field.Number(field.NumberFormatFloat), + "c", field.Object("x", field.String()), + "d", field.Array(field.String()), + ) + enc, err := tc.item.Encode(ctx, sch) + require.NoError(t, err) + dec, err := enc.Decode(ctx, sch) + require.NoError(t, err) + assert.Equal(t, tc.item, dec) + }) + } +} diff --git a/pkg/items/middleware/caching_middleware.go b/pkg/items/middleware/caching_middleware.go index 6b11851381fb9dc13b630477052f05d4148bc765..60d3bf80250843f2ddc963fe5d242e58f590a3f7 100644 --- a/pkg/items/middleware/caching_middleware.go +++ b/pkg/items/middleware/caching_middleware.go @@ -6,7 +6,9 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/cache" envService "git.perx.ru/perxis/perxis-go/pkg/environments" + "git.perx.ru/perxis/perxis-go/pkg/errors" service "git.perx.ru/perxis/perxis-go/pkg/items" + "git.perx.ru/perxis/perxis-go/pkg/locales" ) func makeKey(ss ...string) string { @@ -32,145 +34,141 @@ type cachingMiddleware struct { } func (m cachingMiddleware) Get(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*service.GetOptions) (itm *service.Item, err error) { + opts := service.MergeGetOptions(options...) + localeID := opts.LocaleID + if localeID == "" { + localeID = locales.DefaultID + } - value, e := m.cache.Get(makeKey(spaceId, envId, collectionId, itemId)) - if e == nil { - return value.(*service.Item), err + // Значение из кэша можно достать только в случае, когда не запрашиваются переводы. Для + // списка переводов (`item.Translations`) кэш не предусмотрен: предполагается, что это + // нечастый запрос и содержание кэша с разными переводами себя не оправдывает + var value = make(map[string]*service.Item) + if len(opts.TranslationsIDs) == 0 { + val, e := m.cache.Get(makeKey(spaceId, envId, collectionId, itemId)) + if e == nil { + value = val.(map[string]*service.Item) + if i, ok := value[localeID]; ok { + return i.Clone(), nil + } + } } + itm, err = m.Items.Get(ctx, spaceId, envId, collectionId, itemId, options...) if err == nil { env, err := m.envs.Get(ctx, itm.SpaceID, itm.EnvID) if err != nil { - return nil, err + return nil, errors.Wrap(err, "get environment") } - m.cache.Set(makeKey(itm.SpaceID, env.ID, itm.CollectionID, itm.ID), itm) - for _, al := range env.Aliases { - m.cache.Set(makeKey(itm.SpaceID, al, itm.CollectionID, itm.ID), itm) + + // Сохраняем в кэш запись без Translations, поскольку значение из кэша также + // возвращается только если переводы не запрашиваются + itmCached := *itm + itmCached.Translations = nil + value[localeID] = &itmCached + for _, envID := range append(env.Aliases, env.ID) { + _ = m.cache.Set(makeKey(itm.SpaceID, envID, itm.CollectionID, itm.ID), value) } + return itm.Clone(), err } - return itm, err + + return nil, err } -func (m cachingMiddleware) Update(ctx context.Context, item *service.Item, options ...*service.UpdateOptions) (err error) { +func (m cachingMiddleware) invalidateCache(ctx context.Context, item *service.Item) (err error) { + env, err := m.envs.Get(ctx, item.SpaceID, item.EnvID) + if err != nil { + return errors.Wrap(err, "get environment") + } + for _, a := range append(env.Aliases, env.ID) { + key := makeKey(item.SpaceID, a, item.CollectionID, item.ID) + _ = m.cache.Remove(key) + _ = m.cachePublished.Remove(key) + } + return nil +} +// Update вызывает удаление всех сохраненных в кэше значений для записи: +// - Каждую из локализаций записи +// - С ключами, составленных из разных алиасов окружения +func (m cachingMiddleware) Update(ctx context.Context, item *service.Item, options ...*service.UpdateOptions) (err error) { err = m.Items.Update(ctx, item, options...) - if err == nil { - env, err := m.envs.Get(ctx, item.SpaceID, item.EnvID) - if err != nil { - return err - } - m.cache.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - for _, al := range env.Aliases { - m.cache.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - } + if err != nil { + return err } - return err + return m.invalidateCache(ctx, item) } func (m cachingMiddleware) Delete(ctx context.Context, del *service.Item, options ...*service.DeleteOptions) (err error) { - err = m.Items.Delete(ctx, del, options...) - if err == nil { - env, err := m.envs.Get(ctx, del.SpaceID, del.EnvID) - if err != nil { - return err - } - m.cache.Remove(makeKey(del.SpaceID, env.ID, del.CollectionID, del.ID)) - m.cachePublished.Remove(makeKey(del.SpaceID, env.ID, del.CollectionID, del.ID)) - for _, al := range env.Aliases { - m.cache.Remove(makeKey(del.SpaceID, al, del.CollectionID, del.ID)) - m.cachePublished.Remove(makeKey(del.SpaceID, al, del.CollectionID, del.ID)) - } - + if err != nil { + return err } - return err + return m.invalidateCache(ctx, del) } func (m cachingMiddleware) Publish(ctx context.Context, item *service.Item, options ...*service.PublishOptions) (err error) { - err = m.Items.Publish(ctx, item, options...) - if err == nil { - env, err := m.envs.Get(ctx, item.SpaceID, item.EnvID) - if err != nil { - return err - } - m.cache.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - for _, al := range env.Aliases { - m.cache.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - } + if err != nil { + return err } - return err + return m.invalidateCache(ctx, item) } func (m cachingMiddleware) Unpublish(ctx context.Context, item *service.Item, options ...*service.UnpublishOptions) (err error) { - err = m.Items.Unpublish(ctx, item, options...) - if err == nil { - env, err := m.envs.Get(ctx, item.SpaceID, item.EnvID) - if err != nil { - return err - } - m.cache.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - for _, al := range env.Aliases { - m.cache.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - } + if err != nil { + return err } - return err + return m.invalidateCache(ctx, item) } func (m cachingMiddleware) GetPublished(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*service.GetPublishedOptions) (itm *service.Item, err error) { - opts := service.MergeGetPublishedOptions(options...) + localeID := opts.LocaleID + if localeID == "" { + localeID = locales.DefaultID + } - val, e := m.cachePublished.Get(makeKey(spaceId, envId, collectionId, itemId)) - if e == nil { - value := val.(map[string]*service.Item) - if i, ok := value[opts.LocaleID]; ok { - return i, nil + // Значение из кэша можно достать только в случае, когда не запрашиваются переводы. Для + // списка переводов (`item.Translations`) кэш не предусмотрен: предполагается, что это + // нечастый запрос и содержание кэша с разными переводами себя не оправдывает + var value = make(map[string]*service.Item) + if len(opts.TranslationsIDs) == 0 { + val, e := m.cachePublished.Get(makeKey(spaceId, envId, collectionId, itemId)) + if e == nil { + value = val.(map[string]*service.Item) + if i, ok := value[localeID]; ok { + return i.Clone(), nil + } } } itm, err = m.Items.GetPublished(ctx, spaceId, envId, collectionId, itemId, opts) - if err == nil { env, err := m.envs.Get(ctx, itm.SpaceID, itm.EnvID) if err != nil { return nil, err } - var value = make(map[string]*service.Item) - if val != nil { - value = val.(map[string]*service.Item) - } - value[opts.LocaleID] = itm - m.cachePublished.Set(makeKey(itm.SpaceID, env.ID, itm.CollectionID, itm.ID), value) - for _, al := range env.Aliases { - m.cachePublished.Set(makeKey(itm.SpaceID, al, itm.CollectionID, itm.ID), value) + + // Сохраняем в кэш запись без Translations, поскольку значение из кэша также + // возвращается только если переводы не запрашиваются + itmCached := *itm + itmCached.Translations = nil + value[localeID] = &itmCached + for _, envID := range append(env.Aliases, env.ID) { + _ = m.cachePublished.Set(makeKey(itm.SpaceID, envID, itm.CollectionID, itm.ID), value) } + return itm.Clone(), err } - return itm, err + return nil, err } func (m cachingMiddleware) Archive(ctx context.Context, item *service.Item, options ...*service.ArchiveOptions) (err error) { - err = m.Items.Archive(ctx, item, options...) - if err == nil { - env, err := m.envs.Get(ctx, item.SpaceID, item.EnvID) - if err != nil { - return err - } - m.cache.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, env.ID, item.CollectionID, item.ID)) - for _, al := range env.Aliases { - m.cache.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - m.cachePublished.Remove(makeKey(item.SpaceID, al, item.CollectionID, item.ID)) - } + if err != nil { + return err } - return err + return m.invalidateCache(ctx, item) } diff --git a/pkg/items/middleware/caching_middleware_test.go b/pkg/items/middleware/caching_middleware_test.go index c3e862b1ffe3dd5e7fdde976cc4aa09e316a600f..4d777647788f290acf4e55550c435fa7ba27153a 100644 --- a/pkg/items/middleware/caching_middleware_test.go +++ b/pkg/items/middleware/caching_middleware_test.go @@ -47,10 +47,10 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша, при повторном запросе.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша, при повторном запросе.") v3, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) - assert.Same(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") + assert.Equal(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") require.NoError(t, err) env.AssertExpectations(t) @@ -71,10 +71,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша, при повторном запросе.") + assert.Equal(t, v1, v2, "Ожидается получение равного объекта из кеша при повторном запросе.") + assert.NotSame(t, v1, v2, "Создается копия объекта для хранения в кэше") v3, err := svc.Get(ctx, spaceID, envID, colID, itemID) - assert.Same(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") + assert.Equal(t, v3, v2, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") require.NoError(t, err) env.AssertExpectations(t) @@ -95,11 +96,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша, при запросе того же объекта по alias окружения.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -119,11 +120,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша, при запросе того же объекта по ID окружения.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -152,19 +153,19 @@ func TestItemsCache(t *testing.T) { v2loc1, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: loc1}) require.NoError(t, err) - assert.Same(t, v1loc1, v2loc1, "Ожидается получение объекта c локализацией loc1 из кеша.") + assert.Equal(t, v1loc1, v2loc1, "Ожидается получение объекта c локализацией loc1 из кеша.") v2loc2, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: loc2}) require.NoError(t, err) - assert.Same(t, v1loc2, v2loc2, "Ожидается получение объекта c локализацией loc2 из кеша.") + assert.Equal(t, v1loc2, v2loc2, "Ожидается получение объекта c локализацией loc2 из кеша.") v3loc1, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: loc1}) require.NoError(t, err) - assert.Same(t, v2loc1, v3loc1, "Ожидается получение объекта c локализацией loc1 из кеша, при запросе того же объекта по ID окружения.") + assert.Equal(t, v2loc1, v3loc1, "Ожидается получение объекта c локализацией loc1 из кеша, при запросе того же объекта по ID окружения.") v3loc2, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: loc2}) require.NoError(t, err) - assert.Same(t, v2loc2, v3loc2, "Ожидается получение объекта c локализацией loc2 из кеша, при запросе того же объекта по ID окружения.") + assert.Equal(t, v2loc2, v3loc2, "Ожидается получение объекта c локализацией loc2 из кеша, при запросе того же объекта по ID окружения.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -185,7 +186,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") itms.On("Update", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -198,7 +199,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кэша после обновления и получение его заново из сервиса.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кэша после обновления и получение его заново из сервиса.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -218,7 +219,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") itms.On("Archive", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -231,7 +232,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кэша после архивации и получение из сервиса.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кэша после архивации и получение из сервиса.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -251,7 +252,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") itms.On("Publish", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -263,7 +264,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кэша после публикации и получение заново из сервиса.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кэша после публикации и получение заново из сервиса.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -283,11 +284,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша при повторном запросе.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша при повторном запросе.") v3, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по alias окружения.") itms.On("Delete", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -323,7 +324,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() itms.On("Unpublish", mock.Anything, mock.Anything).Return(nil).Once() @@ -336,7 +337,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кэша после снятия с публикации и получение заново из сервиса.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кэша после снятия с публикации и получение заново из сервиса.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -356,7 +357,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по alias окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по alias окружения.") itms.On("Publish", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -389,7 +390,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по alias окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по alias окружения.") itms.On("Update", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -402,7 +403,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кэша при обновлении и получение из сервиса по alias окружения.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кэша при обновлении и получение из сервиса по alias окружения.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -422,7 +423,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша по alias окружения.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша по alias окружения.") itms.On("Unpublish", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -435,7 +436,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envAlias, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кэша после снятия с публикации и получение из сервиса по alias окружения.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кэша после снятия с публикации и получение из сервиса по alias окружения.") env.AssertExpectations(t) itms.AssertExpectations(t) @@ -455,11 +456,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") itms.On("Update", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -496,11 +497,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") itms.On("Archive", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -537,11 +538,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") itms.On("Delete", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -578,11 +579,11 @@ func TestItemsCache(t *testing.T) { v2, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кеша по о alias окружения.") itms.On("Unpublish", mock.Anything, mock.Anything).Return(nil).Once() env.On("Get", mock.Anything, spaceID, envID).Return(&environments.Environment{ID: envID, SpaceID: spaceID, Aliases: []string{envAlias}}, nil).Once() @@ -623,14 +624,14 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") v3, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) v4, err := svc.GetPublished(ctx, spaceID, envID, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.NoError(t, err) - assert.Same(t, v3, v4, "Ожидается получение опубликованного объекта из кеша.") + assert.Equal(t, v3, v4, "Ожидается получение опубликованного объекта из кеша.") itms.On("Unpublish", mock.Anything, mock.Anything).Return(nil).Once() err = svc.Unpublish(ctx, &items.Item{ID: itemID, SpaceID: spaceID, EnvID: envAlias, CollectionID: colID, State: items.StatePublished}) @@ -643,7 +644,7 @@ func TestItemsCache(t *testing.T) { v5, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.NotSame(t, v5, v2, "Ожидается удаление объекта из кэша и получение заново из сервиса.") + assert.NotEqual(t, v5, v2, "Ожидается удаление объекта из кэша и получение заново из сервиса.") _, err = svc.GetPublished(ctx, spaceID, envAlias, colID, itemID, &items.GetPublishedOptions{LocaleID: locID}) require.Error(t, err) @@ -667,7 +668,7 @@ func TestItemsCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кеша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кеша.") time.Sleep(2 * ttl) @@ -677,6 +678,7 @@ func TestItemsCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, envID, colID, itemID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается удаление объекта из кэша и получение из сервиса.") + assert.Equal(t, v2, v3) env.AssertExpectations(t) itms.AssertExpectations(t) diff --git a/pkg/items/middleware/logging_middleware.go b/pkg/items/middleware/logging_middleware.go index c8271c58dd1e0c09862bcad7b7c8f60817346a40..1178719ee2ad0190e12316165b2536de67f1324e 100644 --- a/pkg/items/middleware/logging_middleware.go +++ b/pkg/items/middleware/logging_middleware.go @@ -26,7 +26,7 @@ func LoggingMiddleware(logger *zap.Logger) Middleware { func (m *loggingMiddleware) Aggregate(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregateOptions) (result map[string]interface{}, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) result, err = m.next.Aggregate(ctx, spaceId, envId, collectionId, filter, options...) @@ -40,7 +40,7 @@ func (m *loggingMiddleware) Aggregate(ctx context.Context, spaceId string, envId func (m *loggingMiddleware) AggregatePublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) result, err = m.next.AggregatePublished(ctx, spaceId, envId, collectionId, filter, options...) @@ -58,7 +58,7 @@ func (m *loggingMiddleware) Archive(ctx context.Context, item *items.Item, optio spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventArchive), logzap.Object(item), ) @@ -79,7 +79,7 @@ func (m *loggingMiddleware) Create(ctx context.Context, item *items.Item, opts . spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventCreate), ) @@ -99,7 +99,7 @@ func (m *loggingMiddleware) Delete(ctx context.Context, item *items.Item, option spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventDelete), logzap.Object(item), ) @@ -116,7 +116,7 @@ func (m *loggingMiddleware) Delete(ctx context.Context, item *items.Item, option func (m *loggingMiddleware) Find(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindOptions) (items []*items.Item, total int, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) items, total, err = m.next.Find(ctx, spaceId, envId, collectionId, filter, options...) @@ -131,7 +131,7 @@ func (m *loggingMiddleware) Find(ctx context.Context, spaceId string, envId stri func (m *loggingMiddleware) FindArchived(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindArchivedOptions) (items []*items.Item, total int, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) items, total, err = m.next.FindArchived(ctx, spaceId, envId, collectionId, filter, options...) @@ -145,7 +145,7 @@ func (m *loggingMiddleware) FindArchived(ctx context.Context, spaceId string, en func (m *loggingMiddleware) FindPublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), ) items, total, err = m.next.FindPublished(ctx, spaceId, envId, collectionId, filter, options...) @@ -159,7 +159,7 @@ func (m *loggingMiddleware) FindPublished(ctx context.Context, spaceId string, e func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetOptions) (item *items.Item, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)), ) @@ -174,7 +174,7 @@ func (m *loggingMiddleware) Get(ctx context.Context, spaceId string, envId strin func (m *loggingMiddleware) GetPublished(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)), ) @@ -189,7 +189,7 @@ func (m *loggingMiddleware) GetPublished(ctx context.Context, spaceId string, en func (m *loggingMiddleware) GetRevision(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, revisionId string, options ...*items.GetRevisionOptions) (item *items.Item, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)), ) @@ -208,7 +208,7 @@ func (m *loggingMiddleware) Introspect(ctx context.Context, item *items.Item, op spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Object(item), ) @@ -223,7 +223,7 @@ func (m *loggingMiddleware) Introspect(ctx context.Context, item *items.Item, op func (m *loggingMiddleware) ListRevisions(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.ListRevisionsOptions) (items []*items.Item, err error) { logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceId), + logzap.Caller(ctx, logzap.WithSpace(spaceId)), logzap.Object(id.NewItemId(spaceId, envId, collectionId, itemId)), ) @@ -242,7 +242,7 @@ func (m *loggingMiddleware) Publish(ctx context.Context, item *items.Item, optio spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventPublish), logzap.Object(item), ) @@ -263,7 +263,7 @@ func (m *loggingMiddleware) Unarchive(ctx context.Context, item *items.Item, opt spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventUnarchive), logzap.Object(item), ) @@ -284,7 +284,7 @@ func (m *loggingMiddleware) Undelete(ctx context.Context, item *items.Item, opti spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventUndelete), logzap.Object(item), ) @@ -305,7 +305,7 @@ func (m *loggingMiddleware) Unpublish(ctx context.Context, item *items.Item, opt spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventUnpublish), logzap.Object(item), ) @@ -326,7 +326,7 @@ func (m *loggingMiddleware) Update(ctx context.Context, item *items.Item, option spaceID = item.SpaceID } logger := m.logger.With( - logzap.CallerFromContext(ctx, spaceID), + logzap.Caller(ctx, logzap.WithSpace(spaceID)), logzap.Event(items.EventUpdate), logzap.Object(item), ) diff --git a/pkg/items/mocks/Decoder.go b/pkg/items/mocks/Decoder.go index b1dbd9aa526cf4fe4a62d29f652c3e2a513924b3..fcc4d502ee3d57504560a69c35ebdea06460b595 100644 --- a/pkg/items/mocks/Decoder.go +++ b/pkg/items/mocks/Decoder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Decoder struct { func (_m *Decoder) Decode(value interface{}, item *items.Item) error { ret := _m.Called(value, item) + if len(ret) == 0 { + panic("no return value specified for Decode") + } + var r0 error if rf, ok := ret.Get(0).(func(interface{}, *items.Item) error); ok { r0 = rf(value, item) diff --git a/pkg/items/mocks/Encoder.go b/pkg/items/mocks/Encoder.go index c19203b2448930eb75e62195837a1b22cd9cfe42..cd2dd5c9762c84131974b6e612086ad61d3699f3 100644 --- a/pkg/items/mocks/Encoder.go +++ b/pkg/items/mocks/Encoder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Encoder struct { func (_m *Encoder) Encode(item *items.Item) (interface{}, error) { ret := _m.Called(item) + if len(ret) == 0 { + panic("no return value specified for Encode") + } + var r0 interface{} var r1 error if rf, ok := ret.Get(0).(func(*items.Item) (interface{}, error)); ok { diff --git a/pkg/items/mocks/ItemObserver.go b/pkg/items/mocks/ItemObserver.go index d826e04045f01e504200e742afa16e68181bc6c9..e3451e680e643ac49343830a4713b93d6ad174c6 100644 --- a/pkg/items/mocks/ItemObserver.go +++ b/pkg/items/mocks/ItemObserver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks diff --git a/pkg/items/mocks/ItemReadObserver.go b/pkg/items/mocks/ItemReadObserver.go index 212f09ad7a046086f1cc99230699a304ec2a9878..c6876a5a3aada6942bf07fdfdfcee35f626353c9 100644 --- a/pkg/items/mocks/ItemReadObserver.go +++ b/pkg/items/mocks/ItemReadObserver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type ItemReadObserver struct { func (_m *ItemReadObserver) OnPostFind(ctx context.Context, _a1 []*items.Item, total int) ([]*items.Item, int, error) { ret := _m.Called(ctx, _a1, total) + if len(ret) == 0 { + panic("no return value specified for OnPostFind") + } + var r0 []*items.Item var r1 int var r2 error @@ -51,6 +55,10 @@ func (_m *ItemReadObserver) OnPostFind(ctx context.Context, _a1 []*items.Item, t func (_m *ItemReadObserver) OnPostGet(ctx context.Context, item *items.Item) (*items.Item, error) { ret := _m.Called(ctx, item) + if len(ret) == 0 { + panic("no return value specified for OnPostGet") + } + var r0 *items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item) (*items.Item, error)); ok { @@ -77,6 +85,10 @@ func (_m *ItemReadObserver) OnPostGet(ctx context.Context, item *items.Item) (*i func (_m *ItemReadObserver) OnPreFind(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options *items.FindOptions) error { ret := _m.Called(ctx, spaceId, envId, collectionId, filter, options) + if len(ret) == 0 { + panic("no return value specified for OnPreFind") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *items.Filter, *items.FindOptions) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, filter, options) @@ -91,6 +103,10 @@ func (_m *ItemReadObserver) OnPreFind(ctx context.Context, spaceId string, envId func (_m *ItemReadObserver) OnPreGet(ctx context.Context, spaceId string, envId string, collectionId string, itemId string) error { ret := _m.Called(ctx, spaceId, envId, collectionId, itemId) + if len(ret) == 0 { + panic("no return value specified for OnPreGet") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId) diff --git a/pkg/items/mocks/Items.go b/pkg/items/mocks/Items.go index 9bbd8948668a7ec665fdefd2f5e086cb235d579d..e134822e2869693fa3801affac8660eb357cd70c 100644 --- a/pkg/items/mocks/Items.go +++ b/pkg/items/mocks/Items.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *Items) Aggregate(ctx context.Context, spaceId string, envId string, co _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Aggregate") + } + var r0 map[string]interface{} var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *items.Filter, ...*items.AggregateOptions) (map[string]interface{}, error)); ok { @@ -60,6 +64,10 @@ func (_m *Items) AggregatePublished(ctx context.Context, spaceId string, envId s _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for AggregatePublished") + } + var r0 map[string]interface{} var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *items.Filter, ...*items.AggregatePublishedOptions) (map[string]interface{}, error)); ok { @@ -93,6 +101,10 @@ func (_m *Items) Archive(ctx context.Context, item *items.Item, options ...*item _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Archive") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.ArchiveOptions) error); ok { r0 = rf(ctx, item, options...) @@ -114,6 +126,10 @@ func (_m *Items) Create(ctx context.Context, item *items.Item, opts ...*items.Cr _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 *items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.CreateOptions) (*items.Item, error)); ok { @@ -147,6 +163,10 @@ func (_m *Items) Delete(ctx context.Context, item *items.Item, options ...*items _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.DeleteOptions) error); ok { r0 = rf(ctx, item, options...) @@ -168,6 +188,10 @@ func (_m *Items) Find(ctx context.Context, spaceId string, envId string, collect _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Find") + } + var r0 []*items.Item var r1 int var r2 error @@ -208,6 +232,10 @@ func (_m *Items) FindArchived(ctx context.Context, spaceId string, envId string, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindArchived") + } + var r0 []*items.Item var r1 int var r2 error @@ -248,6 +276,10 @@ func (_m *Items) FindPublished(ctx context.Context, spaceId string, envId string _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindPublished") + } + var r0 []*items.Item var r1 int var r2 error @@ -288,6 +320,10 @@ func (_m *Items) Get(ctx context.Context, spaceId string, envId string, collecti _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.GetOptions) (*items.Item, error)); ok { @@ -321,6 +357,10 @@ func (_m *Items) GetPublished(ctx context.Context, spaceId string, envId string, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetPublished") + } + var r0 *items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.GetPublishedOptions) (*items.Item, error)); ok { @@ -354,6 +394,10 @@ func (_m *Items) GetRevision(ctx context.Context, spaceId string, envId string, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetRevision") + } + var r0 *items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string, ...*items.GetRevisionOptions) (*items.Item, error)); ok { @@ -387,6 +431,10 @@ func (_m *Items) Introspect(ctx context.Context, item *items.Item, opts ...*item _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Introspect") + } + var r0 *items.Item var r1 *schema.Schema var r2 error @@ -429,6 +477,10 @@ func (_m *Items) ListRevisions(ctx context.Context, spaceId string, envId string _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ListRevisions") + } + var r0 []*items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.ListRevisionsOptions) ([]*items.Item, error)); ok { @@ -462,6 +514,10 @@ func (_m *Items) Publish(ctx context.Context, item *items.Item, options ...*item _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Publish") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.PublishOptions) error); ok { r0 = rf(ctx, item, options...) @@ -483,6 +539,10 @@ func (_m *Items) Unarchive(ctx context.Context, item *items.Item, options ...*it _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Unarchive") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UnarchiveOptions) error); ok { r0 = rf(ctx, item, options...) @@ -504,6 +564,10 @@ func (_m *Items) Undelete(ctx context.Context, item *items.Item, options ...*ite _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Undelete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UndeleteOptions) error); ok { r0 = rf(ctx, item, options...) @@ -525,6 +589,10 @@ func (_m *Items) Unpublish(ctx context.Context, item *items.Item, options ...*it _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Unpublish") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UnpublishOptions) error); ok { r0 = rf(ctx, item, options...) @@ -546,6 +614,10 @@ func (_m *Items) Update(ctx context.Context, item *items.Item, options ...*items _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UpdateOptions) error); ok { r0 = rf(ctx, item, options...) diff --git a/pkg/items/mocks/Middleware.go b/pkg/items/mocks/Middleware.go index 1cde36c075701f58cd108a677fc73537cf25bf52..0bebef848868bd06d6539b5159f5973f6a39315e 100644 --- a/pkg/items/mocks/Middleware.go +++ b/pkg/items/mocks/Middleware.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Middleware struct { func (_m *Middleware) Execute(_a0 items.Items) items.Items { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Execute") + } + var r0 items.Items if rf, ok := ret.Get(0).(func(items.Items) items.Items); ok { r0 = rf(_a0) diff --git a/pkg/items/mocks/PreSaver.go b/pkg/items/mocks/PreSaver.go index 729c1ebfc4e7e60e2920b082e22f35617bf22e4e..3acc32732fcea3df459a5234fb5c952e823edfaa 100644 --- a/pkg/items/mocks/PreSaver.go +++ b/pkg/items/mocks/PreSaver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type PreSaver struct { func (_m *PreSaver) PreSave(ctx context.Context, f *field.Field, v interface{}, itemCtx *items.Context) (interface{}, bool, error) { ret := _m.Called(ctx, f, v, itemCtx) + if len(ret) == 0 { + panic("no return value specified for PreSave") + } + var r0 interface{} var r1 bool var r2 error diff --git a/pkg/items/mocks/ProcessDataFunc.go b/pkg/items/mocks/ProcessDataFunc.go index 6ba38c984c7bba69461acc206393ebb66ba1cc07..7689da0df40591ba68ca8a6eb3a160d475a81c90 100644 --- a/pkg/items/mocks/ProcessDataFunc.go +++ b/pkg/items/mocks/ProcessDataFunc.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type ProcessDataFunc struct { func (_m *ProcessDataFunc) Execute(ctx context.Context, sch *schema.Schema, data map[string]interface{}) (map[string]interface{}, error) { ret := _m.Called(ctx, sch, data) + if len(ret) == 0 { + panic("no return value specified for Execute") + } + var r0 map[string]interface{} var r1 error if rf, ok := ret.Get(0).(func(context.Context, *schema.Schema, map[string]interface{}) (map[string]interface{}, error)); ok { diff --git a/pkg/items/mocks/Storage.go b/pkg/items/mocks/Storage.go index 6f8082b98690dab97058c6775f3a53c2c655c80f..4ce04d02d6985f5e4da86137d74763999da02136 100644 --- a/pkg/items/mocks/Storage.go +++ b/pkg/items/mocks/Storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.33.3. DO NOT EDIT. +// Code generated by mockery v2.45.0. DO NOT EDIT. package mocks @@ -9,6 +9,8 @@ import ( items "git.perx.ru/perxis/perxis-go/pkg/items" + locales "git.perx.ru/perxis/perxis-go/pkg/locales" + mock "github.com/stretchr/testify/mock" ) @@ -28,6 +30,10 @@ func (_m *Storage) Aggregate(ctx context.Context, coll *collections.Collection, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Aggregate") + } + var r0 map[string]interface{} var r1 error if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.AggregateOptions) (map[string]interface{}, error)); ok { @@ -61,6 +67,10 @@ func (_m *Storage) AggregatePublished(ctx context.Context, coll *collections.Col _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for AggregatePublished") + } + var r0 map[string]interface{} var r1 error if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.AggregatePublishedOptions) (map[string]interface{}, error)); ok { @@ -94,6 +104,10 @@ func (_m *Storage) Archive(ctx context.Context, archived *items.Item, options .. _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Archive") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.ArchiveOptions) error); ok { r0 = rf(ctx, archived, options...) @@ -108,6 +122,10 @@ func (_m *Storage) Archive(ctx context.Context, archived *items.Item, options .. func (_m *Storage) ChangeRevisionsItemID(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, newItemId string) error { ret := _m.Called(ctx, spaceId, envId, collectionId, itemId, newItemId) + if len(ret) == 0 { + panic("no return value specified for ChangeRevisionsItemID") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId, newItemId) @@ -118,6 +136,24 @@ func (_m *Storage) ChangeRevisionsItemID(ctx context.Context, spaceId string, en return r0 } +// CleanUpRevisions provides a mock function with given fields: ctx, coll, itemId +func (_m *Storage) CleanUpRevisions(ctx context.Context, coll *collections.Collection, itemId string) error { + ret := _m.Called(ctx, coll, itemId) + + if len(ret) == 0 { + panic("no return value specified for CleanUpRevisions") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string) error); ok { + r0 = rf(ctx, coll, itemId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Copy provides a mock function with given fields: ctx, src, dst, itemSets func (_m *Storage) Copy(ctx context.Context, src *collections.Collection, dst *collections.Collection, itemSets ...string) error { _va := make([]interface{}, len(itemSets)) @@ -129,6 +165,10 @@ func (_m *Storage) Copy(ctx context.Context, src *collections.Collection, dst *c _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Copy") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *collections.Collection, ...string) error); ok { r0 = rf(ctx, src, dst, itemSets...) @@ -150,6 +190,10 @@ func (_m *Storage) Create(ctx context.Context, coll *collections.Collection, ite _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 *items.Item var r1 error if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Item, ...*items.CreateOptions) (*items.Item, error)); ok { @@ -176,6 +220,10 @@ func (_m *Storage) Create(ctx context.Context, coll *collections.Collection, ite func (_m *Storage) CreateRevision(ctx context.Context, spaceId string, envId string, collectionId string, itemId string) error { ret := _m.Called(ctx, spaceId, envId, collectionId, itemId) + if len(ret) == 0 { + panic("no return value specified for CreateRevision") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId) @@ -187,7 +235,7 @@ func (_m *Storage) CreateRevision(ctx context.Context, spaceId string, envId str } // Find provides a mock function with given fields: ctx, coll, filter, opts -func (_m *Storage) Find(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.FindOptions) ([]*items.Item, int, error) { +func (_m *Storage) Find(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.StorageFindOptions) ([]*items.Item, int, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -197,13 +245,17 @@ func (_m *Storage) Find(ctx context.Context, coll *collections.Collection, filte _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Find") + } + var r0 []*items.Item var r1 int var r2 error - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) ([]*items.Item, int, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) ([]*items.Item, int, error)); ok { return rf(ctx, coll, filter, opts...) } - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) []*items.Item); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) []*items.Item); ok { r0 = rf(ctx, coll, filter, opts...) } else { if ret.Get(0) != nil { @@ -211,13 +263,13 @@ func (_m *Storage) Find(ctx context.Context, coll *collections.Collection, filte } } - if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) int); ok { + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) int); ok { r1 = rf(ctx, coll, filter, opts...) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindOptions) error); ok { + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) error); ok { r2 = rf(ctx, coll, filter, opts...) } else { r2 = ret.Error(2) @@ -227,7 +279,7 @@ func (_m *Storage) Find(ctx context.Context, coll *collections.Collection, filte } // FindArchived provides a mock function with given fields: ctx, coll, filter, opts -func (_m *Storage) FindArchived(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.FindArchivedOptions) ([]*items.Item, int, error) { +func (_m *Storage) FindArchived(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.StorageFindOptions) ([]*items.Item, int, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -237,13 +289,17 @@ func (_m *Storage) FindArchived(ctx context.Context, coll *collections.Collectio _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindArchived") + } + var r0 []*items.Item var r1 int var r2 error - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) ([]*items.Item, int, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) ([]*items.Item, int, error)); ok { return rf(ctx, coll, filter, opts...) } - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) []*items.Item); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) []*items.Item); ok { r0 = rf(ctx, coll, filter, opts...) } else { if ret.Get(0) != nil { @@ -251,13 +307,13 @@ func (_m *Storage) FindArchived(ctx context.Context, coll *collections.Collectio } } - if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) int); ok { + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) int); ok { r1 = rf(ctx, coll, filter, opts...) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindArchivedOptions) error); ok { + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) error); ok { r2 = rf(ctx, coll, filter, opts...) } else { r2 = ret.Error(2) @@ -267,7 +323,7 @@ func (_m *Storage) FindArchived(ctx context.Context, coll *collections.Collectio } // FindPublished provides a mock function with given fields: ctx, coll, filter, opts -func (_m *Storage) FindPublished(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.FindPublishedOptions) ([]*items.Item, int, error) { +func (_m *Storage) FindPublished(ctx context.Context, coll *collections.Collection, filter *items.Filter, opts ...*items.StorageFindOptions) ([]*items.Item, int, error) { _va := make([]interface{}, len(opts)) for _i := range opts { _va[_i] = opts[_i] @@ -277,13 +333,17 @@ func (_m *Storage) FindPublished(ctx context.Context, coll *collections.Collecti _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindPublished") + } + var r0 []*items.Item var r1 int var r2 error - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) ([]*items.Item, int, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) ([]*items.Item, int, error)); ok { return rf(ctx, coll, filter, opts...) } - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) []*items.Item); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) []*items.Item); ok { r0 = rf(ctx, coll, filter, opts...) } else { if ret.Get(0) != nil { @@ -291,13 +351,13 @@ func (_m *Storage) FindPublished(ctx context.Context, coll *collections.Collecti } } - if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) int); ok { + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) int); ok { r1 = rf(ctx, coll, filter, opts...) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.FindPublishedOptions) error); ok { + if rf, ok := ret.Get(2).(func(context.Context, *collections.Collection, *items.Filter, ...*items.StorageFindOptions) error); ok { r2 = rf(ctx, coll, filter, opts...) } else { r2 = ret.Error(2) @@ -307,7 +367,7 @@ func (_m *Storage) FindPublished(ctx context.Context, coll *collections.Collecti } // GetRevision provides a mock function with given fields: ctx, coll, itemId, revisionId, options -func (_m *Storage) GetRevision(ctx context.Context, coll *collections.Collection, itemId string, revisionId string, options ...*items.GetRevisionOptions) (*items.Item, error) { +func (_m *Storage) GetRevision(ctx context.Context, coll *collections.Collection, itemId string, revisionId string, options ...*items.StorageFindOptions) (*items.Item, error) { _va := make([]interface{}, len(options)) for _i := range options { _va[_i] = options[_i] @@ -317,12 +377,16 @@ func (_m *Storage) GetRevision(ctx context.Context, coll *collections.Collection _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetRevision") + } + var r0 *items.Item var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, string, ...*items.GetRevisionOptions) (*items.Item, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, string, ...*items.StorageFindOptions) (*items.Item, error)); ok { return rf(ctx, coll, itemId, revisionId, options...) } - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, string, ...*items.GetRevisionOptions) *items.Item); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, string, ...*items.StorageFindOptions) *items.Item); ok { r0 = rf(ctx, coll, itemId, revisionId, options...) } else { if ret.Get(0) != nil { @@ -330,7 +394,7 @@ func (_m *Storage) GetRevision(ctx context.Context, coll *collections.Collection } } - if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, string, string, ...*items.GetRevisionOptions) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, string, string, ...*items.StorageFindOptions) error); ok { r1 = rf(ctx, coll, itemId, revisionId, options...) } else { r1 = ret.Error(1) @@ -339,13 +403,24 @@ func (_m *Storage) GetRevision(ctx context.Context, coll *collections.Collection return r0, r1 } -// Init provides a mock function with given fields: ctx, collection -func (_m *Storage) Init(ctx context.Context, collection *collections.Collection) error { - ret := _m.Called(ctx, collection) +// Init provides a mock function with given fields: ctx, collection, _a2 +func (_m *Storage) Init(ctx context.Context, collection *collections.Collection, _a2 ...*locales.Locale) error { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, collection) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Init") + } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection) error); ok { - r0 = rf(ctx, collection) + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, ...*locales.Locale) error); ok { + r0 = rf(ctx, collection, _a2...) } else { r0 = ret.Error(0) } @@ -354,7 +429,7 @@ func (_m *Storage) Init(ctx context.Context, collection *collections.Collection) } // ListRevisions provides a mock function with given fields: ctx, coll, itemId, options -func (_m *Storage) ListRevisions(ctx context.Context, coll *collections.Collection, itemId string, options ...*items.ListRevisionsOptions) ([]*items.Item, error) { +func (_m *Storage) ListRevisions(ctx context.Context, coll *collections.Collection, itemId string, options ...*items.StorageFindOptions) ([]*items.Item, error) { _va := make([]interface{}, len(options)) for _i := range options { _va[_i] = options[_i] @@ -364,12 +439,16 @@ func (_m *Storage) ListRevisions(ctx context.Context, coll *collections.Collecti _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ListRevisions") + } + var r0 []*items.Item var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, ...*items.ListRevisionsOptions) ([]*items.Item, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, ...*items.StorageFindOptions) ([]*items.Item, error)); ok { return rf(ctx, coll, itemId, options...) } - if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, ...*items.ListRevisionsOptions) []*items.Item); ok { + if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, string, ...*items.StorageFindOptions) []*items.Item); ok { r0 = rf(ctx, coll, itemId, options...) } else { if ret.Get(0) != nil { @@ -377,7 +456,7 @@ func (_m *Storage) ListRevisions(ctx context.Context, coll *collections.Collecti } } - if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, string, ...*items.ListRevisionsOptions) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *collections.Collection, string, ...*items.StorageFindOptions) error); ok { r1 = rf(ctx, coll, itemId, options...) } else { r1 = ret.Error(1) @@ -397,6 +476,10 @@ func (_m *Storage) Publish(ctx context.Context, published *items.Item, options . _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Publish") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.PublishOptions) error); ok { r0 = rf(ctx, published, options...) @@ -418,6 +501,10 @@ func (_m *Storage) RemoveArchived(ctx context.Context, spaceId string, envId str _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RemoveArchived") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) @@ -439,6 +526,10 @@ func (_m *Storage) RemoveItems(ctx context.Context, spaceId string, envId string _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RemoveItems") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) @@ -460,6 +551,10 @@ func (_m *Storage) RemovePublished(ctx context.Context, spaceId string, envId st _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RemovePublished") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) @@ -481,6 +576,10 @@ func (_m *Storage) RemoveRevision(ctx context.Context, spaceId string, envId str _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RemoveRevision") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, revision, options...) @@ -502,6 +601,10 @@ func (_m *Storage) RemoveRevisions(ctx context.Context, spaceId string, envId st _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RemoveRevisions") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, ...*items.DeleteOptions) error); ok { r0 = rf(ctx, spaceId, envId, collectionId, itemId, options...) @@ -516,6 +619,10 @@ func (_m *Storage) RemoveRevisions(ctx context.Context, spaceId string, envId st func (_m *Storage) Reset(ctx context.Context, spaceId string, envId string, collectionId string) error { ret := _m.Called(ctx, spaceId, envId, collectionId) + if len(ret) == 0 { + panic("no return value specified for Reset") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { r0 = rf(ctx, spaceId, envId, collectionId) @@ -537,6 +644,10 @@ func (_m *Storage) Unarchive(ctx context.Context, unarchived *items.Item, option _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Unarchive") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UnarchiveOptions) error); ok { r0 = rf(ctx, unarchived, options...) @@ -558,6 +669,10 @@ func (_m *Storage) Unpublish(ctx context.Context, unpublished *items.Item, optio _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Unpublish") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *items.Item, ...*items.UnpublishOptions) error); ok { r0 = rf(ctx, unpublished, options...) @@ -579,6 +694,10 @@ func (_m *Storage) Update(ctx context.Context, coll *collections.Collection, ite _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *collections.Collection, *items.Item, ...*items.UpdateOptions) error); ok { r0 = rf(ctx, coll, item, options...) diff --git a/pkg/items/options.go b/pkg/items/options.go index 6794ddde79a864ac58188d8fd3cc600cbb18cd10..cdd98918d3e35a09f2d2fe2d9971781013bace1e 100644 --- a/pkg/items/options.go +++ b/pkg/items/options.go @@ -1,6 +1,12 @@ package items -import "git.perx.ru/perxis/perxis-go/pkg/options" +import ( + "maps" + "slices" + + "git.perx.ru/perxis/perxis-go/pkg/options" + pb "git.perx.ru/perxis/perxis-go/proto/items" +) type Options struct { Env map[string]interface{} @@ -50,9 +56,27 @@ func MergeCreateOptions(opts ...*CreateOptions) *CreateOptions { return o } +func CreateOptionsToProto(opts ...*CreateOptions) *pb.CreateOptions { + if opts == nil { + return nil + } + o := MergeCreateOptions(opts...) + return &pb.CreateOptions{ + UpdateAttrs: o.UpdateAttrs, + } +} + +func CreateOptionsFromProto(opts *pb.CreateOptions) *CreateOptions { + if opts == nil { + return nil + } + return &CreateOptions{ + UpdateAttrs: opts.UpdateAttrs, + } +} + type IntrospectOptions struct { Options - Locale string } type IntrospectOptionsFn func(*IntrospectOptions) *IntrospectOptions @@ -70,6 +94,12 @@ func MergeIntrospectOptions(opts ...*IntrospectOptions) *IntrospectOptions { type GetOptions struct { Options + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string } type GetOptionsFn func(*GetOptions) *GetOptions @@ -81,17 +111,49 @@ func MergeGetOptions(opts ...*GetOptions) *GetOptions { continue } o.Options = MergeOptions(o.Options, opt.Options) + if opt.LocaleID != "" { + o.LocaleID = opt.LocaleID + } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) } return o } +func GetOptionsToProto(opts ...*GetOptions) *pb.GetOptions { + if opts == nil { + return nil + } + o := MergeGetOptions(opts...) + return &pb.GetOptions{ + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + } +} + +func GetOptionsFromProto(opts *pb.GetOptions) *GetOptions { + if opts == nil { + return nil + } + return &GetOptions{ + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } +} + type FindOptions struct { Options options.FindOptions + Deleted bool Regular bool Hidden bool Templates bool + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string } type FindOptionsFn func(*FindOptions) *FindOptions @@ -114,6 +176,44 @@ func MergeFindOptions(opts ...*FindOptions) *FindOptions { o.Deleted = o.Deleted || opt.Deleted o.Options = MergeOptions(o.Options, opt.Options) o.FindOptions = *options.MergeFindOptions(&o.FindOptions, &opt.FindOptions) + if opt.LocaleID != "" { + o.LocaleID = opt.LocaleID + } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + } + return o +} + +func FindOptionsToProto(opts ...*FindOptions) *pb.FindOptions { + if opts == nil { + return nil + } + o := MergeFindOptions(opts...) + return &pb.FindOptions{ + Deleted: o.Deleted, + Regular: o.Regular, + Hidden: o.Hidden, + Templates: o.Templates, + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + Options: options.FindOptionsToPB(&o.FindOptions), + } +} + +func FindOptionsFromProto(opts *pb.FindOptions) *FindOptions { + if opts == nil { + return nil + } + o := &FindOptions{ + Deleted: opts.Deleted, + Regular: opts.Regular, + Hidden: opts.Hidden, + Templates: opts.Templates, + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } + if fo := options.FindOptionsFromPB(opts.Options); fo != nil { + o.FindOptions = *fo } return o } @@ -141,6 +241,25 @@ func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions { return o } +func UpdateOptionsToProto(opts ...*UpdateOptions) *pb.UpdateOptions { + if opts == nil { + return nil + } + o := MergeUpdateOptions(opts...) + return &pb.UpdateOptions{ + UpdateAttrs: o.UpdateAttrs, + } +} + +func UpdateOptionsFromProto(opts *pb.UpdateOptions) *UpdateOptions { + if opts == nil { + return nil + } + return &UpdateOptions{ + UpdateAttrs: opts.UpdateAttrs, + } +} + type DeleteOptions struct { Options @@ -168,6 +287,27 @@ func MergeDeleteOptions(options ...*DeleteOptions) *DeleteOptions { return o } +func DeleteOptionsToProto(opts ...*DeleteOptions) *pb.DeleteOptions { + if opts == nil { + return nil + } + o := MergeDeleteOptions(opts...) + return &pb.DeleteOptions{ + UpdateAttrs: o.UpdateAttrs, + Erase: o.Erase, + } +} + +func DeleteOptionsFromProto(opts *pb.DeleteOptions) *DeleteOptions { + if opts == nil { + return nil + } + return &DeleteOptions{ + UpdateAttrs: opts.UpdateAttrs, + Erase: opts.Erase, + } +} + type SoftDeleteOptions struct { Options } @@ -254,7 +394,20 @@ func MergeUnpublishOptions(opts ...*UnpublishOptions) *UnpublishOptions { type GetPublishedOptions struct { Options + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string +} + +func (opts *GetPublishedOptions) ToGetOptions() *GetOptions { + return &GetOptions{ + Options: MergeOptions(opts.Options), + LocaleID: opts.LocaleID, + TranslationsIDs: slices.Clone(opts.TranslationsIDs), + } } type GetPublishedOptionsFn func(*GetPublishedOptions) *GetPublishedOptions @@ -265,6 +418,8 @@ func NewGetPublishedOptions(oo ...interface{}) *GetPublishedOptions { switch o := o.(type) { case string: fo.LocaleID = o + case []string: + fo.TranslationsIDs = o } } return fo @@ -280,17 +435,59 @@ func MergeGetPublishedOptions(opts ...*GetPublishedOptions) *GetPublishedOptions if opt.LocaleID != "" { o.LocaleID = opt.LocaleID } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) } return o } +func GetPublishedOptionsToProto(opts ...*GetPublishedOptions) *pb.GetPublishedOptions { + if opts == nil { + return nil + } + o := MergeGetPublishedOptions(opts...) + return &pb.GetPublishedOptions{ + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + } +} + +func GetPublishedOptionsFromProto(opts *pb.GetPublishedOptions) *GetPublishedOptions { + if opts == nil { + return nil + } + return &GetPublishedOptions{ + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } +} + type FindPublishedOptions struct { Options options.FindOptions - LocaleID string + + Deleted bool Regular bool Hidden bool Templates bool + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string +} + +func (opts *FindPublishedOptions) ToFindOptions() *FindOptions { + return &FindOptions{ + Options: MergeOptions(opts.Options), + FindOptions: *options.MergeFindOptions(opts.FindOptions), + Deleted: opts.Deleted, + Regular: opts.Regular, + Hidden: opts.Hidden, + Templates: opts.Templates, + LocaleID: opts.LocaleID, + TranslationsIDs: slices.Clone(opts.TranslationsIDs), + } } func NewFindPublishedOptions(opts ...interface{}) *FindPublishedOptions { @@ -321,12 +518,51 @@ func MergeFindPublishedOptions(opts ...*FindPublishedOptions) *FindPublishedOpti if opt.LocaleID != "" { o.LocaleID = opt.LocaleID } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + } + return o +} + +func FindPublishedOptionsToProto(opts ...*FindPublishedOptions) *pb.FindPublishedOptions { + if opts == nil { + return nil + } + o := MergeFindPublishedOptions(opts...) + return &pb.FindPublishedOptions{ + Regular: o.Regular, + Hidden: o.Hidden, + Templates: o.Templates, + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + Options: options.FindOptionsToPB(&o.FindOptions), + } +} + +func FindPublishedOptionsFromProto(opts *pb.FindPublishedOptions) *FindPublishedOptions { + if opts == nil { + return nil + } + o := &FindPublishedOptions{ + Regular: opts.Regular, + Hidden: opts.Hidden, + Templates: opts.Templates, + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } + if fo := options.FindOptionsFromPB(opts.Options); fo != nil { + o.FindOptions = *fo } return o } type GetRevisionOptions struct { Options + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string } func MergeGetRevisionOptions(opts ...*GetRevisionOptions) *GetRevisionOptions { @@ -336,6 +572,33 @@ func MergeGetRevisionOptions(opts ...*GetRevisionOptions) *GetRevisionOptions { continue } o.Options = MergeOptions(o.Options, opt.Options) + + if opt.LocaleID != "" { + o.LocaleID = opt.LocaleID + } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + } + return o +} + +func GetRevisionOptionsToProto(opts ...*GetRevisionOptions) *pb.GetRevisionOptions { + if opts == nil { + return nil + } + o := MergeGetRevisionOptions(opts...) + return &pb.GetRevisionOptions{ + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + } +} + +func GetRevisionOptionsFromProto(opts *pb.GetRevisionOptions) *GetRevisionOptions { + if opts == nil { + return nil + } + o := &GetRevisionOptions{ + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, } return o } @@ -343,6 +606,12 @@ func MergeGetRevisionOptions(opts ...*GetRevisionOptions) *GetRevisionOptions { type ListRevisionsOptions struct { Options options.FindOptions + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string } func MergeListRevisionsOptions(opts ...*ListRevisionsOptions) *ListRevisionsOptions { @@ -353,6 +622,37 @@ func MergeListRevisionsOptions(opts ...*ListRevisionsOptions) *ListRevisionsOpti } o.Options = MergeOptions(o.Options, opt.Options) o.FindOptions = *options.MergeFindOptions(&o.FindOptions, &opt.FindOptions) + + if opt.LocaleID != "" { + o.LocaleID = opt.LocaleID + } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + } + return o +} + +func ListRevisionsOptionsToProto(opts ...*ListRevisionsOptions) *pb.ListRevisionsOptions { + if opts == nil { + return nil + } + o := MergeListRevisionsOptions(opts...) + return &pb.ListRevisionsOptions{ + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + Options: options.FindOptionsToPB(&o.FindOptions), + } +} + +func ListRevisionsOptionsFromProto(opts *pb.ListRevisionsOptions) *ListRevisionsOptions { + if opts == nil { + return nil + } + o := &ListRevisionsOptions{ + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } + if fo := options.FindOptionsFromPB(opts.Options); fo != nil { + o.FindOptions = *fo } return o } @@ -375,6 +675,12 @@ func MergeArchiveOptions(opts ...*ArchiveOptions) *ArchiveOptions { type FindArchivedOptions struct { Options options.FindOptions + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string } func NewFindArchivedOptions(oo ...interface{}) *FindArchivedOptions { @@ -391,6 +697,37 @@ func MergeFindArchivedOptions(opts ...*FindArchivedOptions) *FindArchivedOptions } o.Options = MergeOptions(o.Options, opt.Options) o.FindOptions = *options.MergeFindOptions(o.FindOptions, opt.FindOptions) + + if opt.LocaleID != "" { + o.LocaleID = opt.LocaleID + } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + } + return o +} + +func FindArchivedOptionsToProto(opts ...*FindArchivedOptions) *pb.FindArchivedOptions { + if opts == nil { + return nil + } + o := MergeFindArchivedOptions(opts...) + return &pb.FindArchivedOptions{ + LocaleId: o.LocaleID, + TranslationsIds: o.TranslationsIDs, + Options: options.FindOptionsToPB(&o.FindOptions), + } +} + +func FindArchivedOptionsFromProto(opts *pb.FindArchivedOptions) *FindArchivedOptions { + if opts == nil { + return nil + } + o := &FindArchivedOptions{ + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } + if fo := options.FindOptionsFromPB(opts.Options); fo != nil { + o.FindOptions = *fo } return o } @@ -448,6 +785,14 @@ func MergeAggregateOptions(opts ...*AggregateOptions) *AggregateOptions { type AggregatePublishedOptions AggregateOptions +func (opts *AggregatePublishedOptions) ToAggregateOptions() *AggregateOptions { + return &AggregateOptions{ + Options: MergeOptions(opts.Options), + SortOptions: options.MergeSortOptions(opts.SortOptions), + Fields: maps.Clone(opts.Fields), + } +} + func MergeAggregatePublishedOptions(opts ...*AggregatePublishedOptions) *AggregatePublishedOptions { ao := make([]*AggregateOptions, len(opts)) for i, opt := range opts { diff --git a/pkg/items/pagination.go b/pkg/items/pagination.go index c8c4bb16d2da0d2d10e3d98422aaf345ffbf7c21..73a5ae9ac8e3431e332b2c1de9b56c66c78fc503 100644 --- a/pkg/items/pagination.go +++ b/pkg/items/pagination.go @@ -27,33 +27,26 @@ func (b *BatchProcessor) getBatch(ctx context.Context) ([]*Item, bool, error) { var total int if b.FindPublishedOptions != nil { + opts := *b.FindPublishedOptions + opts.FindOptions = *options.New(b.processed, b.limit, b.sort...) res, total, err = b.Items.FindPublished( ctx, b.SpaceID, b.EnvID, b.CollectionID, b.Filter, - &FindPublishedOptions{ - Regular: b.FindPublishedOptions.Regular, - Hidden: b.FindPublishedOptions.Hidden, - Templates: b.FindPublishedOptions.Templates, - FindOptions: *options.New(b.processed, b.limit, b.sort...), - }, + &opts, ) } else { + opts := *b.FindOptions + opts.FindOptions = *options.New(b.processed, b.limit, b.sort...) res, total, err = b.Items.Find( ctx, b.SpaceID, b.EnvID, b.CollectionID, b.Filter, - &FindOptions{ - Deleted: b.FindOptions.Deleted, - Regular: b.FindOptions.Regular, - Hidden: b.FindOptions.Hidden, - Templates: b.FindOptions.Templates, - FindOptions: *options.New(b.processed, b.limit, b.sort...), - }, + &opts, ) } diff --git a/pkg/items/pagination_test.go b/pkg/items/pagination_test.go index 008b17795cc1c57d4e2dcf6bb3507bee8b3f1646..23d484b83e3e21ec3ee7b5f93477ea9d9a9b7cee 100644 --- a/pkg/items/pagination_test.go +++ b/pkg/items/pagination_test.go @@ -5,6 +5,7 @@ import ( "testing" "git.perx.ru/perxis/perxis-go/pkg/environments" + "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/options" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -58,4 +59,39 @@ func TestBatchProcessor(t *testing.T) { require.NoError(t, err) assert.Equal(t, 1000/25, counter) }) + + t.Run("With FindOptions2", func(t *testing.T) { + + f := &FindOptions{ + Deleted: true, + Hidden: true, + Regular: true, + Templates: true, + TranslationsIDs: []string{"*"}, + LocaleID: "en", + } + + itemssvc := &Stub{ + FindResult: func(req StubFindRequest) StubFindResult { + fo := req.Options[0] + if !assert.Equal(t, f, fo) { + return StubFindResult{Items: nil, Total: 0, Error: errors.New("FindOptions not equal")} + } + return StubFindResult{Items: make([]*Item, fo.Limit), Total: 25, Error: nil} + }, + } + + f.FindOptions = *options.New(0, 25) + b := &BatchProcessor{ + Items: itemssvc, + SpaceID: "sp", + EnvID: environments.DefaultEnvironment, + CollectionID: "col", + FindOptions: f, + } + + var counter int + _, err := b.Do(context.Background(), func(batch []*Item) error { counter++; return nil }) + require.NoError(t, err) + }) } diff --git a/pkg/items/storage.go b/pkg/items/storage.go index 64548a009369fad6e74530e2ae5f52dd013e7997..f673e92290e22cd3ab28f25f1b1d5d35ad84bdde 100644 --- a/pkg/items/storage.go +++ b/pkg/items/storage.go @@ -4,6 +4,7 @@ import ( "context" "git.perx.ru/perxis/perxis-go/pkg/collections" + "git.perx.ru/perxis/perxis-go/pkg/locales" ) type Storage interface { @@ -31,17 +32,17 @@ type Storage interface { // CreateRevision - перенести ревизию в коллекцию Revisions CreateRevision(ctx context.Context, spaceId, envId, collectionId, itemId string) error - // Update - Обновление текущей ревизии или создание новой, если в опциях передан флаг `ReplacePublishedRevision` + // Update - Обновление текущей ревизии Update(ctx context.Context, coll *collections.Collection, item *Item, options ...*UpdateOptions) error // Find - поиск записей по рабочим записям, коллекция 'items' - Find(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*FindOptions) ([]*Item, int, error) + Find(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*StorageFindOptions) ([]*Item, int, error) // GetRevision - поиск одной ревизии одной записи - GetRevision(ctx context.Context, coll *collections.Collection, itemId, revisionId string, options ...*GetRevisionOptions) (*Item, error) + GetRevision(ctx context.Context, coll *collections.Collection, itemId, revisionId string, options ...*StorageFindOptions) (*Item, error) // ListRevisions - поиск всех ревизий одной записи - ListRevisions(ctx context.Context, coll *collections.Collection, itemId string, options ...*ListRevisionsOptions) ([]*Item, error) + ListRevisions(ctx context.Context, coll *collections.Collection, itemId string, options ...*StorageFindOptions) ([]*Item, error) // ChangeRevisionsItemID - заменить ID элемента у его ревизий ChangeRevisionsItemID(ctx context.Context, spaceId, envId, collectionId, itemId, newItemId string) error @@ -53,7 +54,7 @@ type Storage interface { Unpublish(ctx context.Context, unpublished *Item, options ...*UnpublishOptions) error // FindPublished - поиск по опубликованным записям, коллекция 'items_published' - FindPublished(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*FindPublishedOptions) ([]*Item, int, error) + FindPublished(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*StorageFindOptions) ([]*Item, int, error) // Archive - архивация записи Archive(ctx context.Context, archived *Item, options ...*ArchiveOptions) error @@ -62,7 +63,7 @@ type Storage interface { Unarchive(ctx context.Context, unarchived *Item, options ...*UnarchiveOptions) error // FindArchived - поиск по архивированным записям, коллекция 'items_archived' - FindArchived(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*FindArchivedOptions) ([]*Item, int, error) + FindArchived(ctx context.Context, coll *collections.Collection, filter *Filter, opts ...*StorageFindOptions) ([]*Item, int, error) // RemoveItems - удаление записи из коллекций Items RemoveItems(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error @@ -70,6 +71,9 @@ type Storage interface { // RemovePublished - удаление записи из коллекций Published RemovePublished(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error + // CleanUpRevisions - очистка ревизий элемента, согласно настройкам лимитов для ревизий в коллекции + CleanUpRevisions(ctx context.Context, coll *collections.Collection, itemId string) error + // RemoveRevisions - удаление записи из всех ревизий элемента RemoveRevisions(ctx context.Context, spaceId, envId, collectionId, itemId string, options ...*DeleteOptions) error @@ -83,7 +87,7 @@ type Storage interface { Copy(ctx context.Context, src, dst *collections.Collection, itemSets ...string) error Reset(ctx context.Context, spaceId, envId, collectionId string) error - Init(ctx context.Context, collection *collections.Collection) error + Init(ctx context.Context, collection *collections.Collection, locales ...*locales.Locale) error // Aggregate выполняет агрегацию данных Aggregate(ctx context.Context, coll *collections.Collection, filter *Filter, options ...*AggregateOptions) (result map[string]interface{}, err error) diff --git a/pkg/items/storage_options.go b/pkg/items/storage_options.go new file mode 100644 index 0000000000000000000000000000000000000000..a56232fb22b2cac5a8555952b5898bf229fc875a --- /dev/null +++ b/pkg/items/storage_options.go @@ -0,0 +1,94 @@ +package items + +import ( + "git.perx.ru/perxis/perxis-go/pkg/locales" + "git.perx.ru/perxis/perxis-go/pkg/options" +) + +type StorageFindOptions struct { + Options + options.FindOptions + + Deleted bool + Regular bool + Hidden bool + Templates bool + + // Язык перевода, который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + LocaleID string + + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + TranslationsIDs []string + + // Список локалей пространства + Locales []*locales.Locale +} + +func NewStorageFindOptions(opts ...interface{}) *StorageFindOptions { + fo := &StorageFindOptions{} + for _, o := range opts { + switch o := o.(type) { + case *FindOptions: + fo.Options = o.Options + fo.FindOptions = o.FindOptions + fo.Deleted = o.Deleted + fo.Regular = o.Regular + fo.Hidden = o.Hidden + fo.Templates = o.Templates + fo.LocaleID = o.LocaleID + fo.TranslationsIDs = o.TranslationsIDs + case *FindPublishedOptions: + fo.Options = o.Options + fo.FindOptions = o.FindOptions + fo.Deleted = o.Deleted + fo.Regular = o.Regular + fo.Hidden = o.Hidden + fo.Templates = o.Templates + fo.LocaleID = o.LocaleID + fo.TranslationsIDs = o.TranslationsIDs + case *FindArchivedOptions: + fo.Options = o.Options + fo.FindOptions = o.FindOptions + fo.LocaleID = o.LocaleID + fo.TranslationsIDs = o.TranslationsIDs + case *GetRevisionOptions: + fo.Options = o.Options + fo.LocaleID = o.LocaleID + fo.TranslationsIDs = o.TranslationsIDs + case *ListRevisionsOptions: + fo.Options = o.Options + fo.FindOptions = o.FindOptions + fo.LocaleID = o.LocaleID + fo.TranslationsIDs = o.TranslationsIDs + case *locales.Locale: + fo.Locales = []*locales.Locale{o} + case []*locales.Locale: + fo.Locales = o + } + } + return fo +} + +func MergeStorageFindOptions(opts ...*StorageFindOptions) *StorageFindOptions { + o := NewStorageFindOptions() + for _, opt := range opts { + if opt == nil { + continue + } + + o.Options = MergeOptions(o.Options, opt.Options) + o.FindOptions = *options.MergeFindOptions(&o.FindOptions, &opt.FindOptions) + + o.Deleted = o.Deleted || opt.Deleted + o.Regular = o.Regular || opt.Regular + o.Templates = o.Templates || opt.Templates + o.Hidden = o.Hidden || opt.Hidden + + if opt.LocaleID != "" { + o.LocaleID = opt.LocaleID + } + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + o.Locales = append(o.Locales, opt.Locales...) + } + return o +} diff --git a/pkg/items/transport/grpc/protobuf_endpoint_converters.microgen.go b/pkg/items/transport/grpc/protobuf_endpoint_converters.microgen.go index b111a6160dba31fb7adb2919a66d8e3bf620ef16..47208ce50e9e869b21c5db611ad89fa66eef8289 100644 --- a/pkg/items/transport/grpc/protobuf_endpoint_converters.microgen.go +++ b/pkg/items/transport/grpc/protobuf_endpoint_converters.microgen.go @@ -7,6 +7,7 @@ import ( "context" "errors" + "git.perx.ru/perxis/perxis-go/pkg/items" transport "git.perx.ru/perxis/perxis-go/pkg/items/transport" pb "git.perx.ru/perxis/perxis-go/proto/items" empty "google.golang.org/protobuf/types/known/emptypb" @@ -37,11 +38,16 @@ func _Encode_Get_Request(ctx context.Context, request interface{}) (interface{}, return nil, errors.New("nil GetRequest") } req := request.(*transport.GetRequest) + opts, err := GetOptionsToProto(req.Options) + if err != nil { + return nil, err + } return &pb.GetRequest{ CollectionId: req.CollectionId, EnvId: req.EnvId, ItemId: req.ItemId, SpaceId: req.SpaceId, + Options: opts, }, nil } @@ -54,15 +60,11 @@ func _Encode_Find_Request(ctx context.Context, request interface{}) (interface{} if err != nil { return nil, err } - reqOptions, err := ElPtrFindOptionsToProto(req.Options) - if err != nil { - return nil, err - } return &pb.FindRequest{ CollectionId: req.CollectionId, EnvId: req.EnvId, SpaceId: req.SpaceId, - Options: reqOptions, + Options: items.FindOptionsToProto(req.Options...), Filter: reqFilter, }, nil } @@ -212,12 +214,17 @@ func _Encode_GetRevision_Request(ctx context.Context, request interface{}) (inte return nil, errors.New("nil GetRevisionRequest") } req := request.(*transport.GetRevisionRequest) + opts, err := GetRevisionOptionsToProto(req.Options) + if err != nil { + return nil, err + } return &pb.GetRevisionRequest{ CollectionId: req.CollectionId, EnvId: req.EnvId, ItemId: req.ItemId, RevisionId: req.RevisionId, SpaceId: req.SpaceId, + Options: opts, }, nil } @@ -226,7 +233,7 @@ func _Encode_ListRevisions_Request(ctx context.Context, request interface{}) (in return nil, errors.New("nil ListRevisionsRequest") } req := request.(*transport.ListRevisionsRequest) - reqOptions, err := ElPtrListRevisionsOptionsToProto(req.Options) + reqOptions, err := ListRevisionsOptionsToProto(req.Options) if err != nil { return nil, err } @@ -260,7 +267,7 @@ func _Encode_FindArchived_Request(ctx context.Context, request interface{}) (int if err != nil { return nil, err } - reqOptions, err := ElPtrFindArchivedOptionsToProto(req.Options) + reqOptions, err := FindArchivedOptionsToProto(req.Options) if err != nil { return nil, err } @@ -515,11 +522,16 @@ func _Decode_Get_Request(ctx context.Context, request interface{}) (interface{}, return nil, errors.New("nil GetRequest") } req := request.(*pb.GetRequest) + opts, err := ProtoToGetOptions(req.Options) + if err != nil { + return nil, err + } return &transport.GetRequest{ CollectionId: string(req.CollectionId), EnvId: string(req.EnvId), ItemId: string(req.ItemId), SpaceId: string(req.SpaceId), + Options: opts, }, nil } @@ -734,12 +746,17 @@ func _Decode_GetRevision_Request(ctx context.Context, request interface{}) (inte return nil, errors.New("nil GetRevisionRequest") } req := request.(*pb.GetRevisionRequest) + opts, err := ProtoToGetRevisionOptions(req.Options) + if err != nil { + return nil, err + } return &transport.GetRevisionRequest{ CollectionId: string(req.CollectionId), EnvId: string(req.EnvId), ItemId: string(req.ItemId), RevisionId: string(req.RevisionId), SpaceId: string(req.SpaceId), + Options: opts, }, nil } @@ -748,7 +765,7 @@ func _Decode_ListRevisions_Request(ctx context.Context, request interface{}) (in return nil, errors.New("nil ListRevisionsRequest") } req := request.(*pb.ListRevisionsRequest) - reqOptions, err := ProtoToElPtrListRevisionsOptions(req.Options) + reqOptions, err := ProtoToListRevisionsOptions(req.Options) if err != nil { return nil, err } @@ -782,7 +799,7 @@ func _Decode_FindArchived_Request(ctx context.Context, request interface{}) (int if err != nil { return nil, err } - reqOptions, err := ProtoToElPtrFindArchivedOptions(req.Options) + reqOptions, err := ProtoToFindArchivedOptions(req.Options) if err != nil { return nil, err } diff --git a/pkg/items/transport/grpc/protobuf_type_converters.microgen.go b/pkg/items/transport/grpc/protobuf_type_converters.microgen.go index ade05bfffeb4a1c745f80338e7faac2287b067a2..1aba486580e9f94882b29d254b1fffab39c8270c 100644 --- a/pkg/items/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/items/transport/grpc/protobuf_type_converters.microgen.go @@ -176,80 +176,43 @@ func ProtoToListPtrItem(protoItems []*pb.Item) ([]*service.Item, error) { } func ProtoToCreateOptions(protoOptions *pb.CreateOptions) ([]*service.CreateOptions, error) { - if protoOptions == nil { - return nil, nil - } - return []*service.CreateOptions{ - {UpdateAttrs: protoOptions.UpdateAttrs}, - }, nil + return []*service.CreateOptions{service.CreateOptionsFromProto(protoOptions)}, nil } func CreateOptionsToProto(options []*service.CreateOptions) (*pb.CreateOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeCreateOptions(options...) - - return &pb.CreateOptions{ - UpdateAttrs: opts.UpdateAttrs, - }, nil + return service.CreateOptionsToProto(options...), nil } -func ElPtrGetOptionsToProto() { - panic("function not provided") // TODO: provide converter +func GetRevisionOptionsToProto(options []*service.GetRevisionOptions) (*pb.GetRevisionOptions, error) { + return service.GetRevisionOptionsToProto(options...), nil } -func ProtoToElPtrGetOptions() { - panic("function not provided") // TODO: provide converter +func ProtoToGetRevisionOptions(protoOptions *pb.GetRevisionOptions) ([]*service.GetRevisionOptions, error) { + return []*service.GetRevisionOptions{service.GetRevisionOptionsFromProto(protoOptions)}, nil } -func ElPtrFindOptionsToProto(options []*service.FindOptions) (*pb.FindOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeFindOptions(options...) +func ListRevisionsOptionsToProto(options []*service.ListRevisionsOptions) (*pb.ListRevisionsOptions, error) { + return service.ListRevisionsOptionsToProto(options...), nil +} - var err error +func ProtoToListRevisionsOptions(protoOptions *pb.ListRevisionsOptions) ([]*service.ListRevisionsOptions, error) { + return []*service.ListRevisionsOptions{service.ListRevisionsOptionsFromProto(protoOptions)}, nil +} - fo := &pb.FindOptions{ - Deleted: opts.Deleted, - Regular: opts.Regular, - Hidden: opts.Hidden, - Templates: opts.Templates, - } +func GetOptionsToProto(options []*service.GetOptions) (*pb.GetOptions, error) { + return service.GetOptionsToProto(options...), nil +} - fo.Options, err = PtrServicesFindOptionsToProto(&opts.FindOptions) - if err != nil { - return nil, err - } +func ProtoToGetOptions(protoOptions *pb.GetOptions) ([]*service.GetOptions, error) { + return []*service.GetOptions{service.GetOptionsFromProto(protoOptions)}, nil +} - return fo, nil +func ElPtrFindOptionsToProto(options []*service.FindOptions) (*pb.FindOptions, error) { + return service.FindOptionsToProto(options...), nil } func ProtoToElPtrFindOptions(protoOptions *pb.FindOptions) ([]*service.FindOptions, error) { - if protoOptions == nil { - return nil, nil - } - - var err error - fo := &service.FindOptions{ - Deleted: protoOptions.Deleted, - Regular: protoOptions.Regular, - Hidden: protoOptions.Hidden, - Templates: protoOptions.Templates, - } - - o, err := ProtoToPtrServicesFindOptions(protoOptions.Options) - if err != nil { - return nil, err - } - if o != nil { - fo.FindOptions = *o - } - - return []*service.FindOptions{fo}, nil + return []*service.FindOptions{service.FindOptionsFromProto(protoOptions)}, nil } func ProtoToUpdateOptions(protoOptions *pb.UpdateOptions) ([]*service.UpdateOptions, error) { @@ -262,40 +225,18 @@ func ProtoToUpdateOptions(protoOptions *pb.UpdateOptions) ([]*service.UpdateOpti } func UpdateOptionsToProto(options []*service.UpdateOptions) (*pb.UpdateOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeUpdateOptions(options...) - - return &pb.UpdateOptions{ - UpdateAttrs: opts.UpdateAttrs, - }, nil + return service.UpdateOptionsToProto(options...), nil } func ProtoToDeleteOptions(protoOptions *pb.DeleteOptions) ([]*service.DeleteOptions, error) { if protoOptions == nil { return nil, nil } - return []*service.DeleteOptions{ - { - UpdateAttrs: protoOptions.UpdateAttrs, - Erase: protoOptions.Erase, - }, - }, nil + return []*service.DeleteOptions{service.DeleteOptionsFromProto(protoOptions)}, nil } func DeleteOptionsToProto(options []*service.DeleteOptions) (*pb.DeleteOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeDeleteOptions(options...) - - return &pb.DeleteOptions{ - UpdateAttrs: opts.UpdateAttrs, - Erase: opts.Erase, - }, nil + return service.DeleteOptionsToProto(options...), nil } func ProtoToUndeleteOptions(protoOptions *pb.UndeleteOptions) ([]*service.UndeleteOptions, error) { @@ -363,70 +304,19 @@ func UnpublishOptionsToProto(options []*service.UnpublishOptions) (*pb.Unpublish } func ElPtrGetPublishedOptionsToProto(options []*service.GetPublishedOptions) (*pb.GetPublishedOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeGetPublishedOptions(options...) - - return &pb.GetPublishedOptions{LocaleId: opts.LocaleID}, nil + return service.GetPublishedOptionsToProto(options...), nil } func ProtoToElPtrGetPublishedOptions(protoOptions *pb.GetPublishedOptions) ([]*service.GetPublishedOptions, error) { - if protoOptions == nil { - return nil, nil - } - - return []*service.GetPublishedOptions{{LocaleID: protoOptions.LocaleId}}, nil + return []*service.GetPublishedOptions{service.GetPublishedOptionsFromProto(protoOptions)}, nil } func ElPtrFindPublishedOptionsToProto(options []*service.FindPublishedOptions) (*pb.FindPublishedOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeFindPublishedOptions(options...) - - var err error - - fo := &pb.FindPublishedOptions{ - Regular: opts.Regular, - Hidden: opts.Hidden, - Templates: opts.Templates, - } - fo.Options, err = PtrServicesFindOptionsToProto(&opts.FindOptions) - if err != nil { - return nil, err - } - - fo.LocaleId = opts.LocaleID - - return fo, nil + return service.FindPublishedOptionsToProto(options...), nil } func ProtoToElPtrFindPublishedOptions(protoOptions *pb.FindPublishedOptions) ([]*service.FindPublishedOptions, error) { - if protoOptions == nil { - return nil, nil - } - - var err error - fo := &service.FindPublishedOptions{ - Regular: protoOptions.Regular, - Hidden: protoOptions.Hidden, - Templates: protoOptions.Templates, - } - - o, err := ProtoToPtrServicesFindOptions(protoOptions.Options) - if err != nil { - return nil, err - } - if o != nil { - fo.FindOptions = *o - } - - fo.LocaleID = protoOptions.LocaleId - - return []*service.FindPublishedOptions{fo}, nil + return []*service.FindPublishedOptions{service.FindPublishedOptionsFromProto(protoOptions)}, nil } func ElPtrGetRevisionOptionsToProto() { @@ -437,44 +327,6 @@ func ProtoToElPtrGetRevisionOptions() { panic("function not provided") // TODO: provide converter } -func ElPtrListRevisionsOptionsToProto(options []*service.ListRevisionsOptions) (*pb.ListRevisionsOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeListRevisionsOptions(options...) - - var err error - - fo := &pb.ListRevisionsOptions{} - - fo.Options, err = PtrServicesFindOptionsToProto(&opts.FindOptions) - if err != nil { - return nil, err - } - - return fo, nil -} - -func ProtoToElPtrListRevisionsOptions(protoOptions *pb.ListRevisionsOptions) ([]*service.ListRevisionsOptions, error) { - if protoOptions == nil { - return nil, nil - } - - var err error - fo := &service.ListRevisionsOptions{} - - o, err := ProtoToPtrServicesFindOptions(protoOptions.Options) - if err != nil { - return nil, err - } - if o != nil { - fo.FindOptions = *o - } - - return []*service.ListRevisionsOptions{fo}, nil -} - func ElPtrArchiveOptionsToProto() { panic("function not provided") // TODO: provide converter } @@ -483,42 +335,12 @@ func ProtoToElPtrArchiveOptions() { panic("function not provided") // TODO: provide converter } -func ElPtrFindArchivedOptionsToProto(options []*service.FindArchivedOptions) (*pb.FindArchivedOptions, error) { - if options == nil { - return nil, nil - } - - opts := service.MergeFindArchivedOptions(options...) - - var err error - - fo := &pb.FindArchivedOptions{} - - fo.Options, err = PtrServicesFindOptionsToProto(&opts.FindOptions) - if err != nil { - return nil, err - } - - return fo, nil +func FindArchivedOptionsToProto(options []*service.FindArchivedOptions) (*pb.FindArchivedOptions, error) { + return service.FindArchivedOptionsToProto(options...), nil } -func ProtoToElPtrFindArchivedOptions(protoOptions *pb.FindArchivedOptions) ([]*service.FindArchivedOptions, error) { - if protoOptions == nil { - return nil, nil - } - - var err error - fo := &service.FindArchivedOptions{} - - o, err := ProtoToPtrServicesFindOptions(protoOptions.Options) - if err != nil { - return nil, err - } - if o != nil { - fo.FindOptions = *o - } - - return []*service.FindArchivedOptions{fo}, nil +func ProtoToFindArchivedOptions(protoOptions *pb.FindArchivedOptions) ([]*service.FindArchivedOptions, error) { + return []*service.FindArchivedOptions{service.FindArchivedOptionsFromProto(protoOptions)}, nil } func ElPtrUnarchiveOptionsToProto() { diff --git a/pkg/locales/errors.go b/pkg/locales/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..b5876aff89925f394b8e36c1e609dfc6b4581164 --- /dev/null +++ b/pkg/locales/errors.go @@ -0,0 +1,22 @@ +package locales + +import ( + "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/pkg/service" +) + +var ( + ErrNotFound = service.ErrNotFound + ErrAlreadyExists = service.ErrAlreadyExists + ErrSpaceIDRequired = errors.New("space id is required") + ErrLocaleValueEmpty = errors.New("locale value cannot be empty") + ErrLocaleIDRequired = errors.New("locale id is required") + ErrLocaleCodeRequired = errors.New("locale code is required") + ErrSetSelfAsFallback = errors.New("cannot set self as fallback") + ErrDisableDefaultLocale = errors.New("cannot disable default locale") + ErrDisablePublishingDefaultLocale = errors.New("cannot disable publishing for default locale") + ErrSetDefaultLocaleFallback = errors.New("cannot set fallback for default locale") + ErrDeleteDefaultLocale = errors.New("cannot delete default locale") + ErrDeleteFallbackLocale = errors.New("cannot delete locale that is used as fallback for other locales") + ErrCircularDependency = errors.New("fallback locales contain cycles") +) diff --git a/pkg/locales/events.go b/pkg/locales/events.go new file mode 100644 index 0000000000000000000000000000000000000000..fe9c8d95ed4be12f129c17ec8a6cedb672024f15 --- /dev/null +++ b/pkg/locales/events.go @@ -0,0 +1,7 @@ +package locales + +const ( + EventCreate = "locales.create" + EventUpdate = "locales.update" + EventDelete = "locales.delete" +) diff --git a/pkg/locales/locale.go b/pkg/locales/locale.go index d3cc43c6c625a5090d975409d7aa2beb16eefc3a..e0e32616ee4bd526c7d25c9cbab740e196529328 100644 --- a/pkg/locales/locale.go +++ b/pkg/locales/locale.go @@ -1,7 +1,164 @@ package locales +import ( + "git.perx.ru/perxis/perxis-go/pkg/data" + "git.perx.ru/perxis/perxis-go/pkg/errors" + pb "git.perx.ru/perxis/perxis-go/proto/locales" + "golang.org/x/text/language" +) + +const ( + DefaultID = "default" // DefaultID идентификатор локали по умолчанию + DefaultDirection = "ltr" // DefaultDirection направление письма по умолчанию +) + type Locale struct { - ID string `json:"id" bson:"_id"` // (Пример: "en", "en-US") - SpaceID string `json:"spaceId" bson:"-"` - Name string `json:"name" bson:"name"` // (Пример: "English", "English (US)" ) + ID string `json:"id" bson:"_id"` // Идентификатор локали, генерируется автоматически. Для локали по умолчанию устанавливается как "default". + SpaceID string `json:"spaceId" bson:"-"` // Идентификатор пространства. + Name string `json:"name" bson:"name"` // Название локали. Опционально, заполняется автоматически (Пример: russian, english) + NativeName string `json:"native_name" bson:"native_name"` // Название локали на языке локали. Опционально, заполняется автоматически (Пример: Русский, English) + Code string `json:"code" bson:"code"` // Код локали https://en.wikipedia.org/wiki/IETF_language_tag + Fallback string `json:"fallback" bson:"fallback"` // Идентификатор локали, который будет использоваться при отсутствии перевода + Direction string `json:"direction" bson:"direction"` // Направление письма - слева направо (ltr) или справа налево (rtl). По умолчанию устанавливается ltr. + Weight int `json:"weight" bson:"weight"` // Вес локали. + NoPublish bool `json:"no_publish" bson:"no_publish"` // Не публиковать контент данной локали. Не будет доступен контент через Delivery API. (кроме default) + Disabled bool `json:"disabled" bson:"disabled"` // Запретить использование локали. Нельзя создавать и редактировать контент для данной локали (кроме default) +} + +func (locale *Locale) Clone() *Locale { + return &Locale{ + ID: locale.ID, + SpaceID: locale.SpaceID, + Name: locale.Name, + NativeName: locale.NativeName, + Code: locale.Code, + Fallback: locale.Fallback, + Direction: locale.Direction, + Weight: locale.Weight, + NoPublish: locale.NoPublish, + Disabled: locale.Disabled, + } +} + +func (locale *Locale) IsDefault() bool { + return locale.ID == DefaultID +} + +func (locale *Locale) Equal(other *Locale) bool { + return locale == other || locale != nil && other != nil && *locale == *other +} + +func (locale *Locale) Key() string { + if locale == nil { + return "" + } + return locale.ID +} + +// Возвращает язык локали, например "en", "ru" +func (locale *Locale) GetLanguage() string { + lang, err := language.Parse(locale.Code) + if err != nil { + return "" + } + + base, _ := lang.Base() + return base.String() +} + +func GetIDs(locales []*Locale) []string { + result := make([]string, 0, len(locales)) + for _, locale := range locales { + result = append(result, locale.ID) + } + return result +} + +func LocaleToProto(locale *Locale) *pb.Locale { + if locale == nil { + return nil + } + protoLocale := &pb.Locale{ + Id: locale.ID, + SpaceId: locale.SpaceID, + Name: locale.Name, + NativeName: locale.NativeName, + Code: locale.Code, + Fallback: locale.Fallback, + Direction: locale.Direction, + Weight: int64(locale.Weight), + NoPublish: locale.NoPublish, + Disabled: locale.Disabled, + } + return protoLocale +} + +func LocaleFromProto(protoLocale *pb.Locale) *Locale { + if protoLocale == nil { + return nil + } + locale := &Locale{ + ID: protoLocale.Id, + SpaceID: protoLocale.SpaceId, + Name: protoLocale.Name, + NativeName: protoLocale.NativeName, + Code: protoLocale.Code, + Fallback: protoLocale.Fallback, + Direction: protoLocale.Direction, + Weight: int(protoLocale.Weight), + NoPublish: protoLocale.NoPublish, + Disabled: protoLocale.Disabled, + } + return locale +} + +func FallbackSort(locales []*Locale) ([]*Locale, error) { + if len(locales) == 0 { + return locales, nil + } + + var ( + unsorted = data.SliceToMap(locales) + sorted = make([]*Locale, 0, len(locales)) + visited = make(map[string]bool, len(locales)) + ) + + for { + changed := false + for _, node := range locales { + + if visited[node.ID] { + continue + } + + if _, exist := unsorted[node.Fallback]; !exist && node.Fallback != "" { + return nil, errors.Wrap(ErrNotFound, node.Fallback) + } + + if node.IsDefault() { + sorted = append([]*Locale{node}, sorted...) + visited[node.ID] = true + changed = true + continue + } + + if node.Fallback == "" || visited[node.Fallback] { + sorted = append(sorted, node) + visited[node.ID] = true + changed = true + } + } + + // Все локали перенесены в список отсортированных + if len(sorted) == len(locales) { + break + } + + // Если не произошло изменений, но не все локали отсортированы - обнаружены циклические зависимости + if !changed { + return nil, ErrCircularDependency + } + } + + return sorted, nil } diff --git a/pkg/locales/locale_test.go b/pkg/locales/locale_test.go new file mode 100644 index 0000000000000000000000000000000000000000..664e369277d701e8c34b818433c492ee688695f4 --- /dev/null +++ b/pkg/locales/locale_test.go @@ -0,0 +1,297 @@ +package locales + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLocale_GetLanguage(t *testing.T) { + tests := []struct { + code string + wantLang string + }{ + { + code: "ru", + wantLang: "ru", + }, + { + code: "ru_RU", + wantLang: "ru", + }, + { + code: "en-US", + wantLang: "en", + }, + { + code: "incorrect-code", + wantLang: "", + }, + } + + for _, tt := range tests { + t.Run(tt.code, func(t *testing.T) { + locale := &Locale{Code: tt.code} + require.Equal(t, tt.wantLang, locale.GetLanguage()) + }) + } +} + +func TestLocale_Equal(t *testing.T) { + tests := []struct { + locale *Locale + other *Locale + want bool + }{ + { + locale: &Locale{Code: "ru-RU"}, + other: &Locale{Code: "ru-RU"}, + want: true, + }, + { + locale: &Locale{Code: "ru-RU"}, + other: &Locale{Code: "ru-RU", Fallback: "en-US"}, + want: false, + }, + { + locale: &Locale{Code: "ru-RU", Fallback: "en-US"}, + other: &Locale{Code: "ru-RU"}, + want: false, + }, + { + locale: &Locale{Code: "ru-RU"}, + other: nil, + want: false, + }, + { + locale: nil, + other: &Locale{Code: "ru-RU"}, + want: false, + }, + { + locale: nil, + other: nil, + want: true, + }, + } + for _, tt := range tests { + got := tt.locale.Equal(tt.other) + require.Equal(t, tt.want, got) + } +} + +func TestFallbackSort(t *testing.T) { + tests := []struct { + name string + input []*Locale + want []*Locale + wantErr bool + }{ + { + name: "Empty input", + input: nil, + want: nil, + wantErr: false, + }, + { + name: "Empty input", + input: []*Locale{}, + want: []*Locale{}, + wantErr: false, + }, + { + name: "One locale not default", + input: []*Locale{ + {ID: "a"}, + }, + want: []*Locale{ + {ID: "a"}, + }, + wantErr: false, + }, + { + name: "One default locale", + input: []*Locale{ + {ID: DefaultID}, + }, + want: []*Locale{ + {ID: DefaultID}, + }, + wantErr: false, + }, + { + name: "One locale with fallback", + input: []*Locale{ + {ID: DefaultID, Fallback: "a"}, + }, + wantErr: true, + }, + { + name: "Fallback locale not exists", + input: []*Locale{ + {ID: "a", Fallback: "c"}, + {ID: "b", Fallback: DefaultID}, + }, + want: nil, + wantErr: true, + }, + { + name: "Not found default", + input: []*Locale{ + {ID: "a", Fallback: DefaultID}, + {ID: "b", Fallback: "d"}, + {ID: "c", Fallback: DefaultID}, + {ID: "d", Fallback: "c"}, + {ID: "e", Fallback: "a"}, + }, + wantErr: true, + }, + { + name: "Simple", + input: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: DefaultID}, + {ID: "b", Fallback: "d"}, + {ID: "c", Fallback: DefaultID}, + {ID: "d", Fallback: "c"}, + {ID: "e", Fallback: "a"}, + }, + want: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: DefaultID}, + {ID: "c", Fallback: DefaultID}, + {ID: "d", Fallback: "c"}, + {ID: "e", Fallback: "a"}, + {ID: "b", Fallback: "d"}, + }, + wantErr: false, + }, + { + name: "Simple #2", + input: []*Locale{ + {ID: "a", Fallback: DefaultID}, + {ID: "b", Fallback: "d"}, + {ID: "c", Fallback: DefaultID}, + {ID: "d", Fallback: "c"}, + {ID: "e", Fallback: "a"}, + {ID: DefaultID}, + }, + want: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: DefaultID}, + {ID: "c", Fallback: DefaultID}, + {ID: "d", Fallback: "c"}, + {ID: "e", Fallback: "a"}, + {ID: "b", Fallback: "d"}, + }, + wantErr: false, + }, + { + name: "Simple #3", + input: []*Locale{ + {ID: DefaultID}, + {ID: "a"}, + {ID: "b"}, + }, + want: []*Locale{ + {ID: DefaultID}, + {ID: "a"}, + {ID: "b"}, + }, + wantErr: false, + }, + { + name: "Simple #4", + input: []*Locale{ + {ID: "a"}, + {ID: "b"}, + {ID: DefaultID}, + }, + want: []*Locale{ + {ID: DefaultID}, + {ID: "a"}, + {ID: "b"}, + }, + wantErr: false, + }, + { + name: "Simple #5", + input: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: "b"}, + {ID: "b", Fallback: "c"}, + {ID: "c"}, + }, + want: []*Locale{ + {ID: DefaultID}, + {ID: "c"}, + {ID: "b", Fallback: "c"}, + {ID: "a", Fallback: "b"}, + }, + wantErr: false, + }, + { + name: "Simple #6", + input: []*Locale{ + {ID: "a", Fallback: "b"}, + {ID: "b", Fallback: "c"}, + {ID: "c"}, + }, + want: []*Locale{ + {ID: "c"}, + {ID: "b", Fallback: "c"}, + {ID: "a", Fallback: "b"}, + }, + wantErr: false, + }, + { + name: "Cyclical dependency", + input: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: "b"}, + {ID: "b", Fallback: "c"}, + {ID: "c", Fallback: "a"}, + }, + want: nil, + wantErr: true, + }, + { + name: "Cyclical dependency #2", + input: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: DefaultID}, + {ID: "b", Fallback: "d"}, + {ID: "c", Fallback: "b"}, + {ID: "d", Fallback: "c"}, + {ID: "e", Fallback: "a"}, + }, + want: nil, + wantErr: true, + }, + { + name: "Cyclical dependency #3", + input: []*Locale{ + {ID: DefaultID}, + {ID: "a", Fallback: "b"}, + {ID: "b", Fallback: "a"}, + {ID: "c", Fallback: "d"}, + {ID: "d", Fallback: "c"}, + }, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := FallbackSort(tt.input) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/locales/middleware/access_logging_middleware.go b/pkg/locales/middleware/access_logging_middleware.go index eabb71c37756d0a7d39d6abe217f394036a69922..ab31fc8c81ec51af35e63ab8eadbc400a9b717db 100644 --- a/pkg/locales/middleware/access_logging_middleware.go +++ b/pkg/locales/middleware/access_logging_middleware.go @@ -87,3 +87,21 @@ func (m *accessLoggingMiddleware) List(ctx context.Context, spaceId string) (loc return locales, err } + +func (m *accessLoggingMiddleware) Update(ctx context.Context, locale *locales.Locale) (err error) { + begin := time.Now() + + m.logger.Debug("Update.Request", + zap.Reflect("principal", auth.GetPrincipal(ctx)), + zap.Reflect("locale", locale), + ) + + err = m.next.Update(ctx, locale) + + m.logger.Debug("Update.Response", + zap.Duration("time", time.Since(begin)), + zap.Error(err), + ) + + return err +} diff --git a/pkg/locales/middleware/caching_middleware.go b/pkg/locales/middleware/caching_middleware.go index 13928a5166f2187e85a5e7da63861509e3f69d3a..64f82bc2347323140674cb7375bfe41a36a5bfb0 100644 --- a/pkg/locales/middleware/caching_middleware.go +++ b/pkg/locales/middleware/caching_middleware.go @@ -4,6 +4,7 @@ import ( "context" "git.perx.ru/perxis/perxis-go/pkg/cache" + "git.perx.ru/perxis/perxis-go/pkg/data" service "git.perx.ru/perxis/perxis-go/pkg/locales" ) @@ -25,29 +26,39 @@ func (m cachingMiddleware) Create(ctx context.Context, locale *service.Locale) ( loc, err = m.next.Create(ctx, locale) if err == nil { - m.cache.Remove(loc.SpaceID) + _ = m.cache.Remove(loc.SpaceID) } return loc, err } +func (m cachingMiddleware) Update(ctx context.Context, locale *service.Locale) (err error) { + + err = m.next.Update(ctx, locale) + if err == nil { + _ = m.cache.Remove(locale.SpaceID) + } + return err +} + func (m cachingMiddleware) List(ctx context.Context, spaceId string) (locales []*service.Locale, err error) { value, e := m.cache.Get(spaceId) if e == nil { - return value.([]*service.Locale), err + return data.CloneSlice(value.([]*service.Locale)), nil } locales, err = m.next.List(ctx, spaceId) if err == nil { - m.cache.Set(spaceId, locales) + _ = m.cache.Set(spaceId, locales) + return data.CloneSlice(locales), nil } - return locales, err + return nil, err } func (m cachingMiddleware) Delete(ctx context.Context, spaceId string, localeId string) (err error) { err = m.next.Delete(ctx, spaceId, localeId) if err == nil { - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) } return err } diff --git a/pkg/locales/middleware/caching_middleware_test.go b/pkg/locales/middleware/caching_middleware_test.go index 281aa49611a83e4a0a28f1064dbf5fe149dd29f3..25b542c840c228324f843267ae3968f96d0ddfe5 100644 --- a/pkg/locales/middleware/caching_middleware_test.go +++ b/pkg/locales/middleware/caching_middleware_test.go @@ -37,7 +37,8 @@ func TestLocalesCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) loc.AssertExpectations(t) }) @@ -55,7 +56,8 @@ func TestLocalesCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) loc.On("Delete", mock.Anything, spaceID, loc1).Return(nil).Once() @@ -83,7 +85,8 @@ func TestLocalesCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) loc.On("Create", mock.Anything, mock.Anything).Return(&locales.Locale{ID: loc2, Name: "name2", SpaceID: spaceID}, nil).Once() @@ -103,6 +106,39 @@ func TestLocalesCache(t *testing.T) { loc.AssertExpectations(t) }) + t.Run("After Update", func(t *testing.T) { + loc := &locmocks.Locales{} + + svc := CachingMiddleware(cache.NewMemoryCache(size, ttl))(loc) + + loc.On("List", mock.Anything, spaceID).Return([]*locales.Locale{{ID: loc1, Name: "name1", SpaceID: spaceID}}, nil).Once() + + vl1, err := svc.List(ctx, spaceID) + require.NoError(t, err) + + vl2, err := svc.List(ctx, spaceID) + require.NoError(t, err) + assert.Equal(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) + + loc.On("Update", mock.Anything, mock.Anything).Return(nil).Once() + + err = svc.Update(ctx, &locales.Locale{ID: loc2, Name: "name2", SpaceID: spaceID}) + require.NoError(t, err) + + loc.On("List", mock.Anything, spaceID). + Return([]*locales.Locale{ + {ID: loc1, Name: "name1", SpaceID: spaceID}, + {ID: loc2, Name: "name2", SpaceID: spaceID}, + }, nil).Once() + + vl3, err := svc.List(ctx, spaceID) + require.NoError(t, err) + assert.Len(t, vl3, 2, "Ожидается что после обновления объекта данные будут удалены из кеша и получены из сервиса.") + + loc.AssertExpectations(t) + }) + t.Run("After TTL expired", func(t *testing.T) { loc := &locmocks.Locales{} @@ -115,7 +151,8 @@ func TestLocalesCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается что при повторном запросе объекты будут получены из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) time.Sleep(2 * ttl) loc.On("List", mock.Anything, spaceID).Return([]*locales.Locale{{ID: loc1, Name: "name1", SpaceID: spaceID}}, nil).Once() @@ -123,6 +160,8 @@ func TestLocalesCache(t *testing.T) { vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) assert.NotSame(t, vl2[0], vl3[0], "Ожидается что элементы будут получены из кэша.") + assert.Equal(t, vl2[0], vl3[0]) + assert.NotSame(t, vl2[0], vl3[0]) loc.AssertExpectations(t) }) diff --git a/pkg/locales/middleware/error_logging_middleware.go b/pkg/locales/middleware/error_logging_middleware.go index a00f23a29aa8b5330e1097c670e6cc0edf5b9983..0dd4ae2e6748c35fa7a0592c274a9dfeb86f5d7b 100644 --- a/pkg/locales/middleware/error_logging_middleware.go +++ b/pkg/locales/middleware/error_logging_middleware.go @@ -58,3 +58,13 @@ func (m *errorLoggingMiddleware) List(ctx context.Context, spaceId string) (loca }() return m.next.List(ctx, spaceId) } + +func (m *errorLoggingMiddleware) Update(ctx context.Context, locale *locales.Locale) (err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.Update(ctx, locale) +} diff --git a/pkg/locales/middleware/logging_middleware.go b/pkg/locales/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..2b6bfea5281a89bf9050094fe2d631fed200c9a4 --- /dev/null +++ b/pkg/locales/middleware/logging_middleware.go @@ -0,0 +1,88 @@ +package middleware + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/locales" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next locales.Locales +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next locales.Locales) locales.Locales { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Locales")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, locale *locales.Locale) (created *locales.Locale, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(locales.EventCreate), + ) + + created, err = m.next.Create(ctx, locale) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(locale)) + return + } + + logger.Info("Locale created", logzap.Channels(logzap.Userlog), logzap.Object(created)) + return created, err +} + +func (m *loggingMiddleware) Update(ctx context.Context, locale *locales.Locale) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(locales.EventUpdate), + logzap.Object(locale), + ) + + err = m.next.Update(ctx, locale) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Locale updated", logzap.Channels(logzap.Userlog)) + return err +} + +func (m *loggingMiddleware) List(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + locales, err = m.next.List(ctx, spaceId) + if err != nil { + logger.Error("Failed to list", zap.Error(err)) + return + } + + return locales, err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, spaceId, localeId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(locales.EventDelete), + logzap.Object(id.NewLocaleId(spaceId, localeId)), + ) + + err = m.next.Delete(ctx, spaceId, localeId) + if err != nil { + logger.Error("Failed to delete", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Locale deleted", logzap.Channels(logzap.Userlog)) + return err +} diff --git a/pkg/locales/middleware/middleware.go b/pkg/locales/middleware/middleware.go index 2598e397afafb552c16be249cfcf1ed62149339b..28c61113902b15acf844d8a6251f0369159128a0 100644 --- a/pkg/locales/middleware/middleware.go +++ b/pkg/locales/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s locales.Locales, logger *zap.Logger, log_access bool) locales.Loc if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/locales/middleware/recovering_middleware.go b/pkg/locales/middleware/recovering_middleware.go index 3229e52394d207361d608744b5dcf73585142958..85f14bdbe6493c40c24c91bf539e33b9ca7e397b 100644 --- a/pkg/locales/middleware/recovering_middleware.go +++ b/pkg/locales/middleware/recovering_middleware.go @@ -65,3 +65,15 @@ func (m *recoveringMiddleware) List(ctx context.Context, spaceId string) (locale return m.next.List(ctx, spaceId) } + +func (m *recoveringMiddleware) Update(ctx context.Context, locale *locales.Locale) (err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.Update(ctx, locale) +} diff --git a/pkg/locales/middleware/telemetry_middleware.go b/pkg/locales/middleware/telemetry_middleware.go index 4efc5293b78781aaa5d8cbf77f4da82c714a6137..98fe346ea000409be27bfd21fccc6723ed09851b 100644 --- a/pkg/locales/middleware/telemetry_middleware.go +++ b/pkg/locales/middleware/telemetry_middleware.go @@ -1,10 +1,10 @@ // Code generated by gowrap. DO NOT EDIT. -// template: ..\..\..\assets\templates\middleware\telemetry +// template: ../../../assets/templates/middleware/telemetry // gowrap: http://github.com/hexdigest/gowrap package middleware -//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/locales -i Locales -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l "" +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/locales -i Locales -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry @@ -149,3 +149,36 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (locales }() return _d.Locales.List(ctx, spaceId) } + +// Update implements locales.Locales +func (_d telemetryMiddleware) Update(ctx context.Context, locale *locales.Locale) (err error) { + attributes := otelmetric.WithAttributeSet(attribute.NewSet( + attribute.String("service", "Locales"), + attribute.String("method", "Update"), + )) + + _d.requestMetrics.Total.Add(ctx, 1, attributes) + + start := time.Now() + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.Update") + + defer func() { + _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes) + + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "locale": locale}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _d.requestMetrics.FailedTotal.Add(ctx, 1, attributes) + + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Locales.Update(ctx, locale) +} diff --git a/pkg/locales/mocks/Locales.go b/pkg/locales/mocks/Locales.go index 491406c5c3fa577050ee0f1a097b89419b17bf42..6519e3cc9b5e02895fa22b778c15437737f606de 100644 --- a/pkg/locales/mocks/Locales.go +++ b/pkg/locales/mocks/Locales.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -18,7 +18,15 @@ type Locales struct { func (_m *Locales) Create(ctx context.Context, locale *locales.Locale) (*locales.Locale, error) { ret := _m.Called(ctx, locale) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 *locales.Locale + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) (*locales.Locale, error)); ok { + return rf(ctx, locale) + } if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) *locales.Locale); ok { r0 = rf(ctx, locale) } else { @@ -27,7 +35,6 @@ func (_m *Locales) Create(ctx context.Context, locale *locales.Locale) (*locales } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *locales.Locale) error); ok { r1 = rf(ctx, locale) } else { @@ -41,6 +48,10 @@ func (_m *Locales) Create(ctx context.Context, locale *locales.Locale) (*locales func (_m *Locales) Delete(ctx context.Context, spaceId string, localeId string) error { ret := _m.Called(ctx, spaceId, localeId) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { r0 = rf(ctx, spaceId, localeId) @@ -55,7 +66,15 @@ func (_m *Locales) Delete(ctx context.Context, spaceId string, localeId string) func (_m *Locales) List(ctx context.Context, spaceId string) ([]*locales.Locale, error) { ret := _m.Called(ctx, spaceId) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []*locales.Locale + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]*locales.Locale, error)); ok { + return rf(ctx, spaceId) + } if rf, ok := ret.Get(0).(func(context.Context, string) []*locales.Locale); ok { r0 = rf(ctx, spaceId) } else { @@ -64,7 +83,6 @@ func (_m *Locales) List(ctx context.Context, spaceId string) ([]*locales.Locale, } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, spaceId) } else { @@ -74,13 +92,30 @@ func (_m *Locales) List(ctx context.Context, spaceId string) ([]*locales.Locale, return r0, r1 } -type mockConstructorTestingTNewLocales interface { - mock.TestingT - Cleanup(func()) +// Update provides a mock function with given fields: ctx, locale +func (_m *Locales) Update(ctx context.Context, locale *locales.Locale) error { + ret := _m.Called(ctx, locale) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) error); ok { + r0 = rf(ctx, locale) + } else { + r0 = ret.Error(0) + } + + return r0 } // NewLocales creates a new instance of Locales. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLocales(t mockConstructorTestingTNewLocales) *Locales { +// The first argument is typically a *testing.T value. +func NewLocales(t interface { + mock.TestingT + Cleanup(func()) +}) *Locales { mock := &Locales{} mock.Mock.Test(t) diff --git a/pkg/locales/mocks/Storage.go b/pkg/locales/mocks/Storage.go index d37bd81cf7011e2498768c76102bb71a689eaf84..42946781b45c100bfb962fde0a2f6098699cec80 100644 --- a/pkg/locales/mocks/Storage.go +++ b/pkg/locales/mocks/Storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -20,7 +20,15 @@ type Storage struct { func (_m *Storage) Create(ctx context.Context, locale *locales.Locale) (*locales.Locale, error) { ret := _m.Called(ctx, locale) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 *locales.Locale + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) (*locales.Locale, error)); ok { + return rf(ctx, locale) + } if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) *locales.Locale); ok { r0 = rf(ctx, locale) } else { @@ -29,7 +37,6 @@ func (_m *Storage) Create(ctx context.Context, locale *locales.Locale) (*locales } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *locales.Locale) error); ok { r1 = rf(ctx, locale) } else { @@ -43,14 +50,21 @@ func (_m *Storage) Create(ctx context.Context, locale *locales.Locale) (*locales func (_m *Storage) Delete(ctx context.Context, spaceID string, filter *locales.Filter) (int, error) { ret := _m.Called(ctx, spaceID, filter) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, *locales.Filter) (int, error)); ok { + return rf(ctx, spaceID, filter) + } if rf, ok := ret.Get(0).(func(context.Context, string, *locales.Filter) int); ok { r0 = rf(ctx, spaceID, filter) } else { r0 = ret.Get(0).(int) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string, *locales.Filter) error); ok { r1 = rf(ctx, spaceID, filter) } else { @@ -64,7 +78,16 @@ func (_m *Storage) Delete(ctx context.Context, spaceID string, filter *locales.F func (_m *Storage) Find(ctx context.Context, spaceID string, filter *locales.Filter, opts *options.FindOptions) ([]*locales.Locale, int, error) { ret := _m.Called(ctx, spaceID, filter, opts) + if len(ret) == 0 { + panic("no return value specified for Find") + } + var r0 []*locales.Locale + var r1 int + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, string, *locales.Filter, *options.FindOptions) ([]*locales.Locale, int, error)); ok { + return rf(ctx, spaceID, filter, opts) + } if rf, ok := ret.Get(0).(func(context.Context, string, *locales.Filter, *options.FindOptions) []*locales.Locale); ok { r0 = rf(ctx, spaceID, filter, opts) } else { @@ -73,14 +96,12 @@ func (_m *Storage) Find(ctx context.Context, spaceID string, filter *locales.Fil } } - var r1 int if rf, ok := ret.Get(1).(func(context.Context, string, *locales.Filter, *options.FindOptions) int); ok { r1 = rf(ctx, spaceID, filter, opts) } else { r1 = ret.Get(1).(int) } - var r2 error if rf, ok := ret.Get(2).(func(context.Context, string, *locales.Filter, *options.FindOptions) error); ok { r2 = rf(ctx, spaceID, filter, opts) } else { @@ -94,6 +115,10 @@ func (_m *Storage) Find(ctx context.Context, spaceID string, filter *locales.Fil func (_m *Storage) Reset(ctx context.Context, spaceID string) error { ret := _m.Called(ctx, spaceID) + if len(ret) == 0 { + panic("no return value specified for Reset") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { r0 = rf(ctx, spaceID) @@ -104,13 +129,30 @@ func (_m *Storage) Reset(ctx context.Context, spaceID string) error { return r0 } -type mockConstructorTestingTNewStorage interface { - mock.TestingT - Cleanup(func()) +// Update provides a mock function with given fields: ctx, locale +func (_m *Storage) Update(ctx context.Context, locale *locales.Locale) error { + ret := _m.Called(ctx, locale) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *locales.Locale) error); ok { + r0 = rf(ctx, locale) + } else { + r0 = ret.Error(0) + } + + return r0 } // NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewStorage(t mockConstructorTestingTNewStorage) *Storage { +// The first argument is typically a *testing.T value. +func NewStorage(t interface { + mock.TestingT + Cleanup(func()) +}) *Storage { mock := &Storage{} mock.Mock.Test(t) diff --git a/pkg/locales/observer.go b/pkg/locales/observer.go new file mode 100644 index 0000000000000000000000000000000000000000..b6f7a56f6ba8971c7ce56c49ed77b592a0afd38c --- /dev/null +++ b/pkg/locales/observer.go @@ -0,0 +1,15 @@ +package locales + +import "context" + +type LocaleCreatedObserver interface { + OnLocaleCreated(ctx context.Context, locale *Locale) (delayedTaskID string, err error) +} + +type LocaleUpdatedObserver interface { + OnLocaleUpdated(ctx context.Context, before, locale *Locale) (delayedTaskID string, err error) +} + +type LocaleDeletedObserver interface { + OnLocaleDeleted(ctx context.Context, locale *Locale) (delayedTaskID string, err error) +} diff --git a/pkg/locales/service.go b/pkg/locales/service.go index 7724d7f7ecdb2f4733d97bff01113d105adabdeb..ba303e13f671a700a5518ca1b200cb48dcad5695 100644 --- a/pkg/locales/service.go +++ b/pkg/locales/service.go @@ -9,6 +9,7 @@ import ( // @grpc-addr content.locales.Locales type Locales interface { Create(ctx context.Context, locale *Locale) (created *Locale, err error) + Update(ctx context.Context, locale *Locale) (err error) List(ctx context.Context, spaceId string) (locales []*Locale, err error) Delete(ctx context.Context, spaceId, localeId string) (err error) } diff --git a/pkg/locales/storage.go b/pkg/locales/storage.go index c345706c5925119cf3eb84a07f91e57ff764f46f..facbb380e33d5f5e92e778cb54873b4d5fca4746 100644 --- a/pkg/locales/storage.go +++ b/pkg/locales/storage.go @@ -10,11 +10,18 @@ type Storage interface { Reset(ctx context.Context, spaceID string) error Create(ctx context.Context, locale *Locale) (created *Locale, err error) + Update(ctx context.Context, locale *Locale) (err error) Find(ctx context.Context, spaceID string, filter *Filter, opts *options.FindOptions) (locales []*Locale, total int, err error) Delete(ctx context.Context, spaceID string, filter *Filter) (total int, err error) } type Filter struct { - ID []string - Name []string + ID []string `json:"id"` + Name []string `json:"name"` + NativeName []string `json:"native_name"` + Code []string `json:"code"` + Fallback []string `json:"fallback"` + Direction []string `json:"direction"` + NoPublish *bool `json:"no_publish"` + Disabled *bool `json:"disabled"` } diff --git a/pkg/locales/transport/client.microgen.go b/pkg/locales/transport/client.go similarity index 62% rename from pkg/locales/transport/client.microgen.go rename to pkg/locales/transport/client.go index f8cd9dee23dafeff1d635b3f5ee42f6e5c8667f1..1aa9dc5169737c91ef96c981405ec6dbcea048c2 100644 --- a/pkg/locales/transport/client.microgen.go +++ b/pkg/locales/transport/client.go @@ -4,32 +4,32 @@ package transport import ( "context" - "errors" locales "git.perx.ru/perxis/perxis-go/pkg/locales" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *locales.Locale) (res0 *locales.Locale, res1 error) { request := CreateRequest{Locale: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 } +func (set EndpointsSet) Update(arg0 context.Context, arg1 *locales.Locale) (res1 error) { + request := UpdateRequest{Locale: arg1} + _, res1 = set.UpdateEndpoint(arg0, &request) + if res1 != nil { + return + } + return res1 +} + func (set EndpointsSet) List(arg0 context.Context, arg1 string) (res0 []*locales.Locale, res1 error) { request := ListRequest{SpaceId: arg1} response, res1 := set.ListEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListResponse).Locales, res1 @@ -37,14 +37,11 @@ func (set EndpointsSet) List(arg0 context.Context, arg1 string) (res0 []*locales func (set EndpointsSet) Delete(arg0 context.Context, arg1 string, arg2 string) (res0 error) { request := DeleteRequest{ - LocaleId: arg2, - SpaceId: arg1, + Id: arg2, + SpaceId: arg1, } _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/locales/transport/endpoints.microgen.go b/pkg/locales/transport/endpoints.microgen.go index ffca7318747104f8b58af332e90646f8cc6a8b9c..44dca7f2185e630db610b4ec162cfa125de97d49 100644 --- a/pkg/locales/transport/endpoints.microgen.go +++ b/pkg/locales/transport/endpoints.microgen.go @@ -7,6 +7,7 @@ import endpoint "github.com/go-kit/kit/endpoint" // EndpointsSet implements Locales API and used for transport purposes. type EndpointsSet struct { CreateEndpoint endpoint.Endpoint + UpdateEndpoint endpoint.Endpoint ListEndpoint endpoint.Endpoint DeleteEndpoint endpoint.Endpoint } diff --git a/pkg/locales/transport/exchanges.microgen.go b/pkg/locales/transport/exchanges.microgen.go index a07204e13a233fd7bae40c74e9984061871a92b7..14a4f1a6492f172de8f2b3df62ae6f632804f62f 100644 --- a/pkg/locales/transport/exchanges.microgen.go +++ b/pkg/locales/transport/exchanges.microgen.go @@ -12,6 +12,12 @@ type ( Created *locales.Locale `json:"created"` } + UpdateRequest struct { + Locale *locales.Locale `json:"locale"` + } + // Formal exchange type, please do not delete. + UpdateResponse struct{} + ListRequest struct { SpaceId string `json:"space_id"` } @@ -20,8 +26,8 @@ type ( } DeleteRequest struct { - SpaceId string `json:"space_id"` - LocaleId string `json:"locale_id"` + Id string `json:"id"` + SpaceId string `json:"space_id"` } // Formal exchange type, please do not delete. DeleteResponse struct{} diff --git a/pkg/locales/transport/grpc/client.go b/pkg/locales/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..877400ddeeaa54b265e43407bff4a9df548ff1be --- /dev/null +++ b/pkg/locales/transport/grpc/client.go @@ -0,0 +1,20 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/locales/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + ListEndpoint: grpcerr.ClientMiddleware(c.ListEndpoint), + } +} diff --git a/pkg/locales/transport/grpc/client.microgen.go b/pkg/locales/transport/grpc/client.microgen.go index 214cdf463436c71195457305de39516bd24e20d0..a8c0b9fcb06a8ed08edf72e495ceb240e2e53b80 100644 --- a/pkg/locales/transport/grpc/client.microgen.go +++ b/pkg/locales/transport/grpc/client.microgen.go @@ -22,6 +22,13 @@ func NewGRPCClient(conn *grpc.ClientConn, addr string, opts ...grpckit.ClientOpt pb.CreateResponse{}, opts..., ).Endpoint(), + UpdateEndpoint: grpckit.NewClient( + conn, addr, "Update", + _Encode_Update_Request, + _Decode_Update_Response, + empty.Empty{}, + opts..., + ).Endpoint(), DeleteEndpoint: grpckit.NewClient( conn, addr, "Delete", _Encode_Delete_Request, diff --git a/pkg/locales/transport/grpc/protobuf_endpoint_converters.microgen.go b/pkg/locales/transport/grpc/protobuf_endpoint_converters.microgen.go index f8124ba307afb6caa42b881a0c5778f465bf6f0f..c9c534131bf7e3be03bce9aeadfa3957d252ae2f 100644 --- a/pkg/locales/transport/grpc/protobuf_endpoint_converters.microgen.go +++ b/pkg/locales/transport/grpc/protobuf_endpoint_converters.microgen.go @@ -24,6 +24,18 @@ func _Encode_Create_Request(ctx context.Context, request interface{}) (interface return &pb.CreateRequest{Locale: pbLocale}, nil } +func _Encode_Update_Request(ctx context.Context, request interface{}) (interface{}, error) { + if request == nil { + return nil, errors.New("nil UpdateRequest") + } + req := request.(*transport.UpdateRequest) + pbLocale, err := PtrLocaleToProto(req.Locale) + if err != nil { + return nil, err + } + return &pb.UpdateRequest{Locale: pbLocale}, nil +} + func _Encode_List_Request(ctx context.Context, request interface{}) (interface{}, error) { if request == nil { return nil, errors.New("nil ListRequest") @@ -38,8 +50,8 @@ func _Encode_Delete_Request(ctx context.Context, request interface{}) (interface } req := request.(*transport.DeleteRequest) return &pb.DeleteRequest{ - LocaleId: req.LocaleId, - SpaceId: req.SpaceId, + Id: req.Id, + SpaceId: req.SpaceId, }, nil } @@ -55,6 +67,10 @@ func _Encode_Create_Response(ctx context.Context, response interface{}) (interfa return &pb.CreateResponse{Locale: respLocale}, nil } +func _Encode_Update_Response(ctx context.Context, response interface{}) (interface{}, error) { + return &empty.Empty{}, nil +} + func _Encode_List_Response(ctx context.Context, response interface{}) (interface{}, error) { if response == nil { return nil, errors.New("nil ListResponse") @@ -83,6 +99,18 @@ func _Decode_Create_Request(ctx context.Context, request interface{}) (interface return &transport.CreateRequest{Locale: locale}, nil } +func _Decode_Update_Request(ctx context.Context, request interface{}) (interface{}, error) { + if request == nil { + return nil, errors.New("nil UpdateRequest") + } + req := request.(*pb.UpdateRequest) + locale, err := ProtoToPtrLocale(req.Locale) + if err != nil { + return nil, err + } + return &transport.UpdateRequest{Locale: locale}, nil +} + func _Decode_List_Request(ctx context.Context, request interface{}) (interface{}, error) { if request == nil { return nil, errors.New("nil ListRequest") @@ -97,8 +125,8 @@ func _Decode_Delete_Request(ctx context.Context, request interface{}) (interface } req := request.(*pb.DeleteRequest) return &transport.DeleteRequest{ - LocaleId: string(req.LocaleId), - SpaceId: string(req.SpaceId), + Id: string(req.Id), + SpaceId: string(req.SpaceId), }, nil } @@ -114,6 +142,10 @@ func _Decode_Create_Response(ctx context.Context, response interface{}) (interfa return &transport.CreateResponse{Created: respLocale}, nil } +func _Decode_Update_Response(ctx context.Context, response interface{}) (interface{}, error) { + return &empty.Empty{}, nil +} + func _Decode_List_Response(ctx context.Context, response interface{}) (interface{}, error) { if response == nil { return nil, errors.New("nil ListResponse") diff --git a/pkg/locales/transport/grpc/protobuf_type_converters.microgen.go b/pkg/locales/transport/grpc/protobuf_type_converters.microgen.go index 6dca0bb8afa68dfe3fa17b53d315f3716c48ae36..4932a7d497ea2d0df148dddbfb0a7bbda3dca300 100644 --- a/pkg/locales/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/locales/transport/grpc/protobuf_type_converters.microgen.go @@ -13,14 +13,14 @@ func PtrLocaleToProto(locale *service.Locale) (*pb.Locale, error) { if locale == nil { return nil, nil } - return &pb.Locale{Id: locale.ID, Name: locale.Name, SpaceId: locale.SpaceID}, nil + return service.LocaleToProto(locale), nil } func ProtoToPtrLocale(protoLocale *pb.Locale) (*service.Locale, error) { if protoLocale == nil { return nil, nil } - return &service.Locale{ID: protoLocale.Id, Name: protoLocale.Name, SpaceID: protoLocale.SpaceId}, nil + return service.LocaleFromProto(protoLocale), nil } func ListPtrLocaleToProto(locales []*service.Locale) ([]*pb.Locale, error) { diff --git a/pkg/locales/transport/grpc/server.go b/pkg/locales/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..ca4f95aeff638c95da871d40b9ce999b1b108299 --- /dev/null +++ b/pkg/locales/transport/grpc/server.go @@ -0,0 +1,20 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/locales" + "git.perx.ru/perxis/perxis-go/pkg/locales/transport" + pb "git.perx.ru/perxis/perxis-go/proto/locales" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc locales.Locales, opts ...grpckit.ServerOption) pb.LocalesServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + ListEndpoint: grpcerr.ServerMiddleware(eps.ListEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/locales/transport/grpc/server.microgen.go b/pkg/locales/transport/grpc/server.microgen.go index fe25ca1a7b676599d5d09463cdbb6c11aba87939..80778f883bafb2aba5d926526b162cded6db53a7 100644 --- a/pkg/locales/transport/grpc/server.microgen.go +++ b/pkg/locales/transport/grpc/server.microgen.go @@ -13,6 +13,7 @@ import ( type localesServer struct { create grpc.Handler + update grpc.Handler list grpc.Handler delete grpc.Handler @@ -27,6 +28,12 @@ func NewGRPCServer(endpoints *transport.EndpointsSet, opts ...grpc.ServerOption) _Encode_Create_Response, opts..., ), + update: grpc.NewServer( + endpoints.UpdateEndpoint, + _Decode_Update_Request, + _Encode_Update_Response, + opts..., + ), delete: grpc.NewServer( endpoints.DeleteEndpoint, _Decode_Delete_Request, @@ -50,6 +57,14 @@ func (S *localesServer) Create(ctx context.Context, req *pb.CreateRequest) (*pb. return resp.(*pb.CreateResponse), nil } +func (S *localesServer) Update(ctx context.Context, req *pb.UpdateRequest) (*empty.Empty, error) { + _, resp, err := S.update.ServeGRPC(ctx, req) + if err != nil { + return nil, err + } + return resp.(*empty.Empty), nil +} + func (S *localesServer) List(ctx context.Context, req *pb.ListRequest) (*pb.ListResponse, error) { _, resp, err := S.list.ServeGRPC(ctx, req) if err != nil { diff --git a/pkg/locales/transport/server.microgen.go b/pkg/locales/transport/server.microgen.go index 5ce815dcb52415a93ddfeb095f99e22fb14c4492..081edcd5c304fa5526e031181e80c78903b1e707 100644 --- a/pkg/locales/transport/server.microgen.go +++ b/pkg/locales/transport/server.microgen.go @@ -12,6 +12,7 @@ import ( func Endpoints(svc locales.Locales) EndpointsSet { return EndpointsSet{ CreateEndpoint: CreateEndpoint(svc), + UpdateEndpoint: UpdateEndpoint(svc), DeleteEndpoint: DeleteEndpoint(svc), ListEndpoint: ListEndpoint(svc), } @@ -25,6 +26,14 @@ func CreateEndpoint(svc locales.Locales) endpoint.Endpoint { } } +func UpdateEndpoint(svc locales.Locales) endpoint.Endpoint { + return func(arg0 context.Context, request interface{}) (interface{}, error) { + req := request.(*UpdateRequest) + res1 := svc.Update(arg0, req.Locale) + return &UpdateResponse{}, res1 + } +} + func ListEndpoint(svc locales.Locales) endpoint.Endpoint { return func(arg0 context.Context, request interface{}) (interface{}, error) { req := request.(*ListRequest) @@ -36,7 +45,7 @@ func ListEndpoint(svc locales.Locales) endpoint.Endpoint { func DeleteEndpoint(svc locales.Locales) endpoint.Endpoint { return func(arg0 context.Context, request interface{}) (interface{}, error) { req := request.(*DeleteRequest) - res0 := svc.Delete(arg0, req.SpaceId, req.LocaleId) + res0 := svc.Delete(arg0, req.SpaceId, req.Id) return &DeleteResponse{}, res0 } } diff --git a/pkg/members/events.go b/pkg/members/events.go new file mode 100644 index 0000000000000000000000000000000000000000..5fef6d772c510e5adf37bedc9738c6c50e7a9ee4 --- /dev/null +++ b/pkg/members/events.go @@ -0,0 +1,7 @@ +package members + +const ( + EventSet = "members.set" + EventRemove = "members.remove" + EventRemoveAll = "members.remove_all" +) diff --git a/pkg/members/members.go b/pkg/members/members.go index 0993b6fddfe34cf7f257e6b70433893485a60dba..28ae060e2dacf12a61ef3e9d99831e01689d39b2 100644 --- a/pkg/members/members.go +++ b/pkg/members/members.go @@ -2,6 +2,7 @@ package members import ( "fmt" + "strconv" ) type Member struct { @@ -10,6 +11,14 @@ type Member struct { Role Role `bson:"role"` } +func (m Member) Clone() *Member { + return &Member{ + OrgId: m.OrgId, + UserId: m.UserId, + Role: m.Role, + } +} + type Role uint const ( @@ -24,12 +33,37 @@ func (r Role) IsPrivileged() bool { } func (r Role) Format(s fmt.State, verb rune) { + switch verb { + case 's': + _, _ = s.Write([]byte(r.String())) + default: + _, _ = s.Write([]byte(strconv.Itoa(int(r)))) + } +} + +func (r Role) String() string { switch r { + case NotMember: + return "not member" + case RoleMember: + return "member" case RoleOwner: - fmt.Fprint(s, "owner") + return "owner" case RoleAdmin: - fmt.Fprint(s, "admin") - case RoleMember: - fmt.Fprint(s, "member") + return "admin" + } + return fmt.Sprintf("%d", r) +} + +func RoleFromString(r string) Role { + switch r { + case RoleMember.String(): + return RoleMember + case RoleOwner.String(): + return RoleOwner + case RoleAdmin.String(): + return RoleAdmin + default: + return NotMember } } diff --git a/pkg/members/members_test.go b/pkg/members/members_test.go new file mode 100644 index 0000000000000000000000000000000000000000..4343b75e17b4d91743f1faf3e69bdce81851e03c --- /dev/null +++ b/pkg/members/members_test.go @@ -0,0 +1,65 @@ +package members + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFormat(t *testing.T) { + tests := []struct { + name string + template string + want string + role Role + }{ + { + name: "NotMember with %s", + template: "%s", + role: NotMember, + want: "not member", + }, + { + name: "RoleMember with %s", + role: RoleMember, + template: "%s", + want: "member", + }, + { + name: "RoleOwner with %s", + role: RoleOwner, + template: "%s", + want: "owner", + }, + { + name: "RoleAdmin with %s", + role: RoleAdmin, + template: "%s", + want: "admin", + }, + { + name: "Existent role with %d", + role: RoleAdmin, + template: "%d", + want: "3", + }, + { + name: "Non-existent role with %s", + role: 4, + template: "%s", + want: "4", + }, + { + name: "Non-existent role with %d", + role: 4, + template: "%d", + want: "4", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, fmt.Sprintf(tt.template, tt.role)) + }) + } +} diff --git a/pkg/members/middleware/caching_middleware.go b/pkg/members/middleware/caching_middleware.go index 0af3f76f9e5aa1eeeee01c36f2e7509e35e951c3..4c61bff9078028009130bc7378908a6db551bba2 100644 --- a/pkg/members/middleware/caching_middleware.go +++ b/pkg/members/middleware/caching_middleware.go @@ -5,6 +5,7 @@ import ( "strings" "git.perx.ru/perxis/perxis-go/pkg/cache" + "git.perx.ru/perxis/perxis-go/pkg/data" service "git.perx.ru/perxis/perxis-go/pkg/members" ) @@ -30,9 +31,9 @@ func (m cachingMiddleware) Set(ctx context.Context, orgId string, userId string, err = m.next.Set(ctx, orgId, userId, role) if err == nil { - m.cache.Remove(makeKey(orgId, userId)) - m.cache.Remove(makeKey(orgId)) - m.cache.Remove(makeKey(userId)) + _ = m.cache.Remove(makeKey(orgId, userId)) + _ = m.cache.Remove(makeKey(orgId)) + _ = m.cache.Remove(makeKey(userId)) } return err } @@ -46,7 +47,7 @@ func (m cachingMiddleware) Get(ctx context.Context, orgId string, userId string) } role, err = m.next.Get(ctx, orgId, userId) if err == nil { - m.cache.Set(key, role) + _ = m.cache.Set(key, role) } return role, err } @@ -55,9 +56,9 @@ func (m cachingMiddleware) Remove(ctx context.Context, orgId string, userId stri err = m.next.Remove(ctx, orgId, userId) if err == nil { - m.cache.Remove(makeKey(orgId, userId)) - m.cache.Remove(makeKey(orgId)) - m.cache.Remove(makeKey(userId)) + _ = m.cache.Remove(makeKey(orgId, userId)) + _ = m.cache.Remove(makeKey(orgId)) + _ = m.cache.Remove(makeKey(userId)) } return err } @@ -68,8 +69,8 @@ func (m cachingMiddleware) RemoveAll(ctx context.Context, orgId string) (err err if err == nil { members, _ := m.ListMembers(ctx, orgId) for _, member := range members { - m.cache.Remove(member.UserId) - m.cache.Remove(makeKey(orgId, member.UserId)) + _ = m.cache.Remove(member.UserId) + _ = m.cache.Remove(makeKey(orgId, member.UserId)) } } return err @@ -79,24 +80,26 @@ func (m cachingMiddleware) ListMembers(ctx context.Context, orgId string) (membe value, e := m.cache.Get(makeKey(orgId)) if e == nil { - return value.([]*service.Member), err + return data.CloneSlice(value.([]*service.Member)), nil } members, err = m.next.ListMembers(ctx, orgId) if err == nil { - m.cache.Set(makeKey(orgId), members) + _ = m.cache.Set(makeKey(orgId), members) + return data.CloneSlice(members), nil } - return members, err + return nil, err } func (m cachingMiddleware) ListOrganizations(ctx context.Context, userId string) (members []*service.Member, err error) { value, e := m.cache.Get(makeKey(userId)) if e == nil { - return value.([]*service.Member), err + return data.CloneSlice(value.([]*service.Member)), nil } members, err = m.next.ListOrganizations(ctx, userId) if err == nil { - m.cache.Set(makeKey(userId), members) + _ = m.cache.Set(makeKey(userId), members) + return data.CloneSlice(members), nil } - return members, err + return nil, err } diff --git a/pkg/members/middleware/caching_middleware_test.go b/pkg/members/middleware/caching_middleware_test.go index eda7eb3a2a85123d36d20f09e9bd0c5188b609a9..ea09d522188857ee841336e4d8dbdf9cad7ff55c 100644 --- a/pkg/members/middleware/caching_middleware_test.go +++ b/pkg/members/middleware/caching_middleware_test.go @@ -129,6 +129,7 @@ func TestMembersCache(t *testing.T) { mbrs.On("Get", mock.Anything, orgId, userId).Return(members.RoleOwner, nil).Once() v1, err := svc.Get(ctx, orgId, userId) + require.NoError(t, err) v2, err := svc.Get(ctx, orgId, userId) require.NoError(t, err) diff --git a/pkg/members/middleware/logging_middleware.go b/pkg/members/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..b967a8b4ffb5729baf69c6d08899fdb7dfa0f0ea --- /dev/null +++ b/pkg/members/middleware/logging_middleware.go @@ -0,0 +1,122 @@ +package middleware + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/members" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next members.Members +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next members.Members) members.Members { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Members")), + } + } +} + +func (m *loggingMiddleware) Set(ctx context.Context, orgId, userId string, role members.Role) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(members.EventSet), + logzap.Object(id.NewOrganizationId(orgId)), + ) + + err = m.next.Set(ctx, orgId, userId, role) + if err != nil { + logger.Error(fmt.Sprintf("Failed to assign user '%s' to role '%s'", userId, role), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("User '%s' assigned to role '%s'", userId, role), logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Get(ctx context.Context, orgId, userId string) (role members.Role, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewRoleId(orgId, userId)), + ) + + role, err = m.next.Get(ctx, orgId, userId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return role, err +} + +func (m *loggingMiddleware) Remove(ctx context.Context, orgId, userId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(members.EventRemove), + logzap.Object(id.NewOrganizationId(orgId)), + ) + + err = m.next.Remove(ctx, orgId, userId) + if err != nil { + logger.Error(fmt.Sprintf("Failed to remove user '%s'", userId), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("User '%s' removed", userId), logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) RemoveAll(ctx context.Context, orgId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(members.EventRemoveAll), + logzap.Object(id.NewOrganizationId(orgId)), + ) + + err = m.next.RemoveAll(ctx, orgId) + if err != nil { + logger.Error("Failed to remove all members", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("All members removed", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) ListMembers(ctx context.Context, orgId string) (members []*members.Member, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + members, err = m.next.ListMembers(ctx, orgId) + if err != nil { + logger.Error("Failed to list members", zap.Error(err)) + return + } + + return members, err +} + +func (m *loggingMiddleware) ListOrganizations(ctx context.Context, userId string) (organizations []*members.Member, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + organizations, err = m.next.ListOrganizations(ctx, userId) + if err != nil { + logger.Error("Failed to list organizations", zap.Error(err)) + return + } + + return organizations, err +} diff --git a/pkg/members/middleware/middleware.go b/pkg/members/middleware/middleware.go index bb491623865e21496adedb1e91987bc2205a3ce4..04626790010ac2da99f00e8501d1c4186683e6b7 100644 --- a/pkg/members/middleware/middleware.go +++ b/pkg/members/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s members.Members, logger *zap.Logger, log_access bool) members.Mem if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/members/observer/transport/client.microgen.go b/pkg/members/observer/transport/client.go similarity index 68% rename from pkg/members/observer/transport/client.microgen.go rename to pkg/members/observer/transport/client.go index 28ca2a88bdbb5e5095b8c2f7d2e9a5e85b67cc09..957fd556fe9e43bac595faed40a5da3b6bd06045 100644 --- a/pkg/members/observer/transport/client.microgen.go +++ b/pkg/members/observer/transport/client.go @@ -4,20 +4,14 @@ package transport import ( "context" - "errors" collaborators "git.perx.ru/perxis/perxis-go/pkg/collaborators" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) OnCollaboratorSet(arg0 context.Context, arg1 *collaborators.Collaborator) (res0 string, res1 error) { request := OnCollaboratorSetRequest{Collaborator: arg1} response, res1 := set.OnCollaboratorSetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*OnCollaboratorSetResponse).DelayedTaskID, res1 diff --git a/pkg/members/observer/transport/grpc/client.go b/pkg/members/observer/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..321ee07dcfe5a964c60a114c18b8f2abe88cc2a3 --- /dev/null +++ b/pkg/members/observer/transport/grpc/client.go @@ -0,0 +1,17 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/members/observer/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + OnCollaboratorSetEndpoint: grpcerr.ClientMiddleware(c.OnCollaboratorSetEndpoint), + } +} diff --git a/pkg/members/observer/transport/grpc/server.go b/pkg/members/observer/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..beb4b614b2466ea6bbe9aa7da73b64c863fad276 --- /dev/null +++ b/pkg/members/observer/transport/grpc/server.go @@ -0,0 +1,17 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/members/observer" + "git.perx.ru/perxis/perxis-go/pkg/members/observer/transport" + pb "git.perx.ru/perxis/perxis-go/proto/members" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc observer.Observer, opts ...grpckit.ServerOption) pb.ObserverServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + OnCollaboratorSetEndpoint: grpcerr.ServerMiddleware(eps.OnCollaboratorSetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/members/transport/client.microgen.go b/pkg/members/transport/client.go similarity index 68% rename from pkg/members/transport/client.microgen.go rename to pkg/members/transport/client.go index 4cd10cad5b1b970f30a9380eae77a5d706748a08..8b3b27bdf0eb100e2b147505d3a638812ee3286b 100644 --- a/pkg/members/transport/client.microgen.go +++ b/pkg/members/transport/client.go @@ -4,11 +4,8 @@ package transport import ( "context" - "errors" members "git.perx.ru/perxis/perxis-go/pkg/members" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Set(arg0 context.Context, arg1 string, arg2 string, arg3 members.Role) (res0 error) { @@ -19,9 +16,6 @@ func (set EndpointsSet) Set(arg0 context.Context, arg1 string, arg2 string, arg3 } _, res0 = set.SetEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -34,9 +28,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string) (res } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Role, res1 @@ -49,9 +40,6 @@ func (set EndpointsSet) Remove(arg0 context.Context, arg1 string, arg2 string) ( } _, res0 = set.RemoveEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -65,9 +53,6 @@ func (set EndpointsSet) ListMembers(arg0 context.Context, arg1 string) (res0 []* request := ListMembersRequest{OrgId: arg1} response, res1 := set.ListMembersEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListMembersResponse).Members, res1 @@ -77,9 +62,6 @@ func (set EndpointsSet) ListOrganizations(arg0 context.Context, arg1 string) (re request := ListOrganizationsRequest{UserId: arg1} response, res1 := set.ListOrganizationsEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListOrganizationsResponse).Organizations, res1 diff --git a/pkg/members/transport/grpc/client.go b/pkg/members/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..dc79e343c6bb173a64752d536bdd6bc1ba88e740 --- /dev/null +++ b/pkg/members/transport/grpc/client.go @@ -0,0 +1,21 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/members/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + ListMembersEndpoint: grpcerr.ClientMiddleware(c.ListMembersEndpoint), + ListOrganizationsEndpoint: grpcerr.ClientMiddleware(c.ListOrganizationsEndpoint), + RemoveEndpoint: grpcerr.ClientMiddleware(c.RemoveEndpoint), + SetEndpoint: grpcerr.ClientMiddleware(c.SetEndpoint), + } +} diff --git a/pkg/members/transport/grpc/server.go b/pkg/members/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..d87048167b71a4cc22e031f164ee4725e7534428 --- /dev/null +++ b/pkg/members/transport/grpc/server.go @@ -0,0 +1,21 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/members" + "git.perx.ru/perxis/perxis-go/pkg/members/transport" + pb "git.perx.ru/perxis/perxis-go/proto/members" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc members.Members, opts ...grpckit.ServerOption) pb.MembersServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + ListMembersEndpoint: grpcerr.ServerMiddleware(eps.ListMembersEndpoint), + ListOrganizationsEndpoint: grpcerr.ServerMiddleware(eps.ListOrganizationsEndpoint), + RemoveEndpoint: grpcerr.ServerMiddleware(eps.RemoveEndpoint), + SetEndpoint: grpcerr.ServerMiddleware(eps.SetEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/operation/operation.go b/pkg/operation/operation.go index bbe73370c21ce1a0c290fd53cd8a2225ba62cc4a..c6c46ca3a4353bbc663fb553477c0e8adcfd849f 100644 --- a/pkg/operation/operation.go +++ b/pkg/operation/operation.go @@ -5,9 +5,9 @@ import ( "fmt" "time" + "git.perx.ru/perxis/perxis-go/id" "git.perx.ru/perxis/perxis-go/pkg/errors" grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" - "git.perx.ru/perxis/perxis-go/pkg/id" "git.perx.ru/perxis/perxis-go/proto/common" "google.golang.org/grpc" "google.golang.org/protobuf/proto" diff --git a/pkg/operation/service.go b/pkg/operation/service.go index b4d5c30e757771bae22b7b460fd2c7e5336a80fc..06512505fdb50569a99fc0eeb79193bb0d62be87 100644 --- a/pkg/operation/service.go +++ b/pkg/operation/service.go @@ -129,7 +129,7 @@ func (s *service) Create(ctx context.Context, desc string, fn func(ctx context.C // Создаем новый контекст для фоновой операции без Deadline opCtx, cancel := context.WithCancel(auth.WithPrincipal(context.Background(), principal)) op.SetCancelFunc(cancel) - s.Set(opCtx, op) + _ = s.Set(opCtx, op) go func() { response, err := fn(opCtx) @@ -137,11 +137,11 @@ func (s *service) Create(ctx context.Context, desc string, fn func(ctx context.C op.SetError(err) } if response != nil { - op.SetResponse(response) + _ = op.SetResponse(response) } op.SetModifiedAt(time.Now()) op.SetDone(true) - s.Set(opCtx, op) + _ = s.Set(opCtx, op) }() return op, nil diff --git a/pkg/organizations/events.go b/pkg/organizations/events.go new file mode 100644 index 0000000000000000000000000000000000000000..d477de46fe0e9ca360d6d61a080a01c9a6e13163 --- /dev/null +++ b/pkg/organizations/events.go @@ -0,0 +1,7 @@ +package organizations + +const ( + EventCreate = "organizations.create" + EventDelete = "organizations.delete" + EventUpdate = "organizations.update" +) diff --git a/pkg/organizations/middleware/caching_middleware.go b/pkg/organizations/middleware/caching_middleware.go index 18649df9511f12a658cbb3966d507a76108939d8..c6503200cfbc47915475a95c154a253dec51e29c 100644 --- a/pkg/organizations/middleware/caching_middleware.go +++ b/pkg/organizations/middleware/caching_middleware.go @@ -30,20 +30,21 @@ func (m cachingMiddleware) Get(ctx context.Context, orgId string) (organization value, e := m.cache.Get(orgId) if e == nil { - return value.(*service.Organization), err + return value.(*service.Organization).Clone(), nil } organization, err = m.next.Get(ctx, orgId) if err == nil { - m.cache.Set(orgId, organization) + _ = m.cache.Set(orgId, organization) + return organization.Clone(), nil } - return organization, err + return nil, err } func (m cachingMiddleware) Update(ctx context.Context, org *service.Organization) (err error) { err = m.next.Update(ctx, org) if err == nil { - m.cache.Remove(org.ID) + _ = m.cache.Remove(org.ID) } return err } @@ -52,7 +53,7 @@ func (m cachingMiddleware) Delete(ctx context.Context, orgId string) (err error) err = m.next.Delete(ctx, orgId) if err == nil { - m.cache.Remove(orgId) + _ = m.cache.Remove(orgId) } return err } diff --git a/pkg/organizations/middleware/caching_middleware_test.go b/pkg/organizations/middleware/caching_middleware_test.go index 19cd14d5b2e808f3d4c22f77d8b115a27a9025cf..f9999cfce509debda6b49d5aa5ee26a3d60d0f4f 100644 --- a/pkg/organizations/middleware/caching_middleware_test.go +++ b/pkg/organizations/middleware/caching_middleware_test.go @@ -37,7 +37,8 @@ func TestOrganizationsCache(t *testing.T) { v2, err := svc.Get(ctx, orgId) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) orgs.AssertExpectations(t) }) @@ -54,16 +55,18 @@ func TestOrganizationsCache(t *testing.T) { v2, err := svc.Get(ctx, orgId) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) orgs.On("Update", mock.Anything, mock.Anything).Return(nil).Once() err = svc.Update(ctx, &organizations.Organization{ID: orgId, Name: "OrganizationUPD"}) + require.NoError(t, err) orgs.On("Get", mock.Anything, orgId).Return(&organizations.Organization{ID: orgId, Name: "OrganizationUPD"}, nil).Once() v3, err := svc.Get(ctx, orgId) require.NoError(t, err) - assert.NotSame(t, v2, v3, "Ожидается удаление объекта из кэша после обновления и получение заново из сервиса.") + assert.NotEqual(t, v2, v3, "Ожидается удаление объекта из кэша после обновления и получение заново из сервиса.") orgs.AssertExpectations(t) }) @@ -79,10 +82,12 @@ func TestOrganizationsCache(t *testing.T) { v2, err := svc.Get(ctx, orgId) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) orgs.On("Delete", mock.Anything, mock.Anything).Return(nil).Once() err = svc.Delete(ctx, orgId) + require.NoError(t, err) orgs.On("Get", mock.Anything, orgId).Return(nil, errNotFound).Once() @@ -103,7 +108,8 @@ func TestOrganizationsCache(t *testing.T) { v2, err := svc.Get(ctx, orgId) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) @@ -112,6 +118,8 @@ func TestOrganizationsCache(t *testing.T) { v3, err := svc.Get(ctx, orgId) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается удаление объекта из кэша и получение заново из сервиса.") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) orgs.AssertExpectations(t) }) diff --git a/pkg/organizations/middleware/logging_middleware.go b/pkg/organizations/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..bda7f54fb101777758978a393bf43b52b1532b28 --- /dev/null +++ b/pkg/organizations/middleware/logging_middleware.go @@ -0,0 +1,108 @@ +package middleware + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/organizations" + + "git.perx.ru/perxis/perxis-go/pkg/options" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next organizations.Organizations +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next organizations.Organizations) organizations.Organizations { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Organizations")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, org *organizations.Organization) (created *organizations.Organization, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(organizations.EventCreate), + ) + + created, err = m.next.Create(ctx, org) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(org)) + return + } + + logger.Info("Organization created", logzap.Channels(logzap.Userlog), logzap.Object(created)) + + return created, err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, orgId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(organizations.EventDelete), + logzap.Object(id.NewOrganizationId(orgId)), + ) + + err = m.next.Delete(ctx, orgId) + if err != nil { + logger.Error("Failed to delete", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Organization deleted", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Find(ctx context.Context, filter *organizations.Filter, opts *options.FindOptions) (orgs []*organizations.Organization, total int, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + orgs, total, err = m.next.Find(ctx, filter, opts) + if err != nil { + logger.Error("Failed to find", zap.Error(err)) + return + } + + return orgs, total, err +} + +func (m *loggingMiddleware) Get(ctx context.Context, orgId string) (org *organizations.Organization, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewOrganizationId(orgId)), + ) + + org, err = m.next.Get(ctx, orgId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return org, err +} + +func (m *loggingMiddleware) Update(ctx context.Context, org *organizations.Organization) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(organizations.EventUpdate), + logzap.Object(org), + ) + + err = m.next.Update(ctx, org) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Organization updated", logzap.Channels(logzap.Userlog)) + + return err +} diff --git a/pkg/organizations/middleware/middleware.go b/pkg/organizations/middleware/middleware.go index 906a4c356b434fa2926a3e970bf0f32d0c0fa936..83808ec26d317f68a07b7b49c772911be1381fcb 100644 --- a/pkg/organizations/middleware/middleware.go +++ b/pkg/organizations/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s organizations.Organizations, logger *zap.Logger, log_access bool) if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/organizations/organization.go b/pkg/organizations/organization.go index b95daa6988710d26fcda200eebef8afeff9158df..8c6df31c766487d3978ef35e73d043343ab7d090 100644 --- a/pkg/organizations/organization.go +++ b/pkg/organizations/organization.go @@ -8,6 +8,16 @@ type Organization struct { OwnerID *string `bson:"-"` } +func (o Organization) Clone() *Organization { + return &Organization{ + ID: o.ID, + Name: o.Name, + Description: o.Description, + LogoURL: o.LogoURL, + OwnerID: o.OwnerID, + } +} + func (o *Organization) SetOwnerID(s string) *Organization { o.OwnerID = &s return o diff --git a/pkg/organizations/transport/client.microgen.go b/pkg/organizations/transport/client.go similarity index 67% rename from pkg/organizations/transport/client.microgen.go rename to pkg/organizations/transport/client.go index 00b14af754877e02fe3936269d72cb13c7b138da..e08e3346129b8ec886f3eb83709c4047fd4eac43 100644 --- a/pkg/organizations/transport/client.microgen.go +++ b/pkg/organizations/transport/client.go @@ -4,21 +4,15 @@ package transport import ( "context" - "errors" options "git.perx.ru/perxis/perxis-go/pkg/options" organizations "git.perx.ru/perxis/perxis-go/pkg/organizations" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *organizations.Organization) (res0 *organizations.Organization, res1 error) { request := CreateRequest{Org: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 @@ -28,9 +22,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string) (res0 *organizati request := GetRequest{OrgId: arg1} response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Org, res1 @@ -40,9 +31,6 @@ func (set EndpointsSet) Update(arg0 context.Context, arg1 *organizations.Organiz request := UpdateRequest{Org: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -52,9 +40,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string) (res0 error) { request := DeleteRequest{OrgId: arg1} _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -67,9 +52,6 @@ func (set EndpointsSet) Find(arg0 context.Context, arg1 *organizations.Filter, a } response, res2 := set.FindEndpoint(arg0, &request) if res2 != nil { - if e, ok := status.FromError(res2); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res2 = errors.New(e.Message()) - } return } return response.(*FindResponse).Orgs, response.(*FindResponse).Total, res2 diff --git a/pkg/organizations/transport/grpc/client.go b/pkg/organizations/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..3e8793d1b81dd2c6e28b2c24a6be7b4d5b23ff95 --- /dev/null +++ b/pkg/organizations/transport/grpc/client.go @@ -0,0 +1,21 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/organizations/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + FindEndpoint: grpcerr.ClientMiddleware(c.FindEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + } +} diff --git a/pkg/organizations/transport/grpc/server.go b/pkg/organizations/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..8748dabd8cd66b1c0597dce50b1cf43f87938d2e --- /dev/null +++ b/pkg/organizations/transport/grpc/server.go @@ -0,0 +1,21 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/organizations" + "git.perx.ru/perxis/perxis-go/pkg/organizations/transport" + pb "git.perx.ru/perxis/perxis-go/proto/organizations" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc organizations.Organizations, opts ...grpckit.ServerOption) pb.OrganizationsServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + FindEndpoint: grpcerr.ServerMiddleware(eps.FindEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/queue/queue.go b/pkg/queue/queue.go index 34075f23240f0aff3002f1ad576fd204d620f9e7..adc8ed6e7e35b749a9b281484496e8ff7b991aa1 100644 --- a/pkg/queue/queue.go +++ b/pkg/queue/queue.go @@ -5,12 +5,12 @@ import ( "sync" "time" + "git.perx.ru/perxis/perxis-go/id" "git.perx.ru/perxis/perxis-go/pkg/errors" - "git.perx.ru/perxis/perxis-go/pkg/id" ) const ( - defaultSize = 100 + defaultSize = 10_000 defaultStoreResultsTTL = 1 * time.Hour ) diff --git a/pkg/references/field.go b/pkg/references/field.go index c98ed2298150e012545d55d5364f62c4f44eac1b..f80e7b5a564efe81df2969fb35f14d69fd23a1c8 100644 --- a/pkg/references/field.go +++ b/pkg/references/field.go @@ -18,17 +18,31 @@ type ReferenceParameters struct { } func (p ReferenceParameters) Type() field.Type { return &ReferenceType{} } - func (p ReferenceParameters) Clone(reset bool) field.Parameters { if p.AllowedCollections != nil { cols := make([]string, 0, len(p.AllowedCollections)) - for _, c := range p.AllowedCollections { - cols = append(cols, c) - } + cols = append(cols, p.AllowedCollections...) p.AllowedCollections = cols } return &p } +func (p ReferenceParameters) GetField(f *field.Field, name string) *field.Field { + var fld *field.Field + switch name { + case "id", "collection_id": + return field.String() + case "disabled": + return field.Bool() + } + return f.SetFieldState(name, fld) +} +func (p ReferenceParameters) ListFields(f *field.Field, filter ...field.FieldFilterFunc) []*field.Field { + return []*field.Field{ + f.SetFieldState("id", field.String()), + f.SetFieldState("collection_id", field.String()), + f.SetFieldState("disabled", field.Bool()), + } +} type ReferenceType struct{} diff --git a/pkg/references/field_test.go b/pkg/references/field_test.go index a51cb2ac65a3483cbe58169421734f17b6dce20c..ac9d5c03db107ed8f284cab3c9205afe95f1502b 100644 --- a/pkg/references/field_test.go +++ b/pkg/references/field_test.go @@ -255,7 +255,7 @@ func TestReferenceField_Validate(t *testing.T) { refs := []*Reference{ {ID: "111", CollectionID: "media"}, } - err := validate.Validate(nil, f, refs) + err := validate.Validate(context.Background(), f, refs) require.NoError(t, err) }) t.Run("Limit exceeded", func(t *testing.T) { @@ -264,7 +264,7 @@ func TestReferenceField_Validate(t *testing.T) { {ID: "111", CollectionID: "media"}, {ID: "222", CollectionID: "media"}, } - err := validate.Validate(nil, f, refs) + err := validate.Validate(context.Background(), f, refs) require.Error(t, err) require.Contains(t, err.Error(), "validation error: maximum elements number is 1") }) @@ -273,13 +273,13 @@ func TestReferenceField_Validate(t *testing.T) { t.Run("Correct", func(t *testing.T) { f := Field(nil, validate.Required()) ref := &Reference{ID: "111", CollectionID: "media"} - err := validate.Validate(nil, f, ref) + err := validate.Validate(context.Background(), f, ref) require.NoError(t, err) }) t.Run("Empty", func(t *testing.T) { f := Field(nil, validate.Required()) ref := &Reference{} - err := validate.Validate(nil, f, ref) + err := validate.Validate(context.Background(), f, ref) require.Error(t, err) require.Contains(t, err.Error(), "validation error: value is required") }) @@ -298,3 +298,23 @@ func TestReference_JSON(t *testing.T) { assert.Equal(t, fld, res) } + +func TestReferenceField_Get(t *testing.T) { + sch := schema.New( + "a", field.String(), + "b", field.Object( + "ref", Field(nil), + ), + "ref", Field(nil), + ) + sch.ClearState() + + assert.Equal(t, field.String(), sch.GetField("ref.id")) + assert.Equal(t, field.String(), sch.GetField("ref.collection_id")) + assert.Equal(t, field.Bool(), sch.GetField("ref.disabled")) + + assert.Equal(t, field.String(), sch.GetField("b.ref.id")) + assert.Equal(t, field.String(), sch.GetField("b.ref.collection_id")) + assert.Equal(t, field.Bool(), sch.GetField("b.ref.disabled")) + +} diff --git a/pkg/references/middleware/access_logging_middleware.go b/pkg/references/middleware/access_logging_middleware.go index c628dc11fccc175b91f0ed7fdc7f180e3a91bfb4..b5fe116505c7a5f7d12c5f043c5d1c6b4c5d8fda 100644 --- a/pkg/references/middleware/access_logging_middleware.go +++ b/pkg/references/middleware/access_logging_middleware.go @@ -32,7 +32,7 @@ func AccessLoggingMiddleware(logger *zap.Logger) Middleware { } } -func (m *accessLoggingMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference) (items []*items.Item, notfound []*references.Reference, err error) { +func (m *accessLoggingMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference, options ...*references.GetOptions) (items []*items.Item, notfound []*references.Reference, err error) { begin := time.Now() m.logger.Debug("Get.Request", @@ -40,9 +40,10 @@ func (m *accessLoggingMiddleware) Get(ctx context.Context, spaceId string, envId zap.Reflect("spaceId", spaceId), zap.Reflect("envId", envId), zap.Reflect("references", references), + zap.Reflect("options", options), ) - items, notfound, err = m.next.Get(ctx, spaceId, envId, references) + items, notfound, err = m.next.Get(ctx, spaceId, envId, references, options...) m.logger.Debug("Get.Response", zap.Duration("time", time.Since(begin)), diff --git a/pkg/references/middleware/client_encode_middleware.go b/pkg/references/middleware/client_encode_middleware.go index 33ca79610896926be3679920a6cd96c8afd6c73b..b6ea043b70da4ea5a9bcd3f3740ebb6e3774d107 100644 --- a/pkg/references/middleware/client_encode_middleware.go +++ b/pkg/references/middleware/client_encode_middleware.go @@ -23,8 +23,8 @@ type encodeDecodeMiddleware struct { colls collections.Collections } -func (m *encodeDecodeMiddleware) Get(ctx context.Context, spaceId, envId string, refs []*references.Reference) (items []*items.Item, notfound []*references.Reference, err error) { - items, notfound, err = m.next.Get(ctx, spaceId, envId, refs) +func (m *encodeDecodeMiddleware) Get(ctx context.Context, spaceId, envId string, refs []*references.Reference, options ...*references.GetOptions) (items []*items.Item, notfound []*references.Reference, err error) { + items, notfound, err = m.next.Get(ctx, spaceId, envId, refs, options...) if err == nil && len(items) > 0 { for i, item := range items { col, err := m.colls.Get(ctx, item.SpaceID, item.EnvID, item.CollectionID) diff --git a/pkg/references/middleware/error_logging_middleware.go b/pkg/references/middleware/error_logging_middleware.go index b55b11679d819e42f30234d27f6f140b2d024aa8..a68dc8f80685b704162c5399053a3bb3831846c9 100644 --- a/pkg/references/middleware/error_logging_middleware.go +++ b/pkg/references/middleware/error_logging_middleware.go @@ -30,14 +30,14 @@ func ErrorLoggingMiddleware(logger *zap.Logger) Middleware { } } -func (m *errorLoggingMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference) (items []*items.Item, notfound []*references.Reference, err error) { +func (m *errorLoggingMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference, options ...*references.GetOptions) (items []*items.Item, notfound []*references.Reference, err error) { logger := m.logger defer func() { if err != nil { logger.Warn("response error", zap.Error(err)) } }() - return m.next.Get(ctx, spaceId, envId, references) + return m.next.Get(ctx, spaceId, envId, references, options...) } func (m *errorLoggingMiddleware) Publish(ctx context.Context, spaceId string, envId string, references []*references.Reference, recursive bool, force bool) (published []*references.Reference, notfound []*references.Reference, unpublished []*references.Reference, err error) { diff --git a/pkg/references/middleware/recovering_middleware.go b/pkg/references/middleware/recovering_middleware.go index 1331a96787b8ba98322ab2e4ee5764d296504066..cc8a87ff40cd9f70da25444d53762cbce67e8fd7 100644 --- a/pkg/references/middleware/recovering_middleware.go +++ b/pkg/references/middleware/recovering_middleware.go @@ -31,7 +31,7 @@ func RecoveringMiddleware(logger *zap.Logger) Middleware { } } -func (m *recoveringMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference) (items []*items.Item, notfound []*references.Reference, err error) { +func (m *recoveringMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference, options ...*references.GetOptions) (items []*items.Item, notfound []*references.Reference, err error) { logger := m.logger defer func() { if r := recover(); r != nil { @@ -40,7 +40,7 @@ func (m *recoveringMiddleware) Get(ctx context.Context, spaceId string, envId st } }() - return m.next.Get(ctx, spaceId, envId, references) + return m.next.Get(ctx, spaceId, envId, references, options...) } func (m *recoveringMiddleware) Publish(ctx context.Context, spaceId string, envId string, references []*references.Reference, recursive bool, force bool) (published []*references.Reference, notfound []*references.Reference, unpublished []*references.Reference, err error) { diff --git a/pkg/references/middleware/telemetry_middleware.go b/pkg/references/middleware/telemetry_middleware.go index f188bdc7ee04c13690ac0712e511508ccb2b12bc..71c51698bd9c015fdefd24e79b41ddcacda09eb2 100644 --- a/pkg/references/middleware/telemetry_middleware.go +++ b/pkg/references/middleware/telemetry_middleware.go @@ -1,10 +1,10 @@ // Code generated by gowrap. DO NOT EDIT. -// template: ..\..\..\assets\templates\middleware\telemetry +// template: ../../../assets/templates/middleware/telemetry // gowrap: http://github.com/hexdigest/gowrap package middleware -//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/references -i References -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l "" +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/references -i References -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry @@ -50,7 +50,7 @@ func TelemetryMiddleware(base references.References, instance string, spanDecora } // Get implements references.References -func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference) (items []*items.Item, notfound []*references.Reference, err error) { +func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference, options ...*references.GetOptions) (items []*items.Item, notfound []*references.Reference, err error) { attributes := otelmetric.WithAttributeSet(attribute.NewSet( attribute.String("service", "References"), attribute.String("method", "Get"), @@ -69,7 +69,8 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str "ctx": ctx, "spaceId": spaceId, "envId": envId, - "references": references}, map[string]interface{}{ + "references": references, + "options": options}, map[string]interface{}{ "items": items, "notfound": notfound, "err": err}) @@ -83,7 +84,7 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str _span.End() }() - return _d.References.Get(ctx, spaceId, envId, references) + return _d.References.Get(ctx, spaceId, envId, references, options...) } // Publish implements references.References diff --git a/pkg/references/mocks/Middleware.go b/pkg/references/mocks/Middleware.go index a6d794c3c4a3d533b265768a187d39efe416052b..f2526e5012d4200d672b295a608156b3770d5e1f 100644 --- a/pkg/references/mocks/Middleware.go +++ b/pkg/references/mocks/Middleware.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.22.1. DO NOT EDIT. +// Code generated by mockery v2.40.1. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Middleware struct { func (_m *Middleware) Execute(_a0 references.References) references.References { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Execute") + } + var r0 references.References if rf, ok := ret.Get(0).(func(references.References) references.References); ok { r0 = rf(_a0) @@ -28,13 +32,12 @@ func (_m *Middleware) Execute(_a0 references.References) references.References { return r0 } -type mockConstructorTestingTNewMiddleware interface { +// NewMiddleware creates a new instance of Middleware. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMiddleware(t interface { mock.TestingT Cleanup(func()) -} - -// NewMiddleware creates a new instance of Middleware. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMiddleware(t mockConstructorTestingTNewMiddleware) *Middleware { +}) *Middleware { mock := &Middleware{} mock.Mock.Test(t) diff --git a/pkg/references/mocks/References.go b/pkg/references/mocks/References.go index 4cd99f3d7b0c3a96a695e132e9f3ee65754b1dfe..92c8e29036b2960abd16b5f6df6caab04a783c0d 100644 --- a/pkg/references/mocks/References.go +++ b/pkg/references/mocks/References.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.22.1. DO NOT EDIT. +// Code generated by mockery v2.40.1. DO NOT EDIT. package mocks @@ -16,34 +16,45 @@ type References struct { mock.Mock } -// Get provides a mock function with given fields: ctx, spaceId, envId, _a3 -func (_m *References) Get(ctx context.Context, spaceId string, envId string, _a3 []*references.Reference) ([]*items.Item, []*references.Reference, error) { - ret := _m.Called(ctx, spaceId, envId, _a3) +// Get provides a mock function with given fields: ctx, spaceId, envId, _a3, options +func (_m *References) Get(ctx context.Context, spaceId string, envId string, _a3 []*references.Reference, options ...*references.GetOptions) ([]*items.Item, []*references.Reference, error) { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, spaceId, envId, _a3) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Get") + } var r0 []*items.Item var r1 []*references.Reference var r2 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, []*references.Reference) ([]*items.Item, []*references.Reference, error)); ok { - return rf(ctx, spaceId, envId, _a3) + if rf, ok := ret.Get(0).(func(context.Context, string, string, []*references.Reference, ...*references.GetOptions) ([]*items.Item, []*references.Reference, error)); ok { + return rf(ctx, spaceId, envId, _a3, options...) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, []*references.Reference) []*items.Item); ok { - r0 = rf(ctx, spaceId, envId, _a3) + if rf, ok := ret.Get(0).(func(context.Context, string, string, []*references.Reference, ...*references.GetOptions) []*items.Item); ok { + r0 = rf(ctx, spaceId, envId, _a3, options...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*items.Item) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, []*references.Reference) []*references.Reference); ok { - r1 = rf(ctx, spaceId, envId, _a3) + if rf, ok := ret.Get(1).(func(context.Context, string, string, []*references.Reference, ...*references.GetOptions) []*references.Reference); ok { + r1 = rf(ctx, spaceId, envId, _a3, options...) } else { if ret.Get(1) != nil { r1 = ret.Get(1).([]*references.Reference) } } - if rf, ok := ret.Get(2).(func(context.Context, string, string, []*references.Reference) error); ok { - r2 = rf(ctx, spaceId, envId, _a3) + if rf, ok := ret.Get(2).(func(context.Context, string, string, []*references.Reference, ...*references.GetOptions) error); ok { + r2 = rf(ctx, spaceId, envId, _a3, options...) } else { r2 = ret.Error(2) } @@ -55,6 +66,10 @@ func (_m *References) Get(ctx context.Context, spaceId string, envId string, _a3 func (_m *References) Publish(ctx context.Context, spaceId string, envId string, _a3 []*references.Reference, recursive bool, force bool) ([]*references.Reference, []*references.Reference, []*references.Reference, error) { ret := _m.Called(ctx, spaceId, envId, _a3, recursive, force) + if len(ret) == 0 { + panic("no return value specified for Publish") + } + var r0 []*references.Reference var r1 []*references.Reference var r2 []*references.Reference @@ -95,13 +110,12 @@ func (_m *References) Publish(ctx context.Context, spaceId string, envId string, return r0, r1, r2, r3 } -type mockConstructorTestingTNewReferences interface { +// NewReferences creates a new instance of References. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewReferences(t interface { mock.TestingT Cleanup(func()) -} - -// NewReferences creates a new instance of References. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewReferences(t mockConstructorTestingTNewReferences) *References { +}) *References { mock := &References{} mock.Mock.Test(t) diff --git a/pkg/references/reference.go b/pkg/references/reference.go index 75b9bc745d430ed0984ceedd07cf877adcb643e3..676f208c3304eb4840f43161a52a7a63779c6c8e 100644 --- a/pkg/references/reference.go +++ b/pkg/references/reference.go @@ -126,3 +126,45 @@ func EqualArrays(sr1, sr2 []*Reference) bool { func (r *Reference) IsValid() bool { return r != nil && r.ID != "" && r.CollectionID != "" && !r.Disabled } + +type GetOptions struct { + LocaleID string `json:"locale_id,omitempty"` + TranslationsIDs []string `json:"translations_ids,omitempty"` +} + +func NewGetOptions() *GetOptions { + return &GetOptions{} +} + +func MergeGetOptions(opts ...*GetOptions) *GetOptions { + o := NewGetOptions() + for _, opt := range opts { + if opt == nil { + continue + } + o.LocaleID = opt.LocaleID + o.TranslationsIDs = append(o.TranslationsIDs, opt.TranslationsIDs...) + } + return o +} + +func GetOptionsFromPB(opts *pb.GetOptions) *GetOptions { + if opts == nil { + return nil + } + + return &GetOptions{ + LocaleID: opts.LocaleId, + TranslationsIDs: opts.TranslationsIds, + } +} + +func GetOptionsToPB(opts *GetOptions) *pb.GetOptions { + if opts == nil { + return nil + } + return &pb.GetOptions{ + LocaleId: opts.LocaleID, + TranslationsIds: opts.TranslationsIDs, + } +} diff --git a/pkg/references/service.go b/pkg/references/service.go index 136001a263b8754fba68de60259c2102608a0a77..2380a7879e0d15924ac83c226059932daf540bcf 100644 --- a/pkg/references/service.go +++ b/pkg/references/service.go @@ -10,7 +10,7 @@ import ( // @protobuf git.perx.ru/perxis/perxis-go/proto/references // @grpc-addr content.references.References type References interface { - Get(ctx context.Context, spaceId, envId string, references []*Reference) (items []*items.Item, notfound []*Reference, err error) + Get(ctx context.Context, spaceId, envId string, references []*Reference, options ...*GetOptions) (items []*items.Item, notfound []*Reference, err error) Publish(ctx context.Context, spaceId, envId string, references []*Reference, recursive, force bool) (published []*Reference, notfound []*Reference, unpublished []*Reference, err error) } diff --git a/pkg/references/transport/client.microgen.go b/pkg/references/transport/client.go similarity index 69% rename from pkg/references/transport/client.microgen.go rename to pkg/references/transport/client.go index 5c0eb4143138bac3e2eecb3713103cf7c347c873..45f10f4f68c292729d7e461219219d09aa3f1341 100644 --- a/pkg/references/transport/client.microgen.go +++ b/pkg/references/transport/client.go @@ -4,25 +4,20 @@ package transport import ( "context" - "errors" items "git.perx.ru/perxis/perxis-go/pkg/items" references "git.perx.ru/perxis/perxis-go/pkg/references" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) -func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string, arg3 []*references.Reference) (res0 []*items.Item, res1 []*references.Reference, res2 error) { +func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string, arg3 []*references.Reference, arg4 ...*references.GetOptions) (res0 []*items.Item, res1 []*references.Reference, res2 error) { request := GetRequest{ EnvId: arg2, References: arg3, SpaceId: arg1, + Options: arg4, } response, res2 := set.GetEndpoint(arg0, &request) if res2 != nil { - if e, ok := status.FromError(res2); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res2 = errors.New(e.Message()) - } return } return response.(*GetResponse).Items, response.(*GetResponse).Notfound, res2 @@ -38,9 +33,6 @@ func (set EndpointsSet) Publish(arg0 context.Context, arg1 string, arg2 string, } response, res3 := set.PublishEndpoint(arg0, &request) if res3 != nil { - if e, ok := status.FromError(res3); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res3 = errors.New(e.Message()) - } return } return response.(*PublishResponse).Published, response.(*PublishResponse).Notfound, response.(*PublishResponse).Unpublished, res3 diff --git a/pkg/references/transport/exchanges.microgen.go b/pkg/references/transport/exchanges.microgen.go index a0e1774d8b88deb4fb3393473e7efbebbc9a5118..4d0b51bf3f61286e8d4ed6968d3a831e2c57bbf0 100644 --- a/pkg/references/transport/exchanges.microgen.go +++ b/pkg/references/transport/exchanges.microgen.go @@ -9,9 +9,10 @@ import ( type ( GetRequest struct { - SpaceId string `json:"space_id"` - EnvId string `json:"env_id"` - References []*references.Reference `json:"references"` + SpaceId string `json:"space_id"` + EnvId string `json:"env_id"` + References []*references.Reference `json:"references"` + Options []*references.GetOptions `json:"options"` } GetResponse struct { Items []*items.Item `json:"items"` diff --git a/pkg/references/transport/grpc/client.go b/pkg/references/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..01e5debd6080274fa42afe4779efc0190e8716ed --- /dev/null +++ b/pkg/references/transport/grpc/client.go @@ -0,0 +1,18 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/references/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + PublishEndpoint: grpcerr.ClientMiddleware(c.PublishEndpoint), + } +} diff --git a/pkg/references/transport/grpc/protobuf_endpoint_converters.microgen.go b/pkg/references/transport/grpc/protobuf_endpoint_converters.microgen.go index 0c995ffcb98960a8257533992cc5e33faaa9aa59..f2a2fad073ebb89f1b48242682066d0a8e171b10 100644 --- a/pkg/references/transport/grpc/protobuf_endpoint_converters.microgen.go +++ b/pkg/references/transport/grpc/protobuf_endpoint_converters.microgen.go @@ -7,6 +7,7 @@ import ( "context" "errors" + "git.perx.ru/perxis/perxis-go/pkg/references" "git.perx.ru/perxis/perxis-go/pkg/references/transport" pb "git.perx.ru/perxis/perxis-go/proto/references" ) @@ -20,10 +21,15 @@ func _Encode_Get_Request(ctx context.Context, request interface{}) (interface{}, if err != nil { return nil, err } + opts := &pb.GetOptions{} + if req.Options != nil { + opts = references.GetOptionsToPB(req.Options[0]) + } return &pb.GetRequest{ EnvId: req.EnvId, References: reqReferences, SpaceId: req.SpaceId, + Options: opts, }, nil } @@ -59,6 +65,7 @@ func _Decode_Get_Request(ctx context.Context, request interface{}) (interface{}, EnvId: string(req.EnvId), References: reqReferences, SpaceId: string(req.SpaceId), + Options: []*references.GetOptions{references.GetOptionsFromPB(req.Options)}, }, nil } diff --git a/pkg/references/transport/grpc/protobuf_type_converters.microgen.go b/pkg/references/transport/grpc/protobuf_type_converters.microgen.go index 549d11725e085c4a35aaa047a2a4b1e9c43355df..965122b7da2c7e05db175f6f3a15ac373dd075b5 100644 --- a/pkg/references/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/references/transport/grpc/protobuf_type_converters.microgen.go @@ -69,3 +69,25 @@ func ListPtrItemsItemToProto(items []*items.Item) ([]*itemspb.Item, error) { func ProtoToListPtrItemsItem(protoItems []*itemspb.Item) ([]*items.Item, error) { return itemstransportgrpc.ProtoToListPtrItem(protoItems) } + +func ElPtrGetOptionsToProto(options []*service.GetOptions) ([]*pb.GetOptions, error) { + if options == nil { + return nil, nil + } + protoOption := make([]*pb.GetOptions, len(options)) + for _, o := range options { + protoOption = append(protoOption, service.GetOptionsToPB(o)) + } + return protoOption, nil +} + +func ProtoToElPtrGetOptions(protoOptions []*pb.GetOptions) ([]*service.GetOptions, error) { + if protoOptions == nil { + return nil, nil + } + options := make([]*service.GetOptions, len(protoOptions)) + for _, o := range protoOptions { + options = append(options, service.GetOptionsFromPB(o)) + } + return options, nil +} diff --git a/pkg/references/transport/grpc/server.go b/pkg/references/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..32a4beac6e564c40d19a7cad937f8191fd8fe54c --- /dev/null +++ b/pkg/references/transport/grpc/server.go @@ -0,0 +1,18 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/references" + "git.perx.ru/perxis/perxis-go/pkg/references/transport" + pb "git.perx.ru/perxis/perxis-go/proto/references" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc references.References, opts ...grpckit.ServerOption) pb.ReferencesServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + PublishEndpoint: grpcerr.ServerMiddleware(eps.PublishEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/references/transport/server.microgen.go b/pkg/references/transport/server.microgen.go index 581aa61605034fa7fbb4cf025279ba6c38368d4a..06cf49df57605952311d211fc554123a86e760e5 100644 --- a/pkg/references/transport/server.microgen.go +++ b/pkg/references/transport/server.microgen.go @@ -19,7 +19,7 @@ func Endpoints(svc references.References) EndpointsSet { func GetEndpoint(svc references.References) endpoint.Endpoint { return func(arg0 context.Context, request interface{}) (interface{}, error) { req := request.(*GetRequest) - res0, res1, res2 := svc.Get(arg0, req.SpaceId, req.EnvId, req.References) + res0, res1, res2 := svc.Get(arg0, req.SpaceId, req.EnvId, req.References, req.Options...) return &GetResponse{ Items: res0, Notfound: res1, diff --git a/pkg/roles/events.go b/pkg/roles/events.go new file mode 100644 index 0000000000000000000000000000000000000000..c12631afb921a5ef4144e0c1d32d808051acddad --- /dev/null +++ b/pkg/roles/events.go @@ -0,0 +1,7 @@ +package roles + +const ( + EventCreate = "roles.create" + EventUpdate = "roles.update" + EventDelete = "roles.delete" +) diff --git a/pkg/roles/middleware/caching_middleware.go b/pkg/roles/middleware/caching_middleware.go index 3f46087ec59e3ee71cd441b87e16a995d82eb7ea..2bcb04d3df7278d619fe80b2a6b02c48ea58f1fb 100644 --- a/pkg/roles/middleware/caching_middleware.go +++ b/pkg/roles/middleware/caching_middleware.go @@ -5,6 +5,7 @@ import ( "strings" "git.perx.ru/perxis/perxis-go/pkg/cache" + "git.perx.ru/perxis/perxis-go/pkg/data" service "git.perx.ru/perxis/perxis-go/pkg/roles" ) @@ -29,7 +30,7 @@ type cachingMiddleware struct { func (m cachingMiddleware) Create(ctx context.Context, role *service.Role) (rl *service.Role, err error) { rl, err = m.next.Create(ctx, role) if err == nil { - m.cache.Remove(rl.SpaceID) + _ = m.cache.Remove(rl.SpaceID) } return rl, err } @@ -38,33 +39,35 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId string, roleId strin key := makeKey(spaceId, roleId) value, e := m.cache.Get(key) if e == nil { - return value.(*service.Role), err + return value.(*service.Role).Clone(), nil } rl, err = m.next.Get(ctx, spaceId, roleId) if err == nil { - m.cache.Set(key, rl) + _ = m.cache.Set(key, rl) + return rl.Clone(), nil } - return rl, err + return nil, err } func (m cachingMiddleware) List(ctx context.Context, spaceId string) (roles []*service.Role, err error) { value, e := m.cache.Get(spaceId) if e == nil { - return value.([]*service.Role), err + return data.CloneSlice(value.([]*service.Role)), nil } roles, err = m.next.List(ctx, spaceId) if err == nil { - m.cache.Set(spaceId, roles) + _ = m.cache.Set(spaceId, roles) + return data.CloneSlice(roles), nil } - return roles, err + return nil, err } func (m cachingMiddleware) Update(ctx context.Context, role *service.Role) (err error) { err = m.next.Update(ctx, role) if err == nil { key := makeKey(role.SpaceID, role.ID) - m.cache.Remove(key) - m.cache.Remove(role.SpaceID) + _ = m.cache.Remove(key) + _ = m.cache.Remove(role.SpaceID) } return err } @@ -73,8 +76,8 @@ func (m cachingMiddleware) Delete(ctx context.Context, spaceId string, roleId st err = m.next.Delete(ctx, spaceId, roleId) if err == nil { key := makeKey(spaceId, roleId) - m.cache.Remove(key) - m.cache.Remove(spaceId) + _ = m.cache.Remove(key) + _ = m.cache.Remove(spaceId) } return err } diff --git a/pkg/roles/middleware/caching_middleware_test.go b/pkg/roles/middleware/caching_middleware_test.go index 9d5d64f4231cf8bd86d533224fd50e762eebdcab..b9ac8ec826439319348bac2b13fc743c3753d024 100644 --- a/pkg/roles/middleware/caching_middleware_test.go +++ b/pkg/roles/middleware/caching_middleware_test.go @@ -39,7 +39,8 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, roleID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) rl.AssertExpectations(t) }) @@ -56,7 +57,8 @@ func TestRolesCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) rl.AssertExpectations(t) }) @@ -75,14 +77,16 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, roleID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, v1, v2) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) rl.On("Update", mock.Anything, mock.Anything).Return(nil).Once() @@ -94,11 +98,11 @@ func TestRolesCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, roleID) require.NoError(t, err) - assert.NotSame(t, v2, v3, "Ожидается что кеш объекта был удален после его обновления и объект был запрошен из сервиса.") + assert.NotEqual(t, v2, v3, "Ожидается что кеш объекта был удален после его обновления и объект был запрошен из сервиса.") vl3, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после обновления объекта.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после обновления объекта.") rl.AssertExpectations(t) }) @@ -116,14 +120,16 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, roleID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) vl1, err := svc.List(ctx, spaceID) require.NoError(t, err) vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) rl.On("Update", mock.Anything, mock.Anything).Return(nil).Once() @@ -158,7 +164,8 @@ func TestRolesCache(t *testing.T) { vl2, err := svc.List(ctx, spaceID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) rl.On("Create", mock.Anything, mock.Anything).Return(&roles.Role{ID: "roleID2", SpaceID: spaceID, Description: "Role2"}, nil).Once() @@ -186,7 +193,8 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID, roleID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) rl.On("Get", mock.Anything, spaceID, roleID).Return(&roles.Role{ID: roleID, SpaceID: spaceID, Description: "Role"}, nil).Once() @@ -194,6 +202,8 @@ func TestRolesCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID, roleID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается что объект был удален из кеша и получен заново из сервиса.") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) rl.AssertExpectations(t) }) diff --git a/pkg/roles/middleware/logging_middleware.go b/pkg/roles/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..9221265df1603f93be2c344c8c559eb8811e60de --- /dev/null +++ b/pkg/roles/middleware/logging_middleware.go @@ -0,0 +1,106 @@ +package middleware + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/roles" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next roles.Roles +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next roles.Roles) roles.Roles { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Roles")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, role *roles.Role) (created *roles.Role, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(roles.EventCreate), + ) + + created, err = m.next.Create(ctx, role) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(role)) + return + } + + logger.Info("Role created", logzap.Channels(logzap.Userlog), logzap.Object(created)) + + return created, err +} + +func (m *loggingMiddleware) Get(ctx context.Context, spaceId, roleId string) (role *roles.Role, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewRoleId(spaceId, roleId)), + ) + + role, err = m.next.Get(ctx, spaceId, roleId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return role, err +} + +func (m *loggingMiddleware) List(ctx context.Context, spaceId string) (roles []*roles.Role, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + roles, err = m.next.List(ctx, spaceId) + if err != nil { + logger.Error("Failed to list", zap.Error(err)) + return + } + + return roles, err +} + +func (m *loggingMiddleware) Update(ctx context.Context, role *roles.Role) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(roles.EventUpdate), + logzap.Object(role), + ) + + err = m.next.Update(ctx, role) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Role updated", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, spaceId, roleId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(roles.EventDelete), + logzap.Object(id.NewRoleId(spaceId, roleId)), + ) + + err = m.next.Delete(ctx, spaceId, roleId) + if err != nil { + logger.Error("Failed to delete", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Role deleted", logzap.Channels(logzap.Userlog)) + + return err +} diff --git a/pkg/roles/middleware/middleware.go b/pkg/roles/middleware/middleware.go index aaeb2da895d5aa71768e577315e549daa6a247c4..299199a40432f486d1020bb803f5bff18a95428e 100644 --- a/pkg/roles/middleware/middleware.go +++ b/pkg/roles/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s roles.Roles, logger *zap.Logger, log_access bool) roles.Roles { if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/roles/role.go b/pkg/roles/role.go index 370470675cd40ae417d38b2ae8b8f7c4e7a63cfe..76520f8fbf353c027ae782efb1bf79a1bfa453f5 100644 --- a/pkg/roles/role.go +++ b/pkg/roles/role.go @@ -2,6 +2,7 @@ package roles import ( "context" + "slices" "git.perx.ru/perxis/perxis-go/pkg/data" "git.perx.ru/perxis/perxis-go/pkg/environments" @@ -34,6 +35,22 @@ type Role struct { AllowManagement bool `json:"allow_management" bson:"allow_management"` } +// GetID возвращает идентификатор роли +func (r Role) GetID() string { + return r.ID +} + +func (r Role) Clone() *Role { + return &Role{ + ID: r.ID, + SpaceID: r.SpaceID, + Description: r.Description, + Environments: slices.Clone(r.Environments), + Rules: data.CloneSlice(r.Rules), + AllowManagement: r.AllowManagement, + } +} + func (r Role) CanAccessEnvironment(ctx context.Context, env *environments.Environment, service environments.Environments) bool { if env.SpaceID == "" || env.ID == "" { return false diff --git a/pkg/roles/transport/client.microgen.go b/pkg/roles/transport/client.go similarity index 64% rename from pkg/roles/transport/client.microgen.go rename to pkg/roles/transport/client.go index 71b1de9e2b1b746962effe61dc63c37cf7977e69..1b36431f5371bb93579f6bf985aa184337ac086b 100644 --- a/pkg/roles/transport/client.microgen.go +++ b/pkg/roles/transport/client.go @@ -4,20 +4,14 @@ package transport import ( "context" - "errors" roles "git.perx.ru/perxis/perxis-go/pkg/roles" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *roles.Role) (res0 *roles.Role, res1 error) { request := CreateRequest{Role: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).Created, res1 @@ -30,9 +24,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string, arg2 string) (res } response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).Role, res1 @@ -42,9 +33,6 @@ func (set EndpointsSet) List(arg0 context.Context, arg1 string) (res0 []*roles.R request := ListRequest{SpaceId: arg1} response, res1 := set.ListEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*ListResponse).Roles, res1 @@ -54,9 +42,6 @@ func (set EndpointsSet) Update(arg0 context.Context, arg1 *roles.Role) (res0 err request := UpdateRequest{Role: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -69,9 +54,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string, arg2 string) ( } _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 diff --git a/pkg/roles/transport/grpc/client.go b/pkg/roles/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..06a23a7bceb96992c5114a46c1995eb5b4d8518c --- /dev/null +++ b/pkg/roles/transport/grpc/client.go @@ -0,0 +1,21 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/roles/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + ListEndpoint: grpcerr.ClientMiddleware(c.ListEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + } +} diff --git a/pkg/roles/transport/grpc/server.go b/pkg/roles/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..764efc8a4185e2078cac995a2a40a8010c94dd93 --- /dev/null +++ b/pkg/roles/transport/grpc/server.go @@ -0,0 +1,21 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/roles" + "git.perx.ru/perxis/perxis-go/pkg/roles/transport" + pb "git.perx.ru/perxis/perxis-go/proto/roles" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc roles.Roles, opts ...grpckit.ServerOption) pb.RolesServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + ListEndpoint: grpcerr.ServerMiddleware(eps.ListEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/pkg/schema/field/array.go b/pkg/schema/field/array.go index 6700eb9b09af7bb714566dca8c82e90d026c7d57..bf1a4819dd075fc5e3f46fc4d1e289c8bd75cf90 100644 --- a/pkg/schema/field/array.go +++ b/pkg/schema/field/array.go @@ -22,6 +22,22 @@ func (p ArrayParameters) Clone(reset bool) Parameters { return &ArrayParameters{Item: p.Item.Clone(reset)} } +func (a ArrayParameters) GetField(f *Field, name string) *Field { + f.SetFieldState("Item", a.Item) + + if name == "" || name == "Item" { + return a.Item + } + + return a.Item.GetField(name) +} + +func (a ArrayParameters) ListFields(f *Field, filterFunc ...FieldFilterFunc) []*Field { + f.SetFieldState("Item", a.Item) + + return []*Field{a.Item} +} + type ArrayType struct{} func (ArrayType) Name() string { @@ -116,17 +132,17 @@ func (ArrayType) Walk(ctx context.Context, field *Field, v interface{}, fn WalkF return nil, false, nil } - // Выполняется обход по схеме - if opts.WalkSchema && v == nil { - params.Item.Walk(ctx, v, fn, WalkOpts(opts)) - return nil, false, nil - } - arr, ok := v.([]interface{}) - if !ok { + if !ok && v != nil { return nil, false, fmt.Errorf("incorrect type: \"%s\", expected \"[]interface{}\"", reflect.ValueOf(v).Kind()) } + // Выполняется обход по схеме + if opts.WalkSchema && len(arr) == 0 { + _, _, _ = params.Item.Walk(ctx, nil, fn, WalkOpts(opts)) + return nil, false, nil + } + m := make([]interface{}, 0, len(arr)) var merr *multierror.Error diff --git a/pkg/schema/field/array_test.go b/pkg/schema/field/array_test.go index 94e60258661932dc72c2c34c27ea7cecb5c6b33d..b2948e1b12161da604ed22da96e4b8a092c0a99f 100644 --- a/pkg/schema/field/array_test.go +++ b/pkg/schema/field/array_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "fmt" "testing" @@ -23,6 +24,26 @@ func TestArrayField_Decode(t *testing.T) { []interface{}{1.0, 2.0}, false, }, + { + "With object inside with nil-data", + Array( + Object("a", String(), + "b", String()), + ), + nil, + nil, + false, + }, + { + "With object inside with data", + Array( + Object("a", String(), + "b", String()), + ), + []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, + []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, + false, + }, { "Incorrect type", Array(Number("int")), @@ -33,7 +54,7 @@ func TestArrayField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Decode() error = %v, want %v", err, tt.want.(string))) @@ -71,7 +92,7 @@ func TestArrayField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Decode() error = %v, want %v", err, tt.want.(string))) @@ -83,3 +104,61 @@ func TestArrayField_Encode(t *testing.T) { }) } } + +func TestArrayType_Walk(t *testing.T) { + tests := []struct { + name string + field *Field + v interface{} + fn WalkFunc + opts *WalkOptions + want interface{} + want1 bool + wantErr assert.ErrorAssertionFunc + }{ + { + name: "With nil data and WalkSchema = false", + field: Array(Object("a", String(), "b", String())), + v: nil, + opts: &WalkOptions{WalkSchema: false}, + want: nil, + want1: false, + wantErr: assert.NoError, + }, + { + name: "With empty data and WalkSchema = false", + field: Array(Object("a", String(), "b", String())), + v: []interface{}{map[string]interface{}{}}, + opts: &WalkOptions{WalkSchema: false}, + fn: func(ctx context.Context, fld *Field, v interface{}) (result WalkFuncResult, err error) { + return WalkFuncResult{}, err + }, + want: []interface{}{map[string]interface{}{}}, + want1: false, + wantErr: assert.NoError, + }, + { + name: "With data and WalkSchema = false", + field: Array(Object("a", String(), "b", String())), + v: []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, + opts: &WalkOptions{WalkSchema: false}, + fn: func(ctx context.Context, fld *Field, v interface{}) (result WalkFuncResult, err error) { + return WalkFuncResult{}, err + }, + want: []interface{}{map[string]interface{}{"a": "1", "b": "2"}}, + want1: false, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ar := ArrayType{} + got, got1, err := ar.Walk(context.Background(), tt.field, tt.v, tt.fn, tt.opts) + if !tt.wantErr(t, err, fmt.Sprintf("Walk(%v, %v, %v, %v)", tt.field, tt.v, tt.fn, tt.opts)) { + return + } + assert.Equalf(t, tt.want, got, "Walk(%v, %v, %v, %v)", tt.field, tt.v, tt.fn, tt.opts) + assert.Equalf(t, tt.want1, got1, "Walk(%v, %v, %v, %v)", tt.field, tt.v, tt.fn, tt.opts) + }) + } +} diff --git a/pkg/schema/field/boolean.go b/pkg/schema/field/boolean.go index 94580541f8e33f9930adad94bff6a5c18915d05b..e06b704d0bb792d02a2f95343d037760fffb6fc7 100644 --- a/pkg/schema/field/boolean.go +++ b/pkg/schema/field/boolean.go @@ -10,8 +10,10 @@ var boolType = &BoolType{} type BoolParameters struct{} -func (b BoolParameters) Type() Type { return boolType } -func (b *BoolParameters) Clone(reset bool) Parameters { return b } +func (b BoolParameters) Type() Type { return boolType } +func (b *BoolParameters) Clone(reset bool) Parameters { return b } +func (b BoolParameters) GetField(f *Field, name string) *Field { return nil } +func (b BoolParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } type BoolType struct{} diff --git a/pkg/schema/field/boolean_test.go b/pkg/schema/field/boolean_test.go index aaa09dcec353d7648a976759bb4fcc98d0fe0d7a..857201f325680902a2c970010c8da5cc4ab6cadc 100644 --- a/pkg/schema/field/boolean_test.go +++ b/pkg/schema/field/boolean_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "fmt" "testing" @@ -27,7 +28,7 @@ func TestBooleanField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Decode() error = %v, want %v", err, tt.want.(string))) @@ -59,7 +60,7 @@ func TestBooleanField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Encode() error = %v, want %v", err, tt.want.(string))) diff --git a/pkg/schema/field/field.go b/pkg/schema/field/field.go index 45ddb40d128ab3f87ff7c41e3cedf75009ba3f98..4fc9516f1d6b64ce49ee42ea527b84992477365b 100644 --- a/pkg/schema/field/field.go +++ b/pkg/schema/field/field.go @@ -49,13 +49,24 @@ type Include struct { Optional bool `json:"optional,omitempty"` } +// State - состояние поля времени выполнения +type State struct { + Name string + DataPath string + SchemaPath string + SingleLocale bool + Parent *Field + Inlined bool + HasInline bool +} + type Field struct { Title string `json:"title,omitempty"` // Название поля (Например: name) Description string `json:"description,omitempty"` // Описание поле (Например: User name) Translations []Translation `json:"translations,omitempty"` // Переводы данных на разных языках UI *UI `json:"ui,omitempty"` // Опции пользовательского интерфейса Includes []Include `json:"includes,omitempty"` // Импорт схем - SingleLocale bool `json:"singleLocale,omitempty"` // Без перевода + SingleLocale bool `json:"single_locale,omitempty"` // Без перевода Indexed bool `json:"indexed,omitempty"` // Построить индекс для поля Unique bool `json:"unique,omitempty"` // Значение поля должны быть уникальными TextSearch bool `json:"text_search,omitempty"` // Значение поля доступны для полнотекстового поиска @@ -63,8 +74,7 @@ type Field struct { Options Options `json:"options,omitempty"` // Дополнительные опции Condition string `json:"condition,omitempty"` // Условие отображения поля AdditionalValues bool `json:"additional_values,omitempty"` // Разрешает дополнительные значения вне ограничений правил - - prepared bool + State *State `json:"-"` // Состояние поля времени выполнения } // TODO: Replace with Named field??? @@ -86,7 +96,37 @@ func NewField(params Parameters, opts ...interface{}) *Field { return f } +// GetState возвращает состояние поля времени выполнения +func (f Field) GetState() *State { + return f.State +} + +// ClearState очищает состояние поля и всех вложенных полей +// +// Схемы нельзя сравнивать с активным состоянием с помощью `reflect.DeepEqual` или `assert.Equal`. +// Предварительно нужно сделать `ClearState`. +// После очистки состояния полей не будут рассчитываться. Для повторного включения состояния используйте `EnableState` +func (f *Field) ClearState() *Field { + f.State = nil + for _, fld := range f.ListFields() { + fld.ClearState() + } + return f +} + +// EnableState включает расчет состояния поля и всех вложенных полей +// +// Без включения состояния поля, невозможно получить доступ к данным времени выполнения +// schema.New включает состояние для схемы при создании +func (f *Field) EnableState() { + f.State = &State{} +} + func (f Field) GetType() Type { + if f.Params == nil { + return nil + } + return f.Params.Type() } @@ -166,6 +206,10 @@ func (f Field) SetSingleLocale(r bool) *Field { return &f } +func (f Field) IsSingleLocale() bool { + return f.SingleLocale || (f.State != nil && f.State.SingleLocale) +} + func (f Field) SetIndexed(r bool) *Field { f.Indexed = r return &f @@ -259,46 +303,91 @@ func (f *Field) Prepare() error { return nil } -// GetField возвращает поле по строковому пути -func (f *Field) GetField(path string) *Field { - if path == "" { - switch params := f.Params.(type) { - case *ArrayParameters: - // Возвращаем поле Item если путь указан как "arr." - return params.Item - } - return nil +func (f *Field) SetFieldState(name string, fld *Field) *Field { + if f != nil && fld != nil && f.State != nil && fld.State == nil { + fld.State = f.getFieldState(name, fld) } + return fld +} - switch params := f.Params.(type) { - case *ObjectParameters: - pp := strings.SplitN(path, FieldSeparator, 2) +// GetFieldState возвращает состояние вложенного поля +func (f *Field) getFieldState(name string, fld *Field) *State { + if f.State == nil { + return nil + } - for k, v := range params.Fields { + state := State{ + SchemaPath: name, + DataPath: name, + Name: name, + } - p, ok := v.Params.(*ObjectParameters) - if ok && p.Inline { - f := v.GetField(path) - if f != nil { - return f - } - } + dataPath := f.State.DataPath - if k == pp[0] { - if len(pp) == 1 { - return v - } - return v.GetField(pp[1]) + switch params := f.Params.(type) { + case *ObjectParameters: + if params.Inline { + last := strings.LastIndex(dataPath, ".") + if last > 0 { + dataPath = dataPath[:last] + } else { + dataPath = "" } + state.Inlined = true + } + if dataPath != "" { + state.DataPath = dataPath + FieldSeparator + state.DataPath } - case Fielder: - return params.GetField(path) case *ArrayParameters: - return params.Item.GetField(path) + state.DataPath = dataPath // Remove item from path } - return nil + state.SingleLocale = f.IsSingleLocale() || fld.SingleLocale + + if f.State.SchemaPath != "" { + state.SchemaPath = f.State.SchemaPath + FieldSeparator + state.SchemaPath + } + state.Parent = f + state.HasInline = f.State.HasInline || state.Inlined + return &state +} + +func (f *Field) GetFieldByName(name string) *Field { + return f.Params.GetField(f, name) +} + +// GetField возвращает поле по строковому пути +func (f *Field) GetField(path string) *Field { + name := "" + parts := strings.SplitN(path, FieldSeparator, 2) + + if len(parts) > 0 { + name = parts[0] + } + + fld := f.GetFieldByName(name) + + if fld != nil && len(parts) > 1 { + return fld.GetField(parts[1]) + } + + return fld +} + +// ListFields возвращает массив вложенных полей данного поля +func (f *Field) ListFields(filter ...FieldFilterFunc) []*Field { + fields := f.Params.ListFields(f, filter...) + return fields +} + +// ListFieldsRecursive возвращает массив всех вложенных полей рекурсивно +func (f *Field) ListFieldsRecursive(filter ...FieldFilterFunc) []*Field { + fields := f.ListFields(filter...) + for _, fld := range f.ListFields() { + fields = append(fields, fld.ListFieldsRecursive(filter...)...) + } + return fields } // GetFieldsPath возвращает полный путь для массива полей @@ -313,6 +402,8 @@ type FilterFunc func(*Field, string) bool func GetAll(field *Field, path string) bool { return true } +// GetFields возвращает массив полей с путем??? +// DEPRECATED: использовать ListFields или ListFieldsRecursive func (f *Field) GetFields(filterFunc FilterFunc, pathPrefix ...string) (res []PathField) { var path string @@ -335,11 +426,11 @@ func (f *Field) GetFields(filterFunc FilterFunc, pathPrefix ...string) (res []Pa res = append(res, getFieldsArray(path, params, filterFunc)...) } - //if len(pathPrefix) > 0 { + // if len(pathPrefix) > 0 { // for _, r := range res { // r.Path = strings.Join([]string{pathPrefix[0], r.Path}, FieldSeparator) // } - //} + // } return res } @@ -384,22 +475,26 @@ func getFieldsObject(path string, params *ObjectParameters, filterFunc FilterFun return res } +// GetNestedFields возвращает вложенные поля +// DEPRECATED: использовать ListFields func (f *Field) GetNestedFields() []*Field { - switch params := f.Params.(type) { - case *ObjectParameters: - flds := make([]*Field, 0, len(params.Fields)) - for _, v := range params.Fields { - if v == nil { - continue - } - flds = append(flds, v) - } - return flds - case *ArrayParameters: - return []*Field{params.Item} - } - - return nil + return f.ListFields() + + //switch params := f.Params.(type) { + //case *ObjectParameters: + // flds := make([]*Field, 0, len(params.Fields)) + // for _, v := range params.Fields { + // if v == nil { + // continue + // } + // flds = append(flds, v) + // } + // return flds + //case *ArrayParameters: + // return []*Field{params.Item} + //} + // + //return nil } // Clone создает копию поля @@ -477,7 +572,7 @@ func (f *Field) mergeField(fld *Field) error { func (f *Field) Merge(fields ...*Field) error { for _, fld := range fields { - f.mergeField(fld) + _ = f.mergeField(fld) } return nil } diff --git a/pkg/schema/field/field_json.go b/pkg/schema/field/field_json.go index dfb212044838d66da90436b127594427d3f842da..4d5dfcb80fc5d6758056753ea49b8e294c76aeae 100644 --- a/pkg/schema/field/field_json.go +++ b/pkg/schema/field/field_json.go @@ -61,13 +61,19 @@ func (f *Field) UnmarshalJSON(b []byte) error { } } + j.FieldData.State = f.State + *f = Field(j.FieldData) f.Params = params - f.Prepare() + _ = f.Prepare() return nil } func (f *Field) MarshalJSON() ([]byte, error) { + if f.Params == nil { + return nil, errors.New("field parameters is nil") + } + j := jsonField{ FieldData: FieldData(*f), } diff --git a/pkg/schema/field/field_test.go b/pkg/schema/field/field_test.go new file mode 100644 index 0000000000000000000000000000000000000000..cb0458ed610a428abe84dc038bc4c172c5560bb9 --- /dev/null +++ b/pkg/schema/field/field_test.go @@ -0,0 +1,121 @@ +package field + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestField_GetField(t *testing.T) { + sch := Object( + "f1", Object( + "a", String(), + "b", String().SetSingleLocale(true), + ), + "f3", Object( // inline object + true, + "a", String(), + "b", Object(true, "c", String()), + ).SetSingleLocale(true), + "f4", Array(Object("a", String())), + "f5", Array(String()), + "f6", Object(true, "f6", Object("a", String())), + ) + + sch.EnableState() + + tests := []struct { + name string + path string + want *State + }{ + {"Object", "f1", &State{Name: "f1", DataPath: "f1", SchemaPath: "f1", Parent: sch}}, + {"Object field", "f1.a", &State{Name: "a", DataPath: "f1.a", SchemaPath: "f1.a", Parent: sch.GetField("f1")}}, + {"Field with SingleLocale", "f1.b", &State{Name: "b", DataPath: "f1.b", SchemaPath: "f1.b", Parent: sch.GetField("f1"), SingleLocale: true}}, + {"Object with SingleLocale", "f3", &State{Name: "f3", DataPath: "f3", SchemaPath: "f3", Parent: sch, SingleLocale: true}}, + {"Inline", "a", &State{Name: "a", DataPath: "a", SchemaPath: "f3.a", Parent: sch.GetField("f3"), SingleLocale: true, Inlined: true, HasInline: true}}, + {"Inline of inline", "c", &State{Name: "c", DataPath: "c", SchemaPath: "f3.b.c", Parent: sch.GetField("f3.b"), SingleLocale: true, Inlined: true, HasInline: true}}, + {"Inline of inline (direct)", "f3.b.c", &State{Name: "c", DataPath: "c", SchemaPath: "f3.b.c", Parent: sch.GetField("f3.b"), SingleLocale: true, Inlined: true, HasInline: true}}, + {"Array of Objects", "f4", &State{Name: "f4", DataPath: "f4", SchemaPath: "f4", Parent: sch}}, + {"Array of Objects (Item)", "f4.Item", &State{Name: "Item", DataPath: "f4", SchemaPath: "f4.Item", Parent: sch.GetField("f4")}}, + {"Array of Objects (Item field)", "f4.Item.a", &State{Name: "a", DataPath: "f4.a", SchemaPath: "f4.Item.a", Parent: sch.GetField("f4.Item")}}, + {"Array of Objects (Item field direct)", "f4.a", &State{Name: "a", DataPath: "f4.a", SchemaPath: "f4.Item.a", Parent: sch.GetField("f4.Item")}}, + {"Array of Strings", "f5", &State{Name: "f5", DataPath: "f5", SchemaPath: "f5", Parent: sch}}, + {"Array of Strings (Item)", "f5.Item", &State{Name: "Item", DataPath: "f5", SchemaPath: "f5.Item", Parent: sch.GetField("f5")}}, + {"Inline Same name not found", "f6.a", nil}, + {"Inline Same name (direct)", "f6.f6.a", &State{Name: "a", DataPath: "f6.a", SchemaPath: "f6.f6.a", Parent: sch.GetField("f6.f6"), HasInline: true}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := sch.GetField(tt.path) + var st *State + if got != nil { + st = got.State + } + + assert.Equal(t, tt.want, st) + sch.ClearState() + sch.EnableState() + if got != nil { + assert.Nil(t, got.State) + } + }) + } +} + +func TestField_ListFieldsRecursive(t *testing.T) { + sch := Object( + "f1", Object( + "f1a", String(), + "f1b", String().SetSingleLocale(true), + ), + "f2", String(), + "f3", Object( // inline object + true, + "f3a", String(), + "f3b", Object(true, "f3bc", String()), + ).SetSingleLocale(true), + "f4", Array(Object("f4a", String())), + "f5", Array(String()), + "f6", Object(true, "f6", Object("f6a", String())), + ) + + sch.EnableState() + + fields := sch.ListFieldsRecursive() + assert.Len(t, fields, 16) + for _, f := range fields { + assert.NotNil(t, f.State) + assert.NotEmpty(t, f.State.Name) + } +} + +func TestField_ListFieldsRecursive_WithFilter(t *testing.T) { + sch := Object( + "f1", Object( + "b", Object( + "c", String().SetSingleLocale(true), + ), + ), + "f2", Object( + "b", Object( + "c", String().SetSingleLocale(true), + ), + ).SetSingleLocale(true), + ) + + sch.EnableState() + + fields := sch.ListFieldsRecursive(func(f *Field) bool { return f.SingleLocale == true }) + assert.Len(t, fields, 3) +} + +func TestField_CloneWithState(t *testing.T) { + f := Object("a", String()) + fld := f.Clone(false) + assert.Nil(t, fld.State) + f.EnableState() + fld = f.Clone(false) + assert.NotNil(t, fld.State) +} diff --git a/pkg/schema/field/loader.go b/pkg/schema/field/loader.go index 583ecc2c7c6bdc0d278819d2327280ec87858117..3beb0ddef0d68bdad2ec8f099dbfd5f853873c14 100644 --- a/pkg/schema/field/loader.go +++ b/pkg/schema/field/loader.go @@ -22,7 +22,7 @@ type multiLoader struct { func (c *multiLoader) Load(ctx context.Context, ref string) (fs []*Field, err error) { for _, l := range c.loaders { - if f, err := l.Load(nil, ref); err == nil { + if f, err := l.Load(ctx, ref); err == nil { return f, nil } } diff --git a/pkg/schema/field/location.go b/pkg/schema/field/location.go index d89b3206d091971a123e8842330f4b850838ccdf..97aea3ea8aecbf206325bbd1b49363669ce0436d 100644 --- a/pkg/schema/field/location.go +++ b/pkg/schema/field/location.go @@ -14,8 +14,10 @@ var locationType = &LocationType{} type LocationParameters struct{} -func (p LocationParameters) Type() Type { return locationType } -func (p LocationParameters) Clone(reset bool) Parameters { return &LocationParameters{} } +func (p LocationParameters) Type() Type { return locationType } +func (p LocationParameters) Clone(reset bool) Parameters { return &LocationParameters{} } +func (p LocationParameters) GetField(f *Field, name string) *Field { return nil } +func (p LocationParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } func (p LocationParameters) GetMongoIndexes(path string, f *Field) []mongo.IndexModel { var add, geo mongo.IndexModel diff --git a/pkg/schema/field/location_test.go b/pkg/schema/field/location_test.go index 5b8206b6128ae7f4bf8f4042cedc0540bf357992..2680dec74e3f312abdaaf88d97a6ab6a255c1c8f 100644 --- a/pkg/schema/field/location_test.go +++ b/pkg/schema/field/location_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "reflect" "testing" ) @@ -114,7 +115,7 @@ func TestLocationField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr) return @@ -196,7 +197,7 @@ func TestLocationField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Encode() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/field/number.go b/pkg/schema/field/number.go index 40d9c8167f54d23faaa40666ec1934b451d7a516..dfc8a6635cc0e719bd55e9f680ba23688674edd0 100644 --- a/pkg/schema/field/number.go +++ b/pkg/schema/field/number.go @@ -22,8 +22,10 @@ type NumberParameters struct { Format string `json:"format,omitempty"` } -func (NumberParameters) Type() Type { return numberType } -func (p NumberParameters) Clone(reset bool) Parameters { return &p } +func (NumberParameters) Type() Type { return numberType } +func (p NumberParameters) Clone(reset bool) Parameters { return &p } +func (p NumberParameters) GetField(f *Field, name string) *Field { return nil } +func (p NumberParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } type NumberType struct{} diff --git a/pkg/schema/field/object.go b/pkg/schema/field/object.go index d86aa2352544f68ea837152ec6799677f4624d1a..45bc3e61d835cca2b8ba1a8866636ccd740c48c4 100644 --- a/pkg/schema/field/object.go +++ b/pkg/schema/field/object.go @@ -36,6 +36,39 @@ func (p ObjectParameters) Clone(reset bool) Parameters { return &p } +func (p ObjectParameters) GetField(f *Field, name string) *Field { + // Поиск поля в текущем объекте + if fld, ok := p.Fields[name]; ok { + return f.SetFieldState(name, fld) + } + + // Поиск поля во вложенных Inline объектах + for k, v := range p.Fields { + if p, ok := v.Params.(*ObjectParameters); ok { + if p.Inline { + v = f.SetFieldState(k, v) + if fld := v.GetFieldByName(name); fld != nil { + return fld + } + } + } + } + + return nil +} + +func (p ObjectParameters) ListFields(f *Field, filterFunc ...FieldFilterFunc) []*Field { + var fields []*Field + for k, fld := range p.Fields { + f.SetFieldState(k, fld) + if !ApplyFilterFunc(filterFunc, fld) { + continue + } + fields = append(fields, fld) + } + return fields +} + // IsInlineObject определяет являться ли поле name инлайн объектом func (p ObjectParameters) IsInlineObject(name string) bool { fld, ok := p.Fields[name] @@ -74,12 +107,18 @@ func (p *ObjectParameters) Merge(parameters Parameters) error { if !ok { return errors.New("invalid object parameters") } + if op == nil { + return nil + } for k, fld := range op.Fields { if f, ok := p.Fields[k]; ok { if err := f.Merge(fld); err != nil { return err } } else { + if p.Fields == nil { + p.Fields = make(map[string]*Field) + } p.Fields[k] = fld } } diff --git a/pkg/schema/field/object_test.go b/pkg/schema/field/object_test.go index 2ada594bcdeba09fab5dfcc95eb947e2028766d9..cf4d773bedc4c02694e425602f918131ee5a2655 100644 --- a/pkg/schema/field/object_test.go +++ b/pkg/schema/field/object_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "fmt" "testing" "time" @@ -77,7 +78,7 @@ func TestObjectField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Decode() error = %v, want %v", err, tt.want.(string))) @@ -152,7 +153,7 @@ func TestObjectField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.want.(string), fmt.Sprintf("Encode() error = %v, want %v", err, tt.want.(string))) @@ -230,3 +231,59 @@ func TestFieldNameValidate(t *testing.T) { }) } } + +func TestObjectParameters_Merge(t *testing.T) { + tests := []struct { + name string + l, r *ObjectParameters + wantErr assert.ErrorAssertionFunc + want *ObjectParameters + }{ + { + name: "right is nil", + l: &ObjectParameters{}, + r: nil, + wantErr: assert.NoError, + want: &ObjectParameters{}, + }, + { + name: "right has nil Fields map", + l: objectType.NewParameters().(*ObjectParameters), + r: &ObjectParameters{Fields: nil}, + wantErr: assert.NoError, + want: &ObjectParameters{}, + }, + { + name: "left + right is empty object", + l: objectType.NewParameters().(*ObjectParameters), + r: objectType.NewParameters().(*ObjectParameters), + wantErr: assert.NoError, + want: &ObjectParameters{}, + }, + { + name: "left + right with data", + l: &ObjectParameters{Fields: map[string]*Field{"a": {Title: "Text1", Description: "test description"}}}, + r: &ObjectParameters{Fields: map[string]*Field{"b": {Title: "Text2", Description: "test description"}}}, + wantErr: assert.NoError, + want: &ObjectParameters{Fields: map[string]*Field{ + "a": {Title: "Text1", Description: "test description"}, + "b": {Title: "Text2", Description: "test description"}, + }}, + }, + { + name: "left empty + right with data", + l: &ObjectParameters{}, + r: &ObjectParameters{Fields: map[string]*Field{"b": {Title: "Text2", Description: "test description"}}}, + wantErr: assert.NoError, + want: &ObjectParameters{Fields: map[string]*Field{ + "b": {Title: "Text2", Description: "test description"}, + }}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.wantErr(t, tt.l.Merge(tt.r), fmt.Sprintf("Merge(%v)", tt.l)) + assert.Equal(t, tt.l, tt.want) + }) + } +} diff --git a/pkg/schema/field/primary_key.go b/pkg/schema/field/primary_key.go index b0b26e16a91cd506231ba46307485290a138bfb8..da40f97eb65c8551b3ca2710a26812ececea616f 100644 --- a/pkg/schema/field/primary_key.go +++ b/pkg/schema/field/primary_key.go @@ -12,8 +12,10 @@ var primaryKeyType = &PrimaryKeyType{} type PrimaryKeyParameters struct{} -func (p PrimaryKeyParameters) Type() Type { return primaryKeyType } -func (p *PrimaryKeyParameters) Clone(reset bool) Parameters { return p } +func (p PrimaryKeyParameters) Type() Type { return primaryKeyType } +func (p *PrimaryKeyParameters) Clone(reset bool) Parameters { return p } +func (p PrimaryKeyParameters) GetField(f *Field, name string) *Field { return nil } +func (p PrimaryKeyParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } type PrimaryKeyType struct{} diff --git a/pkg/schema/field/primary_key_test.go b/pkg/schema/field/primary_key_test.go index f74f32cafc72612d9b1575561718e6c625334d53..5e11ff00f62f95306bf302da8ae8ba9a5a94fd30 100644 --- a/pkg/schema/field/primary_key_test.go +++ b/pkg/schema/field/primary_key_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "reflect" "testing" ) @@ -18,7 +19,7 @@ func TestPrimaryKeyField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr) return @@ -43,7 +44,7 @@ func TestPrimaryKeyField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/field/string.go b/pkg/schema/field/string.go index b7e548b65f5c1572cc515cad19192899843ab62f..17b5e7ae086d3fac1b25d8c332c33d83fecedfb8 100644 --- a/pkg/schema/field/string.go +++ b/pkg/schema/field/string.go @@ -10,8 +10,10 @@ var stringType = &StringType{} type StringParameters struct{} -func (s StringParameters) Type() Type { return stringType } -func (s *StringParameters) Clone(reset bool) Parameters { return s } +func (s StringParameters) Type() Type { return stringType } +func (s *StringParameters) Clone(reset bool) Parameters { return s } +func (s StringParameters) GetField(f *Field, name string) *Field { return nil } +func (s StringParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } type StringType struct{} diff --git a/pkg/schema/field/string_test.go b/pkg/schema/field/string_test.go index d0fca29b8ed3f0c4ec987bf6705b7ea435116e40..16b7538fb86797946a4a3c3ba709e6e30cf4d5d8 100644 --- a/pkg/schema/field/string_test.go +++ b/pkg/schema/field/string_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "reflect" "testing" ) @@ -18,7 +19,7 @@ func TestStringField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr) return @@ -43,7 +44,7 @@ func TestStringField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/field/time.go b/pkg/schema/field/time.go index 064906f236371d2914a0544c3f6abef83fd77f65..cdb50a4cafc500ea56dd56436faa5babd4793d31 100644 --- a/pkg/schema/field/time.go +++ b/pkg/schema/field/time.go @@ -17,8 +17,10 @@ type TimeParameters struct { Layout string `json:"layout,omitempty"` } -func (p TimeParameters) Type() Type { return timeType } -func (p TimeParameters) Clone(reset bool) Parameters { return &p } +func (p TimeParameters) Type() Type { return timeType } +func (p TimeParameters) Clone(reset bool) Parameters { return &p } +func (p TimeParameters) GetField(f *Field, name string) *Field { return nil } +func (p TimeParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } func (p TimeParameters) GetLayout() string { if p.Layout != "" { diff --git a/pkg/schema/field/time_test.go b/pkg/schema/field/time_test.go index f9a8fb44552a0e0a704f7baae7ab10019c889bec..d315850f7352c706fe9ae34a699795f892a558f4 100644 --- a/pkg/schema/field/time_test.go +++ b/pkg/schema/field/time_test.go @@ -1,6 +1,7 @@ package field import ( + "context" "reflect" "testing" "time" @@ -21,7 +22,7 @@ func TestTimeField_Decode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Decode(nil, tt.field, tt.data) + got, err := Decode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Decode() error = %v, wantErr %v", err, tt.wantErr) return @@ -48,7 +49,7 @@ func TestTimeField_Encode(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Encode(nil, tt.field, tt.data) + got, err := Encode(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Encode() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/field/timestamp.go b/pkg/schema/field/timestamp.go index 694d477e0c6a55e5140c4e7d78d26381a31686ae..593218c645c016751d082d1e938d0c966134ebb9 100644 --- a/pkg/schema/field/timestamp.go +++ b/pkg/schema/field/timestamp.go @@ -13,8 +13,10 @@ var ( type TimestampParameters struct{} -func (t TimestampParameters) Type() Type { return timestampType } -func (t *TimestampParameters) Clone(reset bool) Parameters { return t } +func (t TimestampParameters) Type() Type { return timestampType } +func (t *TimestampParameters) Clone(reset bool) Parameters { return t } +func (t TimestampParameters) GetField(f *Field, name string) *Field { return nil } +func (t TimestampParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } type TimestampType struct{} diff --git a/pkg/schema/field/type.go b/pkg/schema/field/type.go index edae76734d562d2546d3b68e89e125c7a87744a6..984cd59187b8cd1f1380bcc0762d66366d4715ab 100644 --- a/pkg/schema/field/type.go +++ b/pkg/schema/field/type.go @@ -10,10 +10,23 @@ var ( registry sync.Map ) +type FieldFilterFunc func(f *Field) bool + +func ApplyFilterFunc(filterFunc []FieldFilterFunc, fld *Field) bool { + for _, f := range filterFunc { + if !f(fld) { + return false + } + } + return true +} + // Parameters - интерфейс который должен реализовывать параметр конкретного типа type Parameters interface { Type() Type Clone(reset bool) Parameters + GetField(f *Field, name string) *Field + ListFields(f *Field, filter ...FieldFilterFunc) []*Field } // Type - тип поля, отвечает за получение, кодирование и декодирование параметров для данного типа diff --git a/pkg/schema/field/unknown.go b/pkg/schema/field/unknown.go index f28a51cd1fbdc20a6b026d4504872149c939e727..36d0ba97fcd4b917af6e8986074d7f3f40e8654a 100644 --- a/pkg/schema/field/unknown.go +++ b/pkg/schema/field/unknown.go @@ -14,8 +14,10 @@ type UnknownParameters struct { Params json.RawMessage `json:"params,omitempty"` } -func (UnknownParameters) Type() Type { return unknownType } -func (p UnknownParameters) Clone(reset bool) Parameters { return &p } +func (UnknownParameters) Type() Type { return unknownType } +func (p UnknownParameters) Clone(reset bool) Parameters { return &p } +func (p UnknownParameters) GetField(f *Field, name string) *Field { return nil } +func (p UnknownParameters) ListFields(f *Field, filter ...FieldFilterFunc) []*Field { return nil } type UnknownType struct{} @@ -50,8 +52,7 @@ func (UnknownType) ConvertParameters(p Parameters) (Parameters, error) { } func Unknown(typ string, params json.RawMessage, o ...interface{}) *Field { - var pc ParametersConverter - pc = unknownType + pc := unknownType _ = pc return NewField(&UnknownParameters{Typ: typ, Params: params}, o...) } diff --git a/pkg/schema/localizer/localizer.go b/pkg/schema/localizer/localizer.go new file mode 100644 index 0000000000000000000000000000000000000000..4cc99d6075447c3eefe249f0b2963dca436c6e4f --- /dev/null +++ b/pkg/schema/localizer/localizer.go @@ -0,0 +1,253 @@ +package localizer + +import ( + "context" + "reflect" + + "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/pkg/locales" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "git.perx.ru/perxis/perxis-go/pkg/schema/walk" +) + +var ( + ErrLocaleDisabled = errors.New("cannot translate to disabled locale") + ErrLocaleNoPublish = errors.New("cannot translate to locale with disabled publication") +) + +type Localizer struct { + schema *schema.Schema + localesKV map[string]*locales.Locale + localeID string + locales []*locales.Locale + allowNoPublished bool + allowDisabled bool +} + +type Config struct { + Schema *schema.Schema + LocaleID string + Locales []*locales.Locale + AllowNoPublished bool + AllowDisabled bool +} + +// NewLocalizer создает экземпляр локализатора. Требуется указать "загруженную" схему +func NewLocalizer(cfg Config) *Localizer { + if cfg.LocaleID == "" { + cfg.LocaleID = locales.DefaultID + } + + loc := &Localizer{ + schema: cfg.Schema, + localesKV: make(map[string]*locales.Locale, len(cfg.Locales)), + locales: cfg.Locales, + localeID: cfg.LocaleID, + allowDisabled: cfg.AllowDisabled, + allowNoPublished: cfg.AllowNoPublished, + } + + for _, l := range cfg.Locales { + loc.localesKV[l.ID] = l + } + + return loc +} + +// Localize Получить полные локализованные данные для локали `localeID`. Входные параметры: +// - `data map[string]interface{}` - данные основной локали +// - `translations map[string]map[string]interface{}` переводы +// +// При отсутствии каких-либо полей в переводе на `localeID` данные берутся сначала из fallback-локали, +// если перевод отсутствует то из `data` +func (l *Localizer) Localize(data map[string]interface{}, translations map[string]map[string]interface{}) (localized map[string]interface{}, err error) { + target, fallback, err := l.getTargetAndFallBackLocales() + if err != nil { + return nil, err + } + + if target.IsDefault() { + return data, nil + } + + // localize fallback -> target + fallbackData := data + var exist bool + if !fallback.IsDefault() { + if fd, exist := translations[fallback.ID]; exist { + // localize default -> fallback + fallbackData, err = l.localize(fd, data) + if err != nil { + return nil, err + } + } + } + + if localized, exist = translations[target.ID]; !exist { + localized = make(map[string]interface{}) + } + + return l.localize(localized, fallbackData) +} + +// ExtractTranslation Получить "просеянные" данные для локали localeID: все поля, значения которых совпадают +// с переводом на fallback-локаль или основными данными, удаляются из перевода +func (l *Localizer) ExtractTranslation(data map[string]interface{}, translations map[string]map[string]interface{}) (translation map[string]interface{}, err error) { + target, fallback, err := l.getTargetAndFallBackLocales() + if err != nil { + return nil, err + } + + if target.IsDefault() { + return data, nil + } + + var exist bool + if translation, exist = translations[target.ID]; !exist { + return make(map[string]interface{}), nil + } + + var fallbackData map[string]interface{} + if fallbackData, exist = translations[fallback.ID]; !exist { + return l.extractTranslation(translation, data) + } + + // localize default -> fallback - нужно для корректного сравнения нельзя делать просто extract из прореженных данных fallback + if fallbackData, err = l.localize(fallbackData, data); err != nil { + return nil, err + } + + // extract translation default -> target + return l.extractTranslation(translation, fallbackData) +} + +func (l *Localizer) locale(localeID string) (loc *locales.Locale, err error) { + if localeID == "" { + return nil, locales.ErrLocaleIDRequired + } + + var exist bool + if loc, exist = l.localesKV[localeID]; !exist { + return nil, locales.ErrNotFound + } + + if loc == nil { + return nil, locales.ErrNotFound + } + + if !l.allowDisabled && loc.Disabled { + return nil, ErrLocaleDisabled + } + + if !l.allowNoPublished && localeID == l.localeID && loc.NoPublish { // can use non-publishing locale for fallback + return nil, ErrLocaleNoPublish + } + + return +} + +func (l *Localizer) Locale() (loc *locales.Locale, err error) { + return l.locale(l.localeID) +} + +func (l *Localizer) Locales() []*locales.Locale { + return l.locales +} + +func (l *Localizer) LocaleID() string { + return l.localeID +} + +func (l *Localizer) getTargetAndFallBackLocales() (target, fallback *locales.Locale, err error) { + if target, err = l.locale(l.localeID); err != nil { + return nil, nil, err + } + + if fallback, err = l.locale(target.Fallback); err != nil { + if fallback, err = l.locale(locales.DefaultID); err != nil { + return nil, nil, errors.Wrap(err, "get default locale") + } + } + return +} + +func (l *Localizer) localize(target, fallback map[string]interface{}) (map[string]interface{}, error) { + if target == nil && fallback == nil { + return nil, nil + } + + single := l.schema.GetFields(func(f *field.Field, p string) bool { + return f.SingleLocale + }) + + cfg := &walk.WalkConfig{Fields: make(map[string]walk.FieldConfig, len(single))} + for _, sn := range single { + cfg.Fields[sn.Path] = walk.FieldConfig{Fn: walk.KeepSrc} + } + + w := walk.NewWalker(l.schema, cfg) + w.DefaultFn = localize + + res, _, err := w.DataWalk(context.Background(), target, fallback) + if err != nil { + return nil, err + } + + if res != nil { + return res.(map[string]interface{}), err + } + + return nil, nil +} + +func (l *Localizer) extractTranslation(target, fallback map[string]interface{}) (map[string]interface{}, error) { + if target == nil && fallback == nil { + return nil, nil + } + + single := l.schema.GetFields(func(f *field.Field, p string) bool { + return f.SingleLocale + }) + + cfg := &walk.WalkConfig{Fields: make(map[string]walk.FieldConfig, len(single))} + for _, sn := range single { + cfg.Fields[sn.Path] = walk.FieldConfig{Fn: walk.RemoveValue} + } + + w := walk.NewWalker(l.schema, cfg) + w.DefaultFn = extractTranslation + + res, _, err := w.DataWalk(context.Background(), target, fallback) + if err != nil { + return nil, err + } + + if res == nil { + return map[string]interface{}{}, nil + } + + return res.(map[string]interface{}), nil +} + +func localize(c *walk.WalkContext) (err error) { + if c.Dst != nil { + return + } + + c.Dst = c.Src + c.Changed = true + return +} + +func extractTranslation(c *walk.WalkContext) (err error) { + if c.Dst == nil { + return + } + + if reflect.DeepEqual(c.Src, c.Dst) { + c.Dst = nil + c.Changed = true + } + return +} diff --git a/pkg/schema/localizer/localizer_test.go b/pkg/schema/localizer/localizer_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ab6b277cdcad36a1ffdd217f1ec198a2bf958f9f --- /dev/null +++ b/pkg/schema/localizer/localizer_test.go @@ -0,0 +1,938 @@ +package localizer + +import ( + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/locales" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLocalizer_localize(t *testing.T) { + + s := schema.New( + "a", field.String(), + "b", field.Number(field.NumberFormatInt), + "c", field.String().SetSingleLocale(true), + "obj1", field.Object( + "a", field.String(), + "b", field.Number(field.NumberFormatInt), + "c", field.Number(field.NumberFormatInt).SetSingleLocale(true), + "obj2", field.Object( + "a", field.Number(field.NumberFormatInt), + "b", field.String(), + "c", field.String().SetSingleLocale(true), + ), + ), + "obj3", field.Object( + "a", field.String(), + ).SetSingleLocale(true), + "slice", field.Array(field.String()), + "arr", field.Array(field.Object( + "num", field.Number(field.NumberFormatInt), + )), + ) + + tests := []struct { + fallback map[string]interface{} + target map[string]interface{} + want map[string]interface{} + name string + wantErr bool + }{ + { + name: "Nil", + fallback: nil, + target: nil, + want: nil, + }, + { + name: "Empty", + fallback: map[string]interface{}{}, + target: map[string]interface{}{}, + want: map[string]interface{}{}, + }, + { + name: "Target Empty", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{}, + want: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + }, + { + name: "Fallback Empty", + fallback: map[string]interface{}{}, + target: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + want: map[string]interface{}{ + "a": "en", + "b": 1, + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + }, + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + }, + { + name: "Equal", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + want: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + }, + { + name: "Target no single", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{ + "a": "en", + "b": 1, + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + }, + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + want: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + }, + { + name: "Success", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{ + "a": "ru", + "b": 11, + "obj1": map[string]interface{}{ + "a": "obj1_ru", + "b": 22, + "obj2": map[string]interface{}{ + "a": 33, + "b": "obj1_obj2_ru", + }, + }, + "slice": []interface{}{"ru_s3"}, + "arr": []interface{}{ + map[string]interface{}{"num": 1}, + map[string]interface{}{"num": 2}, + }, + }, + want: map[string]interface{}{ + "a": "ru", + "b": 11, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_ru", + "b": 22, + "c": 20, + "obj2": map[string]interface{}{ + "a": 33, + "b": "obj1_obj2_ru", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"ru_s3"}, + "arr": []interface{}{ + map[string]interface{}{"num": 1}, + map[string]interface{}{"num": 2}, + }, + }, + }, + { + name: "Success singlelocale obj", + fallback: map[string]interface{}{ + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + }, + target: map[string]interface{}{ + "obj3": map[string]interface{}{ + "a": "obj3", + }, + }, + want: map[string]interface{}{ + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := &Localizer{ + schema: s, + } + got, err := l.localize(tt.target, tt.fallback) + if !tt.wantErr { + require.NoError(t, err) + assert.Equal(t, tt.want, got) + return + } + require.Error(t, err) + }) + } +} + +func TestLocalizer_extractTranslation(t *testing.T) { + + s := schema.New( + "a", field.String(), + "b", field.Number(field.NumberFormatInt), + "c", field.String().SetSingleLocale(true), + "obj1", field.Object( + "a", field.String(), + "b", field.Number(field.NumberFormatInt), + "c", field.Number(field.NumberFormatInt).SetSingleLocale(true), + "obj2", field.Object( + "a", field.Number(field.NumberFormatInt), + "b", field.String(), + "c", field.String().SetSingleLocale(true), + ), + ), + "obj3", field.Object( + "a", field.String(), + ).SetSingleLocale(true), + "slice", field.Array(field.String()), + "arr", field.Array(field.Object( + "num", field.Number(field.NumberFormatInt), + )), + ) + + tests := []struct { + fallback map[string]interface{} + target map[string]interface{} + want map[string]interface{} + name string + wantErr bool + }{ + { + name: "Nil", + fallback: nil, + target: nil, + want: nil, + }, + { + name: "Empty", + fallback: map[string]interface{}{}, + target: map[string]interface{}{}, + want: map[string]interface{}{}, + }, + { + name: "Target Empty", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{}, + want: map[string]interface{}{}, + }, + { + name: "Fallback Empty", + fallback: map[string]interface{}{}, + target: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + want: map[string]interface{}{ + "a": "en", + "b": 1, + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + }, + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + }, + { + name: "Equal", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + want: map[string]interface{}{}, + }, + { + name: "Success", + fallback: map[string]interface{}{ + "a": "en", + "b": 1, + "c": "single", + "obj1": map[string]interface{}{ + "a": "obj1_en", + "b": 2, + "c": 20, + "obj2": map[string]interface{}{ + "a": 3, + "b": "obj1_obj2_en", + "c": "obj1_obj2_single", + }, + }, + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + "slice": []interface{}{"en_s1", "en_s2"}, + "arr": []interface{}{ + map[string]interface{}{"num": 11}, + map[string]interface{}{"num": 22}, + }, + }, + target: map[string]interface{}{ + "a": "ru", + "b": 11, + "obj1": map[string]interface{}{ + "a": "obj1_ru", + "b": 22, + "obj2": map[string]interface{}{ + "a": 33, + "b": "obj1_obj2_ru", + }, + }, + "slice": []interface{}{"ru_s3"}, + "arr": []interface{}{ + map[string]interface{}{"num": 1}, + map[string]interface{}{"num": 2}, + }, + }, + want: map[string]interface{}{ + "a": "ru", + "b": 11, + "obj1": map[string]interface{}{ + "a": "obj1_ru", + "b": 22, + "obj2": map[string]interface{}{ + "a": 33, + "b": "obj1_obj2_ru", + }, + }, + "slice": []interface{}{"ru_s3"}, + "arr": []interface{}{ + map[string]interface{}{"num": 1}, + map[string]interface{}{"num": 2}, + }, + }, + }, + { + name: "Success singlelocale obj", + fallback: map[string]interface{}{ + "obj3": map[string]interface{}{ + "a": "obj3_en", + }, + }, + target: map[string]interface{}{ + "obj3": map[string]interface{}{ + "a": "obj3_ru", + }, + }, + want: map[string]interface{}{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := &Localizer{ + schema: s, + } + got, err := l.extractTranslation(tt.target, tt.fallback) + if !tt.wantErr { + require.NoError(t, err) + assert.Equal(t, tt.want, got) + return + } + require.Error(t, err) + }) + } +} + +func TestLocalizer_getTargetAndFallBackLocales(t *testing.T) { + + tests := []struct { + localizer *Localizer + wantTarget *locales.Locale + wantFallback *locales.Locale + name string + wantErr bool + }{ + { + name: "Empty", + localizer: &Localizer{}, + wantErr: true, + }, + { + name: "Success", + localizer: &Localizer{ + localeID: "en", + localesKV: map[string]*locales.Locale{ + "en": {ID: "en"}, + "default": {ID: "default"}, + }, + }, + wantTarget: &locales.Locale{ID: "en"}, + wantFallback: &locales.Locale{ID: "default"}, + }, + { + name: "Success fallback", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "en": {ID: "en"}, + "ru": {ID: "ru", Fallback: "en"}, + "default": {ID: "default"}, + }, + }, + wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, + wantFallback: &locales.Locale{ID: "en"}, + }, + { + name: "Success fallback no default", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "en": {ID: "en"}, + "ru": {ID: "ru", Fallback: "en"}, + }, + }, + wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, + wantFallback: &locales.Locale{ID: "en"}, + }, + { + name: "Success fallback no fallback", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "ru": {ID: "ru", Fallback: "en"}, + "default": {ID: "default"}, + }, + }, + wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, + wantFallback: &locales.Locale{ID: "default"}, + }, + { + name: "Fail fallback no fallback", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "ru": {ID: "ru", Fallback: "en"}, + }, + }, + wantErr: true, + }, + { + name: "Fail target nil", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "ru": nil, + }, + }, + wantErr: true, + }, + { + name: "Fail target disabled", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "ru": {ID: "ru", Fallback: "en", Disabled: true}, + "default": {ID: "default"}, + }, + }, + wantErr: true, + }, + { + name: "Success fallback disabled", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "en": {ID: "en", Disabled: true}, + "ru": {ID: "ru", Fallback: "en"}, + "default": {ID: "default"}, + }, + }, + wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, + wantFallback: &locales.Locale{ID: "default"}, + }, + { + name: "Fail target no publish", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "ru": {ID: "ru", Fallback: "en", NoPublish: true}, + "default": {ID: "default"}, + }, + }, + wantErr: true, + }, + { + name: "Success fallback no publish", + localizer: &Localizer{ + localeID: "ru", + localesKV: map[string]*locales.Locale{ + "en": {ID: "en", NoPublish: true}, + "ru": {ID: "ru", Fallback: "en"}, + "default": {ID: "default"}, + }, + }, + wantTarget: &locales.Locale{ID: "ru", Fallback: "en"}, + wantFallback: &locales.Locale{ID: "en", NoPublish: true}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTarget, gotFallback, err := tt.localizer.getTargetAndFallBackLocales() + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.wantTarget, gotTarget) + assert.Equal(t, tt.wantFallback, gotFallback) + }) + } +} + +func TestLocalizer_ExtractTranslations(t *testing.T) { + + s := schema.New( + "a", field.String(), + "b", field.String(), + ) + + tests := []struct { + data map[string]interface{} + translations map[string]map[string]interface{} + want map[string]interface{} + cfg Config + name string + wantErr bool + }{ + { + name: "Extract default", + data: map[string]interface{}{"a": "bbb"}, + translations: map[string]map[string]interface{}{"en": {"a": "bbb"}}, + cfg: Config{ + LocaleID: "en", + Schema: s, + Locales: []*locales.Locale{ + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{}, + }, + { + name: "Extract default not same", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"en": {"a": "bbb"}}, + cfg: Config{ + LocaleID: "en", + Schema: s, + Locales: []*locales.Locale{ + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{"a": "bbb"}, + }, + { + name: "Extract default empty", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"en": {}}, + cfg: Config{ + LocaleID: "en", + Schema: s, + Locales: []*locales.Locale{ + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{}, + }, + { + name: "Extract fallback", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"ru": {"a": "bbb"}, "en": {"a": "bbb"}}, + cfg: Config{ + LocaleID: "ru", + Schema: s, + Locales: []*locales.Locale{ + {ID: "ru", Fallback: "en"}, + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{}, + }, + { + name: "Extract fallback with extracted field", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"ru": {"a": "bbb"}, "en": {}}, + cfg: Config{ + LocaleID: "ru", + Schema: s, + Locales: []*locales.Locale{ + {ID: "ru", Fallback: "en"}, + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{"a": "bbb"}, + }, + { + name: "Extract fallback with empty field", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"ru": {}, "en": {"a": "bbb"}}, + cfg: Config{ + LocaleID: "ru", + Schema: s, + Locales: []*locales.Locale{ + {ID: "ru", Fallback: "en"}, + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{}, + }, + { + name: "Extract fallback with same as default", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"ru": {"a": "aaa"}, "en": {"a": "bbb"}}, + cfg: Config{ + LocaleID: "ru", + Schema: s, + Locales: []*locales.Locale{ + {ID: "ru", Fallback: "en"}, + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{"a": "aaa"}, + }, + { + name: "Extract fallback with same", + data: map[string]interface{}{"a": "aaa"}, + translations: map[string]map[string]interface{}{"ru": {"a": "aaa"}, "en": {"a": "aaa", "b": "bbb"}}, + cfg: Config{ + LocaleID: "ru", + Schema: s, + Locales: []*locales.Locale{ + {ID: "ru", Fallback: "en"}, + {ID: "en"}, + {ID: "default"}, + }, + }, + want: map[string]interface{}{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := NewLocalizer(tt.cfg) + got, err := l.ExtractTranslation(tt.data, tt.translations) + if !tt.wantErr { + require.NoError(t, err) + assert.Equal(t, tt.want, got) + return + } + require.Error(t, err) + }) + } +} diff --git a/pkg/schema/modify/default.go b/pkg/schema/modify/default.go index 66ce6b89c0619ceb232050fa5ab057e4330fdfcb..637a0ff86021b61a59621a6aea7f63d89a40db64 100644 --- a/pkg/schema/modify/default.go +++ b/pkg/schema/modify/default.go @@ -14,7 +14,7 @@ type defaultValue struct { func (d *defaultValue) Prepare(f *field.Field) error { var err error - d.Value, err = field.Decode(nil, f, d.Value) + d.Value, err = field.Decode(context.Background(), f, d.Value) return err } diff --git a/pkg/schema/modify/default_test.go b/pkg/schema/modify/default_test.go index b99630dc65a9249d04bc1b29ac9e9fc902c745cf..6ea9d11047c13434553ae0ee7776a49ab0ffaf44 100644 --- a/pkg/schema/modify/default_test.go +++ b/pkg/schema/modify/default_test.go @@ -1,6 +1,7 @@ package modify import ( + "context" "testing" "time" @@ -45,9 +46,9 @@ func TestDefault(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - got, _, err = Modify(nil, tt.field, got) + got, _, err = Modify(context.Background(), tt.field, got) if (err != nil) != tt.wantErr { t.Errorf("Modify() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/modify/string_test.go b/pkg/schema/modify/string_test.go index ef90f7f6f4d6a43ff13b3ac10bda68602f09c5f4..2f6451266aa08612718321d1b85d4341f280ee74 100644 --- a/pkg/schema/modify/string_test.go +++ b/pkg/schema/modify/string_test.go @@ -1,6 +1,7 @@ package modify import ( + "context" "reflect" "testing" @@ -25,7 +26,7 @@ func TestTrimSpace(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, _, err := Modify(nil, tt.field, tt.data) + got, _, err := Modify(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Modify() error = %v, wantErr %v", err, tt.wantErr) return @@ -65,7 +66,7 @@ func TestModify(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, _, err := Modify(nil, tt.field, tt.data) + _, _, err := Modify(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.error) diff --git a/pkg/schema/modify/value_test.go b/pkg/schema/modify/value_test.go index 9878fc70663005f7650ac567899634a94446e8b9..eb3b9a99f6d4df61f738a993c35b61be2ea865eb 100644 --- a/pkg/schema/modify/value_test.go +++ b/pkg/schema/modify/value_test.go @@ -1,6 +1,7 @@ package modify import ( + "context" "reflect" "testing" @@ -50,7 +51,7 @@ func TestValue(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, _, err := Modify(nil, tt.field, tt.data) + got, _, err := Modify(context.Background(), tt.field, tt.data) if (err != nil) != tt.wantErr { t.Errorf("Modify() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index e45298241602e6855c63019fe5bebcc4e2df27ee..fdb402b412de15b3ba8aa9d2b0244ea3d22e8f09 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -4,6 +4,7 @@ import ( "context" "reflect" + "git.perx.ru/perxis/perxis-go" "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/expr" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -18,7 +19,9 @@ type Schema struct { } func New(kv ...interface{}) *Schema { - return &Schema{Field: *field.Object(kv...)} + s := &Schema{Field: *field.Object(kv...)} + s.Field.EnableState() + return s } func NewFromField(f *field.Field) *Schema { @@ -31,6 +34,10 @@ var ( Modify = modify.Modify Validate = validate.Validate Evaluate = field.Evaluate + + Assets = perxis.NewAssets[*Schema]().WithConstructor(func() *Schema { return New() }) + FromFS = Assets.FromFS + FromFile = Assets.FromFile ) func (s *Schema) Clone(reset bool) *Schema { @@ -41,6 +48,11 @@ func (s *Schema) Clone(reset bool) *Schema { } } +func (s *Schema) ClearState() *Schema { + s.Field.ClearState() + return s +} + func (s *Schema) Equal(sch *Schema) bool { if s == sch { return true @@ -71,12 +83,20 @@ func (s Schema) SetMetadata(md map[string]string) *Schema { return &s } +func (f Schema) SetSingleLocale(r bool) *Schema { + f.SingleLocale = r + return &f +} + func (s *Schema) ConvertTypes() error { b, err := s.MarshalJSON() if err != nil { return errors.Wrap(err, "marshal schema") } + // сохраняем состояние cхемы + state := s.Field.State *s = *New() + s.Field.State = state return errors.Wrap(s.UnmarshalJSON(b), "unmarshal schema") } @@ -222,7 +242,7 @@ func (s *Schema) Introspect(ctx context.Context, data map[string]interface{}) (m } if parent != nil && name != "" { - field.AddField(parent, name, fld) + _ = field.AddField(parent, name, fld) } ctx = context.WithValue(ctx, parentFieldCtxKey{}, fld) @@ -250,3 +270,12 @@ func (s *Schema) Introspect(ctx context.Context, data map[string]interface{}) (m return val, mutatedSchema, nil } + +// GetEnum возвращает список опций перечисления для поля +func (s *Schema) GetEnum(fieldPath string) []validate.EnumOpt { + f := s.Field.GetField(fieldPath) + if f == nil { + return nil + } + return validate.GetEnum(f) +} diff --git a/pkg/schema/schema_json.go b/pkg/schema/schema_json.go index e8710f76dfb8a5a81da279e4ba6d46f77a1bbdb8..0fe8a50b061cecabef84d358b53751139e6a5b21 100644 --- a/pkg/schema/schema_json.go +++ b/pkg/schema/schema_json.go @@ -1,10 +1,23 @@ package schema import ( + "io" + "git.perx.ru/perxis/perxis-go/pkg/errors" jsoniter "github.com/json-iterator/go" ) +func FromJSON(r io.Reader) (s *Schema, err error) { + data, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + s = New() + err = s.UnmarshalJSON(data) + return s, err +} + type jsonSchema struct { Loaded bool `json:"loaded"` Metadata map[string]string `json:"metadata"` @@ -16,6 +29,11 @@ func (s *Schema) UnmarshalJSON(b []byte) error { if err := jsoniter.Unmarshal(b, &j); err != nil { return errors.Wrapf(err, "error unmarshal json into field") } + + if j == nil { + return nil + } + s.Loaded = j.Loaded s.Metadata = j.Metadata @@ -23,15 +41,6 @@ func (s *Schema) UnmarshalJSON(b []byte) error { return err } - //if len(j.Field) > 0 { - // if err := s.Field.UnmarshalJSON(j.Field); err != nil { - // return err - // } - // //if err := jsoniter.Unmarshal(j.Field, &s.Field); err != nil { - // // return err - // //} - //} - return nil } diff --git a/pkg/schema/schema_json_test.go b/pkg/schema/schema_json_test.go new file mode 100644 index 0000000000000000000000000000000000000000..31b475168e9e0179328295044a7201517212d4ec --- /dev/null +++ b/pkg/schema/schema_json_test.go @@ -0,0 +1,78 @@ +package schema + +import ( + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "github.com/stretchr/testify/assert" +) + +func TestSchema_UnmarshalJSON(t *testing.T) { + s := `{ + "ui": { + "options": { + "fields": [ + "text" + ] + } + }, + "type": "object", + "params": { + "inline": false, + "fields": { + "text": { + "title": "text", + "ui": { + "widget": "StringInput" + }, + "type": "string", + "params": {} + } + } + }, + "loaded": false, + "metadata": null +}` + tests := []struct { + name string + b []byte + want *Schema + wantErr bool + }{ + { + name: "No panic with 'null' value in b", + b: []byte("null"), + want: New(), + wantErr: false, + }, + { + name: "UnmarshalJSON error #1", + b: []byte(""), + want: New(), + wantErr: true, + }, + { + name: "UnmarshalJSON error #2", + b: []byte("abc"), + want: New(), + wantErr: true, + }, + { + name: "OK", + b: []byte(s), + want: New("text", field.String().SetTitle("text").WithUI(&field.UI{Widget: "StringInput"})), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + schema := New() + if err := schema.UnmarshalJSON(tt.b); (err != nil) != tt.wantErr { + t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + schema.ClearState() + tt.want.ClearState() + assert.Equal(t, tt.want, schema) + }) + } +} diff --git a/pkg/schema/schema_test.go b/pkg/schema/schema_test.go new file mode 100644 index 0000000000000000000000000000000000000000..dbedf48f9667c348c0898b73a3d308312aede6c6 --- /dev/null +++ b/pkg/schema/schema_test.go @@ -0,0 +1,18 @@ +package schema + +import ( + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "github.com/stretchr/testify/assert" +) + +func TestSchema_Clone(t *testing.T) { + f := New("a", field.String()) + f.ClearState() + fld := f.Clone(false) + assert.Nil(t, fld.State) + f.EnableState() + fld = f.Clone(false) + assert.NotNil(t, fld.State) +} diff --git a/pkg/schema/test/assets/invalid.json b/pkg/schema/test/assets/invalid.json new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pkg/schema/test/assets/not_schema.txt b/pkg/schema/test/assets/not_schema.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/pkg/schema/test/assets/web_pages.json b/pkg/schema/test/assets/web_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..652753c911e79dca0896b2c57587400202d0da69 --- /dev/null +++ b/pkg/schema/test/assets/web_pages.json @@ -0,0 +1,420 @@ +{ + "ui": { + "widget": "Tabs", + "options": { + "description": "path", + "collection_icon": "ApartmentOutlined/FileTextOutlined", + "fields": [ + "content", + "seo", + "settings", + "advanced", + "design", + "variables" + ], + "title": "name", + "key": "path" + }, + "list_view": { + "options": { + "sort": [ + "path" + ], + "page_size": 50, + "fields": [ + "path", + "name", + "updated_at", + "updated_by", + "state" + ] + } + } + }, + "includes": [ + { + "ref": "hoop_item_options", + "optional": true + }, + { + "ref": "ext_web_pages_*", + "optional": true + } + ], + "type": "object", + "params": { + "inline": false, + "fields": { + "design": { + "title": "Дизайн", + "includes": [ + { + "ref": "web_design" + } + ], + "type": "object", + "params": { + "inline": false, + "fields": {} + } + }, + "variables": { + "title": "Переменные", + "ui": { + "options": { + "fields": [ + "variables" + ] + } + }, + "type": "object", + "params": { + "inline": true, + "fields": { + "variables": { + "type": "array", + "params": { + "item": { + "ui": { + "options": { + "collection_icon": "SettingOutlined/FileExcelOutlined", + "fields": [ + "id", + "name", + "value" + ] + }, + "list_view": { + "options": { + "fields": [ + "id", + "name", + "updated_at", + "updated_by", + "state" + ], + "page_size": 50 + } + } + }, + "type": "object", + "params": { + "inline": false, + "fields": { + "id": { + "title": "Идентификатор переменной", + "text_search": true, + "options": { + "required": true + }, + "type": "string", + "params": {} + }, + "name": { + "title": "Название переменной", + "text_search": true, + "type": "string", + "params": {} + }, + "value": { + "title": "Значение переменной", + "type": "string", + "params": {} + } + } + } + } + } + } + } + } + }, + "content": { + "title": "Содержимое страницы", + "ui": { + "options": { + "fields": [ + "blocks" + ] + } + }, + "type": "object", + "params": { + "inline": true, + "fields": { + "blocks": { + "title": "Блоки", + "ui": { + "widget": "BlockList", + "options": { + "create": { + "classes": [ + "class_web_blocks" + ] + } + } + }, + "type": "array", + "params": { + "item": { + "title": "Блок", + "type": "reference", + "params": { + "allowedCollections": [ + "web_block_*" + ] + } + } + } + } + } + } + }, + "seo": { + "title": "SEO", + "includes": [ + { + "ref": "web_seo" + } + ], + "type": "object", + "params": { + "inline": false, + "fields": {} + } + }, + "settings": { + "title": "Настройки", + "ui": { + "options": { + "fields": [ + "name", + "parent", + "path", + "slug", + "section", + "datasource", + "redirect", + "redirect_path", + "redirect_url", + "outputs", + "navTitle", + "navHide", + "weight" + ] + } + }, + "type": "object", + "params": { + "inline": true, + "fields": { + "path": { + "title": "Путь", + "unique": true, + "text_search": true, + "options": { + "value": "$perxis.Item.Template == true ? _value : parent == nil ? '/' : slug == nil ? make_path(parent, slugify(replace_markers(name))) : make_path(parent, slugify(replace_markers(slug)))" + }, + "type": "string", + "params": {} + }, + "redirect_url": { + "title": "URL для перехода", + "condition": "redirect == true", + "type": "string", + "params": {} + }, + "outputs": { + "title": "Форматы страницы для вывода", + "type": "array", + "params": { + "item": { + "ui": { + "widget": "Lookup", + "options": { + "allowedCollections": [ + { + "collection": "web_outputs" + } + ] + } + }, + "type": "string", + "params": {} + } + } + }, + "weight": { + "title": "Порядок следования", + "ui": { + "widget": "NumberInput" + }, + "type": "number", + "params": { + "format": "int" + } + }, + "navHide": { + "title": "Скрыть страницу из навигации", + "ui": { + "widget": "Checkbox" + }, + "type": "bool", + "params": {} + }, + "section": { + "title": "Раздел", + "ui": { + "widget": "Checkbox" + }, + "type": "bool", + "params": {} + }, + "parent": { + "title": "Родительский раздел", + "description": "Раздел сайта, где расположена страница", + "ui": { + "widget": "Lookup", + "options": { + "allowedCollections": [ + { + "collection": "web_pages" + } + ] + } + }, + "type": "string", + "params": {} + }, + "name": { + "title": "Название", + "indexed": true, + "text_search": true, + "options": { + "required": true, + "value": "$perxis.Item.Template == true ? _value : replace_markers(_value)" + }, + "type": "string", + "params": {} + }, + "navTitle": { + "title": "Название для навигации", + "type": "string", + "params": {} + }, + "redirect_path": { + "title": "Страница для перехода", + "ui": { + "widget": "Lookup", + "options": { + "allowedCollections": [ + { + "collection": "web_pages" + } + ] + } + }, + "condition": "redirect == true", + "type": "string", + "params": {} + }, + "datasource": { + "title": "Источник данных", + "description": "Источник данных из которого будут формироваться подстраницы раздела", + "ui": { + "widget": "Lookup", + "options": { + "allowedCollections": [ + { + "collection": "web_datasources" + } + ] + } + }, + "condition": "section == true", + "type": "string", + "params": {} + }, + "redirect": { + "title": "Перенаправление", + "description": "Страница не имеет содержимого и перенаправляет посетителей на другой адрес", + "ui": { + "widget": "Checkbox" + }, + "type": "bool", + "params": {} + }, + "slug": { + "title": "Slug", + "description": "Идентификатор страницы в адресе URL", + "text_search": true, + "options": { + "value": "$perxis.Item.Template == true ? _value : parent == nil ? nil : _value == nil ? slugify(replace_markers(name)) : slugify(replace_markers(_value))" + }, + "type": "string", + "params": {} + } + } + } + }, + "advanced": { + "title": "Расширенные настройки", + "ui": { + "options": { + "fields": [ + "scripts" + ] + } + }, + "type": "object", + "params": { + "inline": false, + "fields": { + "scripts": { + "title": "Дополнительные скрипты", + "type": "array", + "params": { + "item": { + "ui": { + "options": { + "fields": [ + "src", + "type", + "content" + ] + } + }, + "type": "object", + "params": { + "inline": false, + "fields": { + "type": { + "title": "Media Type скрипта", + "type": "string", + "params": {} + }, + "content": { + "title": "Содержимое скрипта", + "type": "string", + "params": {} + }, + "src": { + "title": "URL для загрузки скрипта", + "type": "string", + "params": {} + } + } + } + } + } + } + } + } + } + } + }, + "loaded": false, + "metadata": { + "extension": "perxisweb" + } +} \ No newline at end of file diff --git a/pkg/schema/test/assets/web_pages.yml b/pkg/schema/test/assets/web_pages.yml new file mode 100644 index 0000000000000000000000000000000000000000..7fdfdd24fa9dcaa04d31ca1506955c86d6e3ce43 --- /dev/null +++ b/pkg/schema/test/assets/web_pages.yml @@ -0,0 +1,297 @@ +--- +ui: + widget: Tabs + options: + description: path + collection_icon: ApartmentOutlined/FileTextOutlined + fields: + - content + - seo + - settings + - advanced + - design + - variables + title: name + key: path + list_view: + options: + sort: + - path + page_size: 50 + fields: + - path + - name + - updated_at + - updated_by + - state +includes: +- ref: hoop_item_options + optional: true +- ref: ext_web_pages_* + optional: true +type: object +params: + inline: false + fields: + design: + title: Дизайн + includes: + - ref: web_design + type: object + params: + inline: false + fields: {} + variables: + title: Переменные + ui: + options: + fields: + - variables + type: object + params: + inline: true + fields: + variables: + type: array + params: + item: + ui: + options: + collection_icon: SettingOutlined/FileExcelOutlined + fields: + - id + - name + - value + list_view: + options: + fields: + - id + - name + - updated_at + - updated_by + - state + page_size: 50 + type: object + params: + inline: false + fields: + id: + title: Идентификатор переменной + text_search: true + options: + required: true + type: string + params: {} + name: + title: Название переменной + text_search: true + type: string + params: {} + value: + title: Значение переменной + type: string + params: {} + content: + title: Содержимое страницы + ui: + options: + fields: + - blocks + type: object + params: + inline: true + fields: + blocks: + title: Блоки + ui: + widget: BlockList + options: + create: + classes: + - class_web_blocks + type: array + params: + item: + title: Блок + type: reference + params: + allowedCollections: + - web_block_* + seo: + title: SEO + includes: + - ref: web_seo + type: object + params: + inline: false + fields: {} + settings: + title: Настройки + ui: + options: + fields: + - name + - parent + - path + - slug + - section + - datasource + - redirect + - redirect_path + - redirect_url + - outputs + - navTitle + - navHide + - weight + type: object + params: + inline: true + fields: + path: + title: Путь + unique: true + text_search: true + options: + value: "$perxis.Item.Template == true ? _value : parent == nil ? '/' + : slug == nil ? make_path(parent, slugify(replace_markers(name))) + : make_path(parent, slugify(replace_markers(slug)))" + type: string + params: {} + redirect_url: + title: URL для перехода + condition: redirect == true + type: string + params: {} + outputs: + title: Форматы страницы для вывода + type: array + params: + item: + ui: + widget: Lookup + options: + allowedCollections: + - collection: web_outputs + type: string + params: {} + weight: + title: Порядок следования + ui: + widget: NumberInput + type: number + params: + format: int + navHide: + title: Скрыть страницу из навигации + ui: + widget: Checkbox + type: bool + params: {} + section: + title: Раздел + ui: + widget: Checkbox + type: bool + params: {} + parent: + title: Родительский раздел + description: Раздел сайта, где расположена страница + ui: + widget: Lookup + options: + allowedCollections: + - collection: web_pages + type: string + params: {} + name: + title: Название + indexed: true + text_search: true + options: + required: true + value: "$perxis.Item.Template == true ? _value : replace_markers(_value)" + type: string + params: {} + navTitle: + title: Название для навигации + type: string + params: {} + redirect_path: + title: Страница для перехода + ui: + widget: Lookup + options: + allowedCollections: + - collection: web_pages + condition: redirect == true + type: string + params: {} + datasource: + title: Источник данных + description: Источник данных из которого будут формироваться подстраницы + раздела + ui: + widget: Lookup + options: + allowedCollections: + - collection: web_datasources + condition: section == true + type: string + params: {} + redirect: + title: Перенаправление + description: Страница не имеет содержимого и перенаправляет посетителей + на другой адрес + ui: + widget: Checkbox + type: bool + params: {} + slug: + title: Slug + description: Идентификатор страницы в адресе URL + text_search: true + options: + value: "$perxis.Item.Template == true ? _value : parent == nil ? nil + : _value == nil ? slugify(replace_markers(name)) : slugify(replace_markers(_value))" + type: string + params: {} + advanced: + title: Расширенные настройки + ui: + options: + fields: + - scripts + type: object + params: + inline: false + fields: + scripts: + title: Дополнительные скрипты + type: array + params: + item: + ui: + options: + fields: + - src + - type + - content + type: object + params: + inline: false + fields: + type: + title: Media Type скрипта + type: string + params: {} + content: + title: Содержимое скрипта + type: string + params: {} + src: + title: URL для загрузки скрипта + type: string + params: {} +loaded: false +metadata: + extension: perxisweb diff --git a/pkg/schema/test/convert_test.go b/pkg/schema/test/convert_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5e791570ebfc12c9efc9a4c9295ce5dacced4af5 --- /dev/null +++ b/pkg/schema/test/convert_test.go @@ -0,0 +1,174 @@ +package test + +import ( + "os" + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/extension" + "git.perx.ru/perxis/perxis-go/pkg/references" + "git.perx.ru/perxis/perxis-go/pkg/schema" + "git.perx.ru/perxis/perxis-go/pkg/schema/field" + "git.perx.ru/perxis/perxis-go/pkg/schema/modify" + "git.perx.ru/perxis/perxis-go/pkg/schema/validate" + "github.com/stretchr/testify/require" +) + +func TestFromFiles(t *testing.T) { + t.Run("Non-existen path", func(t *testing.T) { + schemas, err := schema.FromFS(os.DirFS("non-existen")) + require.Error(t, err) + require.ErrorContains(t, err, "no such file or directory") + require.Nil(t, schemas) + }) + + t.Run("Success", func(t *testing.T) { + schemas, err := schema.FromFS(os.DirFS("assets")) + for _, s := range schemas { + s.ClearState() + } + require.NoError(t, err) + require.Len(t, schemas, 2, "В директории хранятся две корректные схемы") + require.ElementsMatch(t, []*schema.Schema{getPagesSchema(), getPagesSchema()}, schemas, "Cхемы должны соответствовать объекту из функции") + }) +} + +// Оригинальное объявление схемы Web/Страницы +// Значение констант подставлено вручную +func getPagesSchema() *schema.Schema { + content := field.Object( + true, "blocks", field.Array( + references.Field([]string{"web_block_*"}).SetTitle("Блок"), + ). + SetTitle("Блоки"). + WithUI(&field.UI{ + Widget: "BlockList", + Options: map[string]interface{}{ + "create": map[string]interface{}{ + "classes": []string{"class_web_blocks"}, + }, + }, + }), + ).SetTitle("Содержимое страницы") + + // SEO + seo := field.Object().WithIncludes("web_seo").SetTitle("SEO") + + //Settings + settings := field.Object(true, + "name", field.String( + validate.Required(), + modify.Value("$perxis.Item.Template == true ? _value : replace_markers(_value)"), + ).SetTitle("Название").SetTextSearch(true).SetIndexed(true), + "parent", field.String().SetTitle("Родительский раздел").SetDescription("Раздел сайта, где расположена страница").WithUI(&field.UI{ + Widget: "Lookup", + Options: map[string]interface{}{ + "allowedCollections": []interface{}{ + map[string]interface{}{"collection": "web_pages"}, + }, + }, + }), // TODO lookup "section == true" + "path", field.String( + modify.Value("$perxis.Item.Template == true ? _value : parent == nil ? '/' : slug == nil ? make_path(parent, slugify(replace_markers(name))) : make_path(parent, slugify(replace_markers(slug)))"), + ).SetTitle("Путь").SetUnique(true).SetTextSearch(true), // TODO readonly + "slug", field.String(modify.Value("$perxis.Item.Template == true ? _value : parent == nil ? nil : _value == nil ? slugify(replace_markers(name)) : slugify(replace_markers(_value))")).SetTitle("Slug").SetDescription("Идентификатор страницы в адресе URL").SetTextSearch(true), + "section", field.Bool().SetTitle("Раздел").WithUI(&field.UI{Widget: "Checkbox"}), + "datasource", field.String().WithUI(&field.UI{ + Widget: "Lookup", + Options: map[string]interface{}{ + "allowedCollections": []interface{}{ + map[string]interface{}{"collection": "web_datasources"}, + }, + }, + }).SetTitle("Источник данных").SetDescription("Источник данных из которого будут формироваться подстраницы раздела").SetCondition("section == true"), + "redirect", field.Bool().SetTitle("Перенаправление").SetDescription("Страница не имеет содержимого и перенаправляет посетителей на другой адрес").WithUI(&field.UI{Widget: "Checkbox"}), + "redirect_path", field.String().SetTitle("Страница для перехода").WithUI(&field.UI{ + Widget: "Lookup", + Options: map[string]interface{}{ + "allowedCollections": []interface{}{ + map[string]interface{}{"collection": "web_pages"}, + }, + }, + }).SetCondition("redirect == true"), + "redirect_url", field.String().SetTitle("URL для перехода").SetCondition("redirect == true"), + "outputs", field.Array(field.String().WithUI(&field.UI{ + Widget: "Lookup", + Options: map[string]interface{}{ + "allowedCollections": []interface{}{ + map[string]interface{}{"collection": "web_outputs"}, + }, + }, + })).SetTitle("Форматы страницы для вывода"), + "navTitle", field.String().SetTitle("Название для навигации"), + "navHide", field.Bool().SetTitle("Скрыть страницу из навигации").WithUI(&field.UI{Widget: "Checkbox"}), + "weight", field.Number(field.NumberFormatInt).SetTitle("Порядок следования").WithUI(&field.UI{Widget: "NumberInput"}), + ).SetTitle("Настройки") + + // Advanced + advanced := field.Object( + "scripts", field.Array( + field.Object( + "src", field.String().SetTitle("URL для загрузки скрипта"), + "type", field.String().SetTitle("Media Type скрипта"), + "content", field.String().SetTitle("Содержимое скрипта"), + ), + ).SetTitle("Дополнительные скрипты"), + ).SetTitle("Расширенные настройки") + + // Design + design := field.Object().WithIncludes("web_design").SetTitle("Дизайн") + + //Variables + variables := field.Object(true, "variables", field.Array(getVarsField())).SetTitle("Переменные") + + // Page + page := schema.New( + "content", content, + "seo", seo, + "settings", settings, + "advanced", advanced, + "design", design, + "variables", variables, + ).WithMetadata(extension.MetadataKey, "perxisweb") + + // Includes + page.SetIncludes( + field.Include{Ref: "hoop_item_options", Optional: true}, + field.Include{Ref: "ext_web_pages_*", Optional: true}, + ) + + //UI + page.Field.UI.ListView = &field.View{Options: map[string]interface{}{ + "fields": []string{"path", "name", "updated_at", "updated_by", "state"}, + "sort": []string{"path"}, + "page_size": 50, + }} + page.Field.UI.Options["title"] = "name" + page.Field.UI.Options["key"] = "path" + page.Field.UI.Options["description"] = "path" + page.Field.UI.Widget = "Tabs" + page.Field.UI.Options["collection_icon"] = "ApartmentOutlined/FileTextOutlined" + + _ = page.ConvertTypes() + page.ClearState() + return page +} + +func getVarsSchema() (sch *schema.Schema) { + sch = schema.New( + "id", field.String(validate.Required()).SetTextSearch(true).SetTitle("Идентификатор переменной"), + "name", field.String().SetTextSearch(true).SetTitle("Название переменной"), + "value", field.String().SetTitle("Значение переменной"), + ).WithMetadata(extension.MetadataKey, "perxisweb") + //UI + sch.Field.UI.ListView = &field.View{Options: map[string]interface{}{ + "fields": []string{"id", "name", "updated_at", "updated_by", "state"}, + "page_size": 50, + }} + + sch.Field.UI.Options["collection_icon"] = "SettingOutlined/FileExcelOutlined" + return sch +} + +func getVarsField() *field.Field { + return &getVarsSchema().Field +} diff --git a/pkg/schema/test/object_test.go b/pkg/schema/test/object_test.go index 38868f66989108c142e50eaad62539be381edb4f..8bf3f82022e8501932e6474a985bcfc9f195e693 100644 --- a/pkg/schema/test/object_test.go +++ b/pkg/schema/test/object_test.go @@ -65,7 +65,7 @@ func TestNumberField_JSON(t *testing.T) { b, err := json.MarshalIndent(fld, "", " ") require.NoError(t, err) - //fmt.Println(string(b)) + // fmt.Println(string(b)) res := field.NewField(nil) err = json.Unmarshal(b, res) @@ -187,12 +187,15 @@ func TestSchema_JSON(t *testing.T) { b, err := json.MarshalIndent(sch, "", " ") require.NoError(t, err) - //fmt.Println(string(b)) + // fmt.Println(string(b)) res := schema.New() err = json.Unmarshal(b, res) require.NoError(t, err) + sch.ClearState() + res.ClearState() + assert.Equal(t, sch, res) } @@ -213,6 +216,7 @@ func TestSchemaUI_UnmarshalJSON(t *testing.T) { "name", field.String().WithUI(ui), ) schm.UI = ui + schm.ClearState() j := `{ "ui": { @@ -288,6 +292,7 @@ func TestSchemaUI_UnmarshalJSON(t *testing.T) { sch := schema.New() err := sch.UnmarshalJSON([]byte(j)) + sch.ClearState() require.NoError(t, err) assert.Equal(t, sch, schm) } @@ -364,7 +369,7 @@ func TestSchema_GetField_WithInline(t *testing.T) { "a", field.String(), "b", field.String(), ), - "zz", field.Object( + "zzz", field.Object( true, "zz", field.Array(field.Object( "str3", field.String(), @@ -703,7 +708,7 @@ func TestSchema_Modify(t *testing.T) { ) in := map[string]interface{}{"last_name": "Curie", "name": "Marie"} - _, _, err := modify.Modify(nil, sch, in) + _, _, err := modify.Modify(context.Background(), sch, in) require.NoError(t, err) } @@ -724,7 +729,7 @@ func TestSchema_Validate(t *testing.T) { ) in := map[string]interface{}{"info": map[string]interface{}{"time": time.Now()}, "name": "Name"} - err := validate.Validate(nil, sch, in) + err := validate.Validate(context.Background(), sch, in) require.NoError(t, err) } @@ -768,9 +773,9 @@ func TestSchema_ValidateErrors(t *testing.T) { ) in := map[string]interface{}{"a": map[string]interface{}{"num2": 20, "num3": 5, "str1": "123456", "str2": "123", "str3": "some"}} - decoded, err := schema.Decode(nil, sch, in) + decoded, err := schema.Decode(context.Background(), sch, in) require.NoError(t, err) - err = validate.Validate(nil, sch, decoded) + err = validate.Validate(context.Background(), sch, decoded) require.Error(t, err) require.Contains(t, err.Error(), "validation error") var merr *multierror.Error @@ -784,11 +789,11 @@ func TestSchema_ValidateEmptyObject(t *testing.T) { "num1", field.Number(field.NumberFormatInt, validate.Required()), ) - res, err := schema.Decode(nil, sch, nil) + res, err := schema.Decode(context.Background(), sch, nil) require.NoError(t, err) - res, _, err = modify.Modify(nil, sch, res) + res, _, err = modify.Modify(context.Background(), sch, res) require.NoError(t, err) - err = validate.Validate(nil, sch, res) + err = validate.Validate(context.Background(), sch, res) require.NoError(t, err, "поля объекта nil не проверяются") } { @@ -796,11 +801,11 @@ func TestSchema_ValidateEmptyObject(t *testing.T) { "num1", field.Number(field.NumberFormatInt, validate.Required()), ) - res, err := schema.Decode(nil, sch, map[string]interface{}{}) + res, err := schema.Decode(context.Background(), sch, map[string]interface{}{}) require.NoError(t, err) - res, _, err = modify.Modify(nil, sch, res) + res, _, err = modify.Modify(context.Background(), sch, res) require.NoError(t, err) - err = validate.Validate(nil, sch, res) + err = validate.Validate(context.Background(), sch, res) require.Error(t, err, "поля пустого объекта проверяются") } { @@ -808,11 +813,11 @@ func TestSchema_ValidateEmptyObject(t *testing.T) { "num1", field.Number(field.NumberFormatInt, validate.Required()), ) - res, err := schema.Decode(nil, sch, map[string]interface{}{"a": "sss"}) + res, err := schema.Decode(context.Background(), sch, map[string]interface{}{"a": "sss"}) require.NoError(t, err) - res, _, err = modify.Modify(nil, sch, res) + res, _, err = modify.Modify(context.Background(), sch, res) require.NoError(t, err) - err = validate.Validate(nil, sch, res) + err = validate.Validate(context.Background(), sch, res) require.Error(t, err, "поля объекта с некорректными данными проверяются") } @@ -821,11 +826,11 @@ func TestSchema_ValidateEmptyObject(t *testing.T) { "num1", field.Number(field.NumberFormatInt, validate.Required()), ).AddOptions(modify.Default(map[string]interface{}{})) - res, err := schema.Decode(nil, sch, nil) + res, err := schema.Decode(context.Background(), sch, nil) require.NoError(t, err) - res, _, err = modify.Modify(nil, sch, res) + res, _, err = modify.Modify(context.Background(), sch, res) require.NoError(t, err) - err = validate.Validate(nil, sch, res) + err = validate.Validate(context.Background(), sch, res) require.Error(t, err, "поля nil объекта Default данными проверяются") } } @@ -839,9 +844,9 @@ func TestSchema_ModificationErrors(t *testing.T) { ) in := map[string]interface{}{"a": map[string]interface{}{"num1": 20, "num3": 5, "str1": "123456", "str2": "123", "str3": "some"}} - decoded, err := schema.Decode(nil, sch, in) + decoded, err := schema.Decode(context.Background(), sch, in) require.NoError(t, err) - _, _, err = modify.Modify(nil, sch, decoded) + _, _, err = modify.Modify(context.Background(), sch, decoded) require.Error(t, err) require.Contains(t, err.Error(), "modification error") var merr *multierror.Error @@ -857,6 +862,7 @@ func TestSchema_UnknownJSON(t *testing.T) { "times", field.Number("int"), "dates", field.Array(field.Time()), ) + sch.ClearState() b, err := json.Marshal(sch) require.NoError(t, err) @@ -868,10 +874,10 @@ func TestSchema_UnknownJSON(t *testing.T) { assert.Equal(t, "unknown", s1.GetType().Name(), "Схема неизвестного типа должна определяться как unknown") in := map[string]interface{}{"info": map[string]interface{}{"time": time.Now()}, "name": "Name"} - out, err := field.Decode(nil, s1, in) + out, err := field.Decode(context.Background(), s1, in) require.NoError(t, err) assert.Equal(t, in, out, "Данные неизвестного типа не изменяются при декодировании") - err = validate.Validate(nil, s1, in) + err = validate.Validate(context.Background(), s1, in) require.NoError(t, err, "Данные неизвестного типа не валидируются вглубь") b, err = json.Marshal(s1) @@ -881,6 +887,8 @@ func TestSchema_UnknownJSON(t *testing.T) { require.NoError(t, err) b, err = json.Marshal(s2) require.NoError(t, err) + s1.ClearState() + s2.ClearState() assert.Equal(t, "unknown", s2.GetType().Name(), "Схема неизвестного типа должна определяться как unknown") assert.Equal(t, s1, s2, "Схема не должна меняться при повторном маршалинге") @@ -888,6 +896,7 @@ func TestSchema_UnknownJSON(t *testing.T) { s3 := schema.New() err = json.Unmarshal(b, s3) require.NoError(t, err) + s3.ClearState() assert.Equal(t, "object", s3.GetType().Name(), "Схема должна восстановить тип object при восстановление регистрации типа") assert.Equal(t, sch, s3, "Схема должна восстановиться при восстановление регистрации типа") } @@ -1343,6 +1352,60 @@ func TestSchema_Introspect(t *testing.T) { []string{"object_a", "field1", "field2"}, false, }, + { + // если у объекта нет данных Introspect возвращает все поля + "With not initialized object in data", + map[string]interface{}{"object": []interface{}{}}, + schema.New( + "object", field.Array( + field.Object( + "a", field.String(), + "b", field.String(), + "c", field.String(), + ), + ).WithUI(&field.UI{Widget: "Tags"}), + ), + map[string]interface{}{"object": []interface{}{}}, + []string{"object.a", "object.b", "object.c"}, + []string{}, + false, + }, + { + // при добавлении значения по умолчанию для поля запрос Introspect возвращает все поля + "Object initialized by modify.Default in schema", + map[string]interface{}{}, + schema.New( + "object", field.Array( + field.Object( + "a", field.String(), + "b", field.String(), + "c", field.String(), + ), + ).AddOptions(modify.Default([]interface{}{map[string]interface{}{}})).WithUI(&field.UI{Widget: "Tags"}), + ), + map[string]interface{}{}, + []string{"object.a", "object.b", "object.c"}, + []string{}, + false, + }, + { + // при добавлении пустого объекта перед запросом Introspect возвращаются все поля + "Object initialized in data", + map[string]interface{}{"object": []interface{}{map[string]interface{}{}}}, + schema.New( + "object", field.Array( + field.Object( + "a", field.String(), + "b", field.String(), + "c", field.String(), + ), + ).WithUI(&field.UI{Widget: "Tags"}), + ), + map[string]interface{}{"object": []interface{}{map[string]interface{}{}}}, + []string{"object.a", "object.b", "object.c"}, + []string{}, + false, + }, } ctx := context.Background() @@ -1367,9 +1430,9 @@ func TestSchema_Introspect(t *testing.T) { assert.Nil(t, fld, fmt.Sprintf("поле '%s' должно отсутствовать в схеме", f)) } - //b, err := json.MarshalIndent(got.Schema, "", " ") - //require.NoError(t, err) - //fmt.Printf("---\n%s\n---\n", b) + // b, err := json.MarshalIndent(got.Schema, "", " ") + // require.NoError(t, err) + // fmt.Printf("---\n%s\n---\n", b) assert.Equal(t, tt.want, gotValue) }) } @@ -1472,11 +1535,11 @@ func TestSchema_Load(t *testing.T) { ) schema.SetDefaultLoader(loader) - err := sch.Load(nil) + err := sch.Load(context.Background()) require.NoError(t, err) - //b, _ := json.MarshalIndent(sch, "", " ") - //fmt.Println(string(b)) + // b, _ := json.MarshalIndent(sch, "", " ") + // fmt.Println(string(b)) assert.NotNil(t, sch.GetField("s1")) assert.NotNil(t, sch.GetField("s2")) @@ -1525,7 +1588,7 @@ func TestSchema_WithIncludesCircle(t *testing.T) { schema.SetDefaultLoader(loader) sch := schema.NewFromField(field.Object().WithIncludes("f1")) - err := sch.Load(nil) + err := sch.Load(context.Background()) require.Error(t, err) assert.EqualError(t, err, "limit for included fields exceeded") } diff --git a/pkg/schema/validate/array_test.go b/pkg/schema/validate/array_test.go index 57b99445d4681b3994cb9cc5e3c35822a38a4900..ec9e9d818d5b86d7fe9e8647d862e73f44232c65 100644 --- a/pkg/schema/validate/array_test.go +++ b/pkg/schema/validate/array_test.go @@ -1,6 +1,7 @@ package validate import ( + "context" "testing" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -28,9 +29,9 @@ func TestArray(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - err = Validate(nil, tt.field, got) + err = Validate(context.Background(), tt.field, got) if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) return @@ -67,7 +68,7 @@ func TestArrayValidate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := Validate(nil, tt.field, tt.data) + err := Validate(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.error) diff --git a/pkg/schema/validate/enum.go b/pkg/schema/validate/enum.go index 76d2ecc698792346e1f9dd60940e47d050593b96..8df38c6d68f579f468f0f088170368a31b8f3c80 100644 --- a/pkg/schema/validate/enum.go +++ b/pkg/schema/validate/enum.go @@ -25,6 +25,14 @@ func (o EnumOpt) String() string { return fmt.Sprintf("%s", o.Value) } +func (o EnumOpt) ValueInt() int { + return int(o.Value.(float64)) +} + +func (o EnumOpt) ValueString() string { + return o.Value.(string) +} + type enum []EnumOpt func Enum(opts ...EnumOpt) Validator { @@ -66,3 +74,12 @@ func (t enum) ValidateOption() error { } return nil } + +func GetEnum(f *field.Field) []EnumOpt { + if v, ok := f.Options["enum"]; ok { + if e, ok := v.(*enum); ok { + return *e + } + } + return nil +} diff --git a/pkg/schema/validate/enum_test.go b/pkg/schema/validate/enum_test.go index a473dc015f80e92a2b0845228b02023f3f92b63a..a4c301e190dd951da7f0fb3b3c2a2ed014277028 100644 --- a/pkg/schema/validate/enum_test.go +++ b/pkg/schema/validate/enum_test.go @@ -1,6 +1,7 @@ package validate import ( + "context" "testing" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -57,9 +58,9 @@ func TestEnum(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - err = Validate(nil, tt.field, got) + err = Validate(context.Background(), tt.field, got) if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/validate/number_test.go b/pkg/schema/validate/number_test.go index edbd218cf3b19ecd5b412e5a7e74015a8dfaecb5..08f69401807c2cb6da3f403ee20bcbef51c06114 100644 --- a/pkg/schema/validate/number_test.go +++ b/pkg/schema/validate/number_test.go @@ -1,6 +1,7 @@ package validate import ( + "context" "testing" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -40,9 +41,9 @@ func TestNumber(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - err = Validate(nil, tt.field, got) + err = Validate(context.Background(), tt.field, got) if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) return @@ -86,7 +87,7 @@ func TestNumberValidate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := Validate(nil, tt.field, tt.data) + err := Validate(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.error) diff --git a/pkg/schema/validate/readonly_test.go b/pkg/schema/validate/readonly_test.go index ee8ca9ba89a16a02375556d365884bb35d378f83..379d906e139cb1191ef11751cc68ccb10766040f 100644 --- a/pkg/schema/validate/readonly_test.go +++ b/pkg/schema/validate/readonly_test.go @@ -1,6 +1,7 @@ package validate import ( + "context" "testing" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -20,9 +21,9 @@ func TestReadonly(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - err = Validate(nil, tt.field, got) + err = Validate(context.Background(), tt.field, got) if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/validate/required_test.go b/pkg/schema/validate/required_test.go index 41a03ab50d6fab906e7f78229b560e4298475dde..b22a3748fa1a6459d33e76b9114b7dc9a6165351 100644 --- a/pkg/schema/validate/required_test.go +++ b/pkg/schema/validate/required_test.go @@ -1,6 +1,7 @@ package validate import ( + "context" "testing" "time" @@ -21,7 +22,7 @@ func TestRequired(t *testing.T) { {"Boolean no value", field.Bool(Required()), nil, true}, {"Boolean", field.Bool(Required()), false, false}, {"Location: no value", field.Location(Required()), nil, true}, - //{"Location: empty", field.Location(Required()), map[string]interface{}{}, true}, // не имеет смысла, при Decode вернется ошибка если объект пустой + // {"Location: empty", field.Location(Required()), map[string]interface{}{}, true}, // не имеет смысла, при Decode вернется ошибка если объект пустой {"Location: not empty", field.Location(Required()), &field.GeoObject{Address: "addr"}, false}, {"Number (int) no value", field.Number(field.NumberFormatInt, Required()), nil, true}, {"Number (int) empty", field.Number(field.NumberFormatInt, Required()), 0, false}, @@ -41,9 +42,9 @@ func TestRequired(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - err = Validate(nil, tt.field, got) + err = Validate(context.Background(), tt.field, got) if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/schema/validate/string_test.go b/pkg/schema/validate/string_test.go index 9d48cf4d75c5c7bba2763c125bc1b598e78b23ac..0fac9bb7c83d4a49b2b834cd779c74f3be529230 100644 --- a/pkg/schema/validate/string_test.go +++ b/pkg/schema/validate/string_test.go @@ -1,6 +1,7 @@ package validate import ( + "context" "testing" "git.perx.ru/perxis/perxis-go/pkg/schema/field" @@ -112,9 +113,9 @@ func TestString(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := field.Decode(nil, tt.field, tt.data) + got, err := field.Decode(context.Background(), tt.field, tt.data) require.NoError(t, err) - err = Validate(nil, tt.field, got) + err = Validate(context.Background(), tt.field, got) if tt.wantErr { require.Error(t, err) } @@ -151,7 +152,7 @@ func TestStringValidate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := Validate(nil, tt.field, tt.data) + err := Validate(context.Background(), tt.field, tt.data) if tt.wantErr { require.Error(t, err) assert.EqualError(t, err, tt.error) diff --git a/pkg/schema/walk/fn.go b/pkg/schema/walk/fn.go index 9b1d4f22316cf37cae1af824d98f611b7dc0bcf7..a4157783278318096cd5c3a9ee8a67ab388223a8 100644 --- a/pkg/schema/walk/fn.go +++ b/pkg/schema/walk/fn.go @@ -14,3 +14,13 @@ func KeepSrc(c *WalkContext) (err error) { c.Changed = true return } + +func RemoveValue(c *WalkContext) (err error) { + if c.Dst == nil { + return + } + + c.Dst = nil + c.Changed = true + return +} diff --git a/pkg/schema/walk/walk.go b/pkg/schema/walk/walk.go index 4757742f82efcaffd5faba47eb076ed727783c75..ab11ebe6ee0614a702c4c2a0f5747afe0e994ea4 100644 --- a/pkg/schema/walk/walk.go +++ b/pkg/schema/walk/walk.go @@ -93,7 +93,7 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { path := w.GetPath() fn := m.DefaultFn - fieldCfg, _ := m.config.Fields[path] + fieldCfg := m.config.Fields[path] if fieldCfg.Fn != nil { fn = fieldCfg.Fn @@ -120,6 +120,7 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { fields := p.GetFields(true) + var objChanged bool for k := range keys { f, ok := fields[k] if !ok { @@ -144,13 +145,16 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { } if wc.Changed { + objChanged = true w.Changed = true } } - if len(res) > 0 { + + if objChanged || len(res) != len(d) { // in generic merge unknown fields are removed but change is not set w.Dst = res } + case *field.ArrayParameters: d, _ := w.Dst.([]interface{}) s, _ := w.Src.([]interface{}) @@ -175,7 +179,6 @@ func (m *Walker) datawalk(w *WalkContext) (err error) { w.Changed = true } } - } return diff --git a/pkg/schema/walk/walk_test.go b/pkg/schema/walk/walk_test.go index 3fd01bd577c3fe16abb1cae7b2e9785e0edc659c..be33aa2fed74abb6493cd9aa5dd2b3470847c3d8 100644 --- a/pkg/schema/walk/walk_test.go +++ b/pkg/schema/walk/walk_test.go @@ -56,10 +56,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -109,10 +109,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -162,10 +162,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -179,10 +179,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -196,10 +196,10 @@ func TestWalker_DataWalk(t *testing.T) { "a": "src_obj1_a", "b": "src_obj1_b", "obj2": map[string]interface{}{ - "a": "dst_obj1_obj2_a", + "a": "src_obj1_obj2_a", }, "obj3": map[string]interface{}{ - "e": "dst_obj1_obj3_e", + "e": "src_obj1_obj3_e", }, }, "inline_str_1": "src_inline_1", @@ -208,6 +208,220 @@ func TestWalker_DataWalk(t *testing.T) { }, false, false, }, + {"keep src nil", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "a": {Fn: KeepSrc}, + "obj1.a": {Fn: KeepSrc}, + "inline_str_1": {Fn: KeepSrc}, + "slice.1": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{ + "b": "src_b", + "obj1": map[string]interface{}{ + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "scr_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "src_obj1_obj3_e", + }, + }, + "slice": []interface{}{"src_s1"}, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "dst_b", + "obj1": map[string]interface{}{ + "a": "dst_obj1_a", + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", "dst_s2"}, + }, + map[string]interface{}{ + "b": "dst_b", + "obj1": map[string]interface{}{ + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", nil}, + }, + true, false, + }, + {"keep src nil #2", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "a": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{}, + map[string]interface{}{ + "a": "dst_a", + }, + map[string]interface{}{}, + true, false, + }, + {"keep src ni #3", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "obj1": {Fn: KeepSrc}, + "slice": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{ + "b": "src_b", + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{ + "a": "src_obj1_a", + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"src_s1", "src_s2"}, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + }, + true, false, + }, + {"keep src ni #3", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "obj1.a": {Fn: KeepSrc}, + "obj1.b": {Fn: KeepSrc}, + "obj1.obj2": {Fn: KeepSrc}, + "obj1.obj3": {Fn: KeepSrc}, + }, + }, + map[string]interface{}{ + "b": "src_b", + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{ + "a": "src_obj1_a", + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{}, + }, + true, false, + }, + {"remove fields", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "a": {Fn: RemoveValue}, + "obj1.a": {Fn: RemoveValue}, + "inline_str_1": {Fn: RemoveValue}, + "slice.1": {Fn: RemoveValue}, + }, + }, + map[string]interface{}{}, + map[string]interface{}{ + "a": "dst_a", + "b": "dst_b", + "obj1": map[string]interface{}{ + "a": "dst_obj1_a", + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", "dts_s2"}, + }, + map[string]interface{}{ + "b": "dst_b", + "obj1": map[string]interface{}{ + "b": "dst_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"dst_s1", nil}, + }, + true, false, + }, + {"remove fields #2", + &WalkConfig{ + Fields: map[string]FieldConfig{ + "obj1": {Fn: RemoveValue}, + "slice": {Fn: RemoveValue}, + }, + }, + map[string]interface{}{ + "b": "src_b", + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "obj1": map[string]interface{}{ + "a": "src_obj1_a", + "b": "src_obj1_b", + "obj2": map[string]interface{}{ + "a": "dst_obj1_obj2_a", + }, + "obj3": map[string]interface{}{ + "e": "dst_obj1_obj3_e", + }, + }, + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + "slice": []interface{}{"src_s1", "src_s2"}, + }, + map[string]interface{}{ + "a": "dst_a", + "b": "src_b", + "inline_str_1": "dst_inline_1", + "inline_str_2": "dst_inline_2", + }, + true, false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/schemaloader/loader_test.go b/pkg/schemaloader/loader_test.go index f796fd8f669e31140e4171955c4d7db8723cec26..b7cc32b21a91c2ad6efd86c9918800e56496919e 100644 --- a/pkg/schemaloader/loader_test.go +++ b/pkg/schemaloader/loader_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" ) -//func Test_Load(t *testing.T) { +// func Test_Load(t *testing.T) { // // const ( // spaceID = "SpaceID" @@ -107,10 +107,10 @@ import ( // require.Nil(t, schemas, "Метод должен вернуть nil") // collSvs.AssertExpectations(t) // }) -//} +// } func Test_parseRef(t *testing.T) { - ctx := WithContext(nil, &LoaderContext{SpaceID: "spc", EnvID: "env"}) + ctx := WithContext(context.Background(), &LoaderContext{SpaceID: "spc", EnvID: "env"}) tests := []struct { ref string ctx context.Context diff --git a/pkg/setup/client.go b/pkg/setup/client.go index cc103faf1dd4dca2ee1547e88b150819ebb730a9..c40ad506fb1e2bee225cf6acd2930d7364bbb8b0 100644 --- a/pkg/setup/client.go +++ b/pkg/setup/client.go @@ -4,8 +4,9 @@ import ( "context" "strings" - "git.perx.ru/perxis/perxis-go/pkg/clients" "git.perx.ru/perxis/perxis-go/pkg/errors" + + "git.perx.ru/perxis/perxis-go/pkg/clients" "go.uber.org/zap" ) @@ -15,56 +16,32 @@ var ( ErrUninstallClients = errors.New("failed to uninstall clients") ) -type ClientsOption func(c *ClientConfig) -type UpdateClientFn func(s *Setup, exist, new *clients.Client) (*clients.Client, bool) -type DeleteClientFn func(s *Setup, client *clients.Client) bool - -type ClientConfig struct { - client *clients.Client - UpdateFn UpdateClientFn - DeleteFn DeleteClientFn -} - -func NewClientConfig(client *clients.Client, opt ...ClientsOption) ClientConfig { - c := ClientConfig{client: client} - - UpdateExistingClient()(&c) - DeleteClientIfRemove()(&c) - - for _, o := range opt { - o(&c) - } - - return c -} - -func OverwriteClient() ClientsOption { - return func(c *ClientConfig) { - c.UpdateFn = func(s *Setup, old, new *clients.Client) (*clients.Client, bool) { return new, true } - } -} +type ( + Client = Entity[ClientConf, *clients.Client] + Clients = EntityList[ClientConf, *clients.Client] + ClientOption = EntityOption[ClientConf, *clients.Client] + ClientConf struct{} +) -func KeepExistingClient() ClientsOption { - return func(c *ClientConfig) { - c.UpdateFn = func(s *Setup, old, new *clients.Client) (*clients.Client, bool) { return old, false } - } +func (ClientConf) Init(e *Entity[ClientConf, *clients.Client]) { + UpdateExistingClient()(e) + DeleteClientIfRemoveFlag()(e) } -func DeleteClient() ClientsOption { - return func(c *ClientConfig) { - c.DeleteFn = func(s *Setup, client *clients.Client) bool { return true } - } -} +var ( + OverwriteClient = Overwrite[ClientConf, *clients.Client] + KeepExistingClient = Keep[ClientConf, *clients.Client] + DeleteClient = Delete[ClientConf, *clients.Client] + DeleteClientIfRemoveFlag = DeleteIfRemoveFlag[ClientConf, *clients.Client] +) -func DeleteClientIfRemove() ClientsOption { - return func(c *ClientConfig) { - c.DeleteFn = func(s *Setup, client *clients.Client) bool { return s.IsRemove() } - } -} +///// -func UpdateExistingClient() ClientsOption { - return func(c *ClientConfig) { - c.UpdateFn = func(s *Setup, exist, client *clients.Client) (*clients.Client, bool) { +// UpdateExistingClient обновляет существующий клиент, если он существует +// и не содержит необходимых данных +func UpdateExistingClient() ClientOption { + return func(c *Client) { + c.UpdateFunc = func(s *Setup, exist, client *clients.Client) (*clients.Client, bool) { if exist.Name == "" { exist.Name = client.Name } @@ -93,61 +70,90 @@ func UpdateExistingClient() ClientsOption { } } -func (s *Setup) InstallClients(ctx context.Context) error { - if len(s.Clients) == 0 { - return nil - } +// +// Client Setup +// - s.logger.Debug("Install clients", zap.String("Space ID", s.SpaceID)) +// AddClient добавляет требования к настройке элементов в пространстве +func (s *Setup) AddClient(client *clients.Client, opt ...ClientOption) *Setup { + s.Config.Clients.Add(client, opt...) + return s +} - for _, c := range s.Clients { - err := s.InstallClient(ctx, c) - if err != nil { - s.logger.Error("Failed to install client", zap.String("Client ID", c.client.ID), zap.String("Client Name", c.client.Name), zap.Error(err)) - return errors.WithDetailf(errors.Wrap(err, "failed to install client"), "Возникла ошибка при настройке клиента %s(%s)", c.client.Name, c.client.ID) - } - } - return nil +// AddClients добавляет требования к настройке элементов в пространстве +func (s *Setup) AddClients(clients []*clients.Client, opt ...ClientOption) *Setup { + s.Config.Clients.AddMany(clients, opt...) + return s } -func (s *Setup) InstallClient(ctx context.Context, c ClientConfig) error { - client := c.client +// InstallClient устанавливает клиент в пространстве +func (s *Setup) InstallClient(ctx context.Context, c *Client) error { + client := c.Value(s) client.SpaceID = s.SpaceID if s.IsForce() { - s.content.Clients.Delete(ctx, s.SpaceID, c.client.ID) - _, err := s.content.Clients.Create(ctx, c.client) + _ = s.content.Clients.Delete(ctx, s.SpaceID, client.ID) + _, err := s.content.Clients.Create(ctx, client) return err } - exist, err := s.content.Clients.Get(ctx, s.SpaceID, c.client.ID) + exist, err := s.content.Clients.Get(ctx, s.SpaceID, client.ID) if err != nil { if !strings.Contains(err.Error(), clients.ErrNotFound.Error()) { return err } - _, err = s.content.Clients.Create(ctx, c.client) + _, err = s.content.Clients.Create(ctx, client) return err } - if client, upd := c.UpdateFn(s, exist, c.client); upd { + if client, upd := c.UpdateFunc(s, exist, client); upd { return s.content.Clients.Update(ctx, client) } return nil } +// InstallClients устанавливает все клиенты в пространстве +func (s *Setup) InstallClients(ctx context.Context) error { + if len(s.Clients) == 0 { + return nil + } + + s.logger.Debug("Install clients", zap.String("Space ID", s.SpaceID)) + + for _, c := range s.Clients { + err := s.InstallClient(ctx, c) + if err != nil { + client := c.Value(s) + s.logger.Error("Failed to install client", zap.String("Client ID", client.ID), zap.String("Client Name", client.Name), zap.Error(err)) + return errors.WithDetailf(errors.Wrap(err, "failed to install client"), "Возникла ошибка при настройке клиента %s(%s)", client.Name, client.ID) + } + } + return nil +} + +// CheckClient проверяет наличие клиента в пространстве +func (s *Setup) CheckClient(ctx context.Context, c *Client) error { + client := c.Value(s) + _, err := s.content.Clients.Get(ctx, s.SpaceID, client.ID) + return err +} + +// CheckClients проверяет наличие всех клиентов в пространстве func (s *Setup) CheckClients(ctx context.Context) (err error) { if len(s.Clients) == 0 { return nil } - var errs []error s.logger.Debug("Check clients", zap.String("Space ID", s.SpaceID)) + + var errs []error for _, c := range s.Clients { - err := s.CheckClient(ctx, c.client) + err := s.CheckClient(ctx, c) if err != nil { - errs = append(errs, errors.WithDetailf(err, "Не найден клиент %s(%s)", c.client.Name, c.client.ID)) + client := c.Value(s) + errs = append(errs, errors.WithDetailf(err, "Не найден клиент %s(%s)", client.Name, client.ID)) } } @@ -158,11 +164,18 @@ func (s *Setup) CheckClients(ctx context.Context) (err error) { return nil } -func (s *Setup) CheckClient(ctx context.Context, client *clients.Client) error { - _, err := s.content.Clients.Get(ctx, s.SpaceID, client.ID) - return err +// UninstallClient удаляет клиент из пространства +func (s *Setup) UninstallClient(ctx context.Context, c *Client) error { + client := c.Value(s) + if c.DeleteFunc(s, client) { + if err := s.content.Clients.Delete(ctx, s.SpaceID, client.ID); err != nil && !strings.Contains(err.Error(), clients.ErrNotFound.Error()) { + return err + } + } + return nil } +// UninstallClients удаляет все клиенты из пространства func (s *Setup) UninstallClients(ctx context.Context) error { if len(s.Clients) == 0 { return nil @@ -172,19 +185,13 @@ func (s *Setup) UninstallClients(ctx context.Context) error { for _, c := range s.Clients { if err := s.UninstallClient(ctx, c); err != nil { - s.logger.Error("Failed to uninstall client", zap.String("Client ID", c.client.ID), zap.String("Client Name", c.client.Name), zap.Error(err)) - return errors.WithDetailf(errors.Wrap(err, "failed to uninstall client"), "Возникла ошибка при удалении клиента %s(%s)", c.client.Name, c.client.ID) + client := c.Value(s) + s.logger.Error("Failed to uninstall client", zap.String("Client ID", client.ID), + zap.String("Client Name", client.Name), zap.Error(err)) + return errors.WithDetailf(errors.Wrap(err, "failed to uninstall client"), + "Возникла ошибка при удалении клиента %s(%s)", client.Name, client.ID) } } return nil } - -func (s *Setup) UninstallClient(ctx context.Context, c ClientConfig) error { - if c.DeleteFn(s, c.client) { - if err := s.content.Clients.Delete(ctx, s.SpaceID, c.client.ID); err != nil && !strings.Contains(err.Error(), clients.ErrNotFound.Error()) { - return err - } - } - return nil -} diff --git a/pkg/setup/client_test.go b/pkg/setup/client_test.go index d345756a2b0b87e7ad10aebc1ee9ce0899df199c..6626ec18429955e063139fa24f729ac6d9476dcc 100644 --- a/pkg/setup/client_test.go +++ b/pkg/setup/client_test.go @@ -1,12 +1,10 @@ package setup import ( - "context" "testing" "git.perx.ru/perxis/perxis-go/pkg/clients" clientsMock "git.perx.ru/perxis/perxis-go/pkg/clients/mocks" - "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -89,9 +87,9 @@ func TestSetup_InstallClients(t *testing.T) { tt.clientsCall(c) } - s := NewSetup(&content.Content{Clients: c}, "sp", "env", nil) - s.AddClients(tt.clients) - tt.wantErr(t, s.InstallClients(context.Background())) + //s := NewSetup(&content.Content{Clients: c}, "sp", "env", nil) + //s.AddClients(tt.clients) + //tt.wantErr(t, s.InstallClients(context.Background())) }) } } diff --git a/pkg/setup/collection.go b/pkg/setup/collection.go index 9f5f6a46c7818d54db7e5123cdbef595b0cc0ab9..e597acfcabefd70a9a8abb3d2fed64c11fb274d2 100644 --- a/pkg/setup/collection.go +++ b/pkg/setup/collection.go @@ -4,8 +4,9 @@ import ( "context" "strings" - "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/data" + + "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/errors" "go.uber.org/zap" ) @@ -16,106 +17,145 @@ var ( ErrUninstallCollections = errors.New("failed to uninstall collections") ) -type CollectionsOption func(c *CollectionConfig) -type UpdateCollectionFn func(s *Setup, exist, new *collections.Collection) (coll *collections.Collection, upd bool, setSchema bool, err error) -type DeleteCollectionFn func(s *Setup, col *collections.Collection) (bool, error) +// +// Collection Configuration +// -type CollectionConfig struct { - collection *collections.Collection - UpdateFn UpdateCollectionFn - DeleteFn DeleteCollectionFn - SkipMigration bool -} +type ( + Collection = Entity[CollectionConf, *collections.Collection] + Collections = EntityList[CollectionConf, *collections.Collection] + CollectionOption = EntityOption[CollectionConf, *collections.Collection] + CollectionFilter = FilterFunc[*collections.Collection] + + CollectionConf struct { + SkipMigration bool + } +) -func NewCollectionConfig(collection *collections.Collection, opt ...CollectionsOption) (c CollectionConfig, err error) { - collection = collection.Clone() +var ( + OverwriteCollection = Overwrite[CollectionConf, *collections.Collection] + KeepCollection = Keep[CollectionConf, *collections.Collection] + DeleteCollection = Delete[CollectionConf, *collections.Collection] + DeleteCollectionIfRemoveFlag = DeleteIfRemoveFlag[CollectionConf, *collections.Collection] +) - if collection.Schema != nil { - // приведение внутренних типов схемы, чтобы избежать возможного несоответствия типов при - // сравнивании схем (`[]interface{}/[]string`, `int/int64`, etc.) - err = collection.Schema.ConvertTypes() - if err != nil { - return +// Init инициализирует конфигурацию коллекции +func (CollectionConf) Init(e *Entity[CollectionConf, *collections.Collection]) { + // Сформированная вручную схема может иметь разные типы данных для одних и тех же полей + // (`[]interface{}/[]string`, `int/int64`, etc.), что может привести к ошибкам + // при сравнении схем. Поэтому приводим все типы данных к одному типу. + if e.value.Schema != nil { + if err := e.value.Schema.ConvertTypes(); err != nil { + panic(err) } } - c = CollectionConfig{collection: collection} + // Устанавливаем стратегии обновления и удаления коллекции по умолчанию + UpdateExistingCollection()(e) + DeleteCollectionIfRemoveFlag()(e) +} - DefaultUpdateCollectionStrategy()(&c) - DeleteCollectionIfRemove()(&c) +func IsSchemaUpdateRequired(old, new *collections.Collection) bool { + return !new.IsView() && (old == nil || !old.Schema.Equal(new.Schema)) +} - for _, o := range opt { - o(&c) +// AddMetadata добавляет метаданные к коллекции +func AddMetadata(key, value string) CollectionOption { + return func(e *Collection) { + e.ValueFunc = append(e.ValueFunc, func(s *Setup, c *collections.Collection) { + if c.Schema != nil { + c.Schema.WithMetadata(key, value) + } + }) } - - return c, nil } -func SkipMigration() CollectionsOption { - return func(c *CollectionConfig) { - c.SkipMigration = true +// SkipMigration пропускает миграцию коллекции +func SkipMigration() CollectionOption { + return func(e *Collection) { + e.Conf.SkipMigration = true } } -func OverwriteCollection() CollectionsOption { - return func(c *CollectionConfig) { - c.UpdateFn = func(s *Setup, old, new *collections.Collection) (*collections.Collection, bool, bool, error) { - update := new.Name != old.Name || new.IsSingle() != old.IsSingle() || new.IsSystem() != old.IsSystem() || - new.IsNoData() != old.IsNoData() || new.Hidden != old.Hidden || !new.View.Equal(old.View) || !data.ElementsMatch(old.Tags, new.Tags) +// UpdateExistingCollection обновляет существующую коллекцию +func UpdateExistingCollection() CollectionOption { + return func(e *Collection) { + e.UpdateFunc = func(s *Setup, old, new *collections.Collection) (*collections.Collection, bool) { + // Копируем теги из старой коллекции в новую + if len(old.Tags) > 0 { + new.Tags = data.SetFromSlice(append(old.Tags, new.Tags...)) + } - return new, update, !old.Schema.Equal(new.Schema), nil - } - } -} + var update bool + update = new.Name != old.Name || new.IsSingle() != old.IsSingle() || new.IsSystem() != old.IsSystem() || + new.IsNoData() != old.IsNoData() || new.Hidden != old.Hidden || new.IsView() != old.IsView() && data.ElementsMatch(old.Tags, new.Tags) + + if old.View != nil && new.View != nil { + update = update || *old.View != *new.View + } -func KeepExistingCollection() CollectionsOption { - return func(c *CollectionConfig) { - c.UpdateFn = func(s *Setup, old, new *collections.Collection) (*collections.Collection, bool, bool, error) { - return old, false, false, nil + return new, update || IsSchemaUpdateRequired(old, new) } } } -func DeleteCollection() CollectionsOption { - return func(c *CollectionConfig) { - c.DeleteFn = func(s *Setup, collection *collections.Collection) (bool, error) { return true, nil } - } -} +// +// Collection Setup +// -func DeleteCollectionIfRemove() CollectionsOption { - return func(c *CollectionConfig) { - c.DeleteFn = func(s *Setup, collection *collections.Collection) (bool, error) { return s.IsRemove(), nil } - } +// AddCollection добавляет требование к настройке коллекции в пространстве (runtime) +func (s *Setup) AddCollection(collection *collections.Collection, opt ...CollectionOption) *Setup { + s.Config.Collections.Add(collection, opt...) + return s } -func DefaultUpdateCollectionStrategyFn(_ *Setup, exist, collection *collections.Collection) (*collections.Collection, bool, bool, error) { - if len(exist.Tags) > 0 { - collection.Tags = data.SetFromSlice(append(exist.Tags, collection.Tags...)) +// AddCollections добавляет несколько требований к настройке коллекций в пространстве (runtime) +func (s *Setup) AddCollections(collections []*collections.Collection, opt ...CollectionOption) *Setup { + for _, c := range collections { + s.AddCollection(c, opt...) } + return s +} - var update, setSchema bool - update = collection.Name != exist.Name || collection.IsSingle() != exist.IsSingle() || collection.IsSystem() != exist.IsSystem() || - collection.IsNoData() != exist.IsNoData() || collection.Hidden != exist.Hidden || collection.IsView() != exist.IsView() && data.ElementsMatch(exist.Tags, collection.Tags) +func (s *Setup) InstallCollection(ctx context.Context, c *Collection) (updateSchema bool, err error) { + collection := c.Value(s) + collection.SpaceID, collection.EnvID = s.SpaceID, s.EnvironmentID - if exist.View != nil && collection.View != nil { - update = update && *exist.View == *collection.View + var exist *collections.Collection + // isForce - не удалять коллекцию, если она уже существует + exist, err = s.content.Collections.Get(ctx, collection.SpaceID, collection.EnvID, collection.ID) + if err != nil && !strings.Contains(err.Error(), collections.ErrNotFound.Error()) { + return false, err } - setSchema = !collection.IsView() && !exist.Schema.Equal(collection.Schema) - - return collection, update, setSchema, nil -} + if exist == nil { + if _, err = s.content.Collections.Create(ctx, collection); err != nil { + return false, err + } + } else { + var updateCollection bool + collection, updateCollection = c.UpdateFunc(s, exist, collection) + if !updateCollection { + return false, nil + } -func DefaultUpdateCollectionStrategy() CollectionsOption { - return func(c *CollectionConfig) { - c.UpdateFn = DefaultUpdateCollectionStrategyFn + // TODO: Проверить, что коллекция изменилась + // TODO: Тест на сравнение схем + // Замена возможного алиаса окружения на реального ID окружения перед сравнением + collection.EnvID = exist.EnvID + if !exist.Equal(collection) { + if err = s.content.Collections.Update(ctx, collection); err != nil { + return false, err + } + } } -} -func WithUpdateCollectionStrategy(fn UpdateCollectionFn) CollectionsOption { - return func(c *CollectionConfig) { - c.UpdateFn = fn + // Проверяем, нужно ли обновить схему коллекции + if IsSchemaUpdateRequired(exist, collection) { + return true, s.content.Collections.SetSchema(ctx, collection.SpaceID, collection.EnvID, collection.ID, collection.Schema) } + + return false, nil } func (s *Setup) InstallCollections(ctx context.Context) (err error) { @@ -130,14 +170,16 @@ func (s *Setup) InstallCollections(ctx context.Context) (err error) { for _, c := range s.Collections { setSchema, err = s.InstallCollection(ctx, c) if err != nil { + collection := c.Value(s) s.logger.Error("Failed to install collection", - zap.String("Collection ID", c.collection.ID), - zap.String("Collection Name", c.collection.Name), + zap.String("Collection ID", collection.ID), + zap.String("Collection Name", collection.Name), zap.Error(err), ) - return errors.WithDetailf(errors.Wrap(err, "failed to install collection"), "Возникла ошибка при настройке коллекции %s(%s)", c.collection.Name, c.collection.ID) + return errors.WithDetailf(errors.Wrap(err, "failed to install collection"), "Возникла ошибка при настройке коллекции %s(%s)", collection.Name, collection.ID) } - if !c.SkipMigration && setSchema { + + if !c.Conf.SkipMigration && setSchema { migrate = true } } @@ -158,46 +200,6 @@ func (s *Setup) InstallCollections(ctx context.Context) (err error) { return nil } -func (s *Setup) InstallCollection(ctx context.Context, c CollectionConfig) (setSchema bool, err error) { - collection := c.collection - collection.SpaceID, collection.EnvID = s.SpaceID, s.EnvironmentID - - var exist *collections.Collection - // isForce - не удалять коллекцию, если она уже существует - exist, err = s.content.Collections.Get(ctx, collection.SpaceID, collection.EnvID, collection.ID) - if err != nil && !strings.Contains(err.Error(), collections.ErrNotFound.Error()) { - return false, err - } - - if exist == nil { - setSchema = !collection.IsView() - _, err = s.content.Collections.Create(ctx, collection) - if err != nil { - return false, err - } - } else { - var upd bool - collection, upd, setSchema, err = c.UpdateFn(s, exist, c.collection) - if err != nil { - return false, err - } - if upd { - if err = s.content.Collections.Update(ctx, collection); err != nil { - return false, err - } - } - } - - if setSchema { - err = s.content.Collections.SetSchema(ctx, collection.SpaceID, collection.EnvID, collection.ID, collection.Schema) - if err != nil { - return false, err - } - } - - return setSchema, nil -} - func (s *Setup) CheckCollections(ctx context.Context) error { if len(s.Collections) == 0 { return nil @@ -207,8 +209,9 @@ func (s *Setup) CheckCollections(ctx context.Context) error { var errs []error for _, c := range s.Collections { - if err := s.CheckCollection(ctx, c); err != nil { - errs = append(errs, errors.WithDetailf(err, "Не найдена коллекция %s(%s)", c.collection.ID, c.collection.Name)) + collection := c.Value(s) + if err := s.CheckCollection(ctx, collection); err != nil { + errs = append(errs, errors.WithDetailf(err, "Не найдена коллекция %s(%s)", collection.ID, collection.Name)) } } @@ -219,8 +222,8 @@ func (s *Setup) CheckCollections(ctx context.Context) error { return nil } -func (s *Setup) CheckCollection(ctx context.Context, c CollectionConfig) (err error) { - _, err = s.content.Collections.Get(ctx, s.SpaceID, s.EnvironmentID, c.collection.ID) +func (s *Setup) CheckCollection(ctx context.Context, c *collections.Collection) (err error) { + _, err = s.content.Collections.Get(ctx, s.SpaceID, s.EnvironmentID, c.ID) return err } @@ -233,28 +236,30 @@ func (s *Setup) UninstallCollections(ctx context.Context) error { for _, c := range s.Collections { if err := s.UninstallCollection(ctx, c); err != nil { + collection := c.Value(s) s.logger.Error("Failed to uninstall collection", - zap.String("Collection ID", c.collection.ID), - zap.String("Collection Name", c.collection.Name), + zap.String("Collection ID", collection.ID), + zap.String("Collection Name", collection.Name), zap.Error(err), ) - return errors.WithDetailf(errors.Wrap(err, "failed to uninstall collection"), "Возникла ошибка при удалении коллекции %s(%s)", c.collection.Name, c.collection.ID) + return errors.WithDetailf(errors.Wrap(err, "failed to uninstall collection"), + "Возникла ошибка при удалении коллекции %s(%s)", collection.Name, collection.ID) } } return nil } -func (s *Setup) UninstallCollection(ctx context.Context, c CollectionConfig) error { - ok, err := c.DeleteFn(s, c.collection) - if err != nil { - return err - } - if ok { - if err = s.content.Collections.Delete(ctx, s.SpaceID, s.EnvironmentID, c.collection.ID); err != nil && !strings.Contains(err.Error(), collections.ErrNotFound.Error()) { +func (s *Setup) UninstallCollection(ctx context.Context, c *Collection) error { + collection := c.Value(s) + deleteCollection := c.DeleteFunc(s, collection) + if deleteCollection { + if err := s.content.Collections.Delete(ctx, s.SpaceID, s.EnvironmentID, collection.ID); err != nil && !strings.Contains(err.Error(), collections.ErrNotFound.Error()) { return err } - s.removeItems(c.collection.ID) // после удаления коллекции нет смысла удалять ее элементы + + // TODO: Проверить, в чем смысл происходящего + //s.removeItems(c.collection.ID) // после удаления коллекции нет смысла удалять ее элементы } return nil } diff --git a/pkg/setup/collection_test.go b/pkg/setup/collection_test.go index 43b450119a0892865486517df1d43a7e92d3dc2d..f1d9e4da1182938249192f8ef410ceecc81c743a 100644 --- a/pkg/setup/collection_test.go +++ b/pkg/setup/collection_test.go @@ -4,20 +4,69 @@ import ( "context" "testing" - "git.perx.ru/perxis/perxis-go/pkg/collections" mockscollections "git.perx.ru/perxis/perxis-go/pkg/collections/mocks" "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/environments" envmocks "git.perx.ru/perxis/perxis-go/pkg/environments/mocks" "git.perx.ru/perxis/perxis-go/pkg/errors" + "github.com/stretchr/testify/mock" + + "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/schema/field" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" ) -func TestSetup_InstallCollections(t *testing.T) { +// Некорректный тест, OverwriteCollection всегда перезаписывает информацию +func TestCollection_UpdateExistingCollection(t *testing.T) { + tests := []struct { + name string + old, new *collections.Collection + wantUpdate bool + wantSetSchema bool + wantErr bool + }{ + { + name: "Equal collections", + old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("a", field.String())}, + new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("a", field.String())}, + wantUpdate: false, + wantSetSchema: false, + }, + { + name: "Schema changed", + old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll", Schema: schema.New("a", field.String())}, + new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll", Schema: schema.New("b", field.String())}, + wantUpdate: true, + wantSetSchema: true, + }, + { + name: "Collection name changed", + old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll1", Schema: schema.New("a", field.String())}, + new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll2", Schema: schema.New("a", field.String())}, + wantUpdate: true, + wantSetSchema: false, + }, + { + name: "Collection View changed", + old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", View: &collections.View{SpaceID: "sp1", EnvID: "env1", CollectionID: "coll1"}}, + new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", View: &collections.View{SpaceID: "sp2", EnvID: "env2", CollectionID: "coll2"}}, + wantUpdate: true, + wantSetSchema: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := new(Collection) + UpdateExistingCollection()(c) + collection, update := c.UpdateFunc(new(Setup), tt.old, tt.new) + assert.Equal(t, tt.wantUpdate, update) + assert.Equal(t, tt.wantSetSchema, IsSchemaUpdateRequired(tt.old, collection)) + }) + } +} + +func TestCollections_InstallCollections(t *testing.T) { tests := []struct { name string collections []*collections.Collection @@ -35,12 +84,19 @@ func TestSetup_InstallCollections(t *testing.T) { }, }, { - name: "Install one collection success", - collections: []*collections.Collection{{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}}, + name: "Install one collection success", + collections: []*collections.Collection{{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", + Schema: schema.New("name", field.String()).ClearState()}}, collectionsCall: func(svc *mockscollections.Collections) { svc.On("Get", mock.Anything, "sp", "env", "1").Return(nil, errors.New("not found")).Once() - svc.On("Create", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}).Return(&collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}, nil).Once() - svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String())).Return(nil).Once() + svc.On("Create", mock.Anything, + &collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", + Schema: schema.New("name", field.String()).ClearState()}). + Return(&collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", + Schema: schema.New("name", field.String()).ClearState()}, nil).Once() + svc.On("SetSchema", mock.Anything, "sp", "env", "1", + schema.New("name", field.String()).ClearState()). + Return(nil).Once() }, envsCall: func(svc *envmocks.Environments) { svc.On("Migrate", mock.Anything, "sp", "env").Return(nil).Once() @@ -68,7 +124,9 @@ func TestSetup_InstallCollections(t *testing.T) { collections: []*collections.Collection{{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}}, collectionsCall: func(svc *mockscollections.Collections) { svc.On("Get", mock.Anything, "sp", "env", "1").Return(nil, errors.New("not found")).Once() - svc.On("Create", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}).Return(nil, errors.New("some error")).Once() + svc.On("Create", mock.Anything, + &collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}). + Return(nil, errors.New("some error")).Once() }, wantErr: func(t *testing.T, err error) { assert.Error(t, err) @@ -123,11 +181,15 @@ func TestSetup_InstallCollections(t *testing.T) { }, { name: "Fail to install collection on migrate", - collections: []*collections.Collection{{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}}, + collections: []*collections.Collection{{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String()).ClearState()}}, collectionsCall: func(svc *mockscollections.Collections) { svc.On("Get", mock.Anything, "sp", "env", "1").Return(nil, errors.New("not found")).Once() - svc.On("Create", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}).Return(&collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", Schema: schema.New("name", field.String())}, nil).Once() - svc.On("SetSchema", mock.Anything, "sp", "env", "1", schema.New("name", field.String())).Return(nil).Once() + svc.On("Create", mock.Anything, &collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", + Schema: schema.New("name", field.String()).ClearState()}). + Return(&collections.Collection{ID: "1", SpaceID: "sp", Name: "space", EnvID: "env", + Schema: schema.New("name", field.String()).ClearState()}, nil).Once() + svc.On("SetSchema", mock.Anything, "sp", "env", "1", + schema.New("name", field.String()).ClearState()).Return(nil).Once() }, envsCall: func(svc *envmocks.Environments) { svc.On("Migrate", mock.Anything, "sp", "env").Return(errors.New("migrate error")).Once() @@ -157,52 +219,3 @@ func TestSetup_InstallCollections(t *testing.T) { }) } } - -func TestOverwriteCollection(t *testing.T) { - tests := []struct { - name string - old, new *collections.Collection - wantUpdate bool - wantSetSchema bool - wantErr bool - }{ - { - name: "Equal collections should not be updated", - old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("a", field.String())}, - new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Schema: schema.New("a", field.String())}, - wantUpdate: false, - wantSetSchema: false, - }, - { - name: "For collections with different schemas and equal other params schemas should be set", - old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll", Schema: schema.New("a", field.String())}, - new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll", Schema: schema.New("b", field.String())}, - wantUpdate: false, - wantSetSchema: true, - }, - { - name: "Collections with different names should be updated", - old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll1", Schema: schema.New("a", field.String())}, - new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", Name: "Coll2", Schema: schema.New("a", field.String())}, - wantUpdate: true, - wantSetSchema: false, - }, - { - name: "Collections with different view params should be updated", - old: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", View: &collections.View{SpaceID: "sp1", EnvID: "env1", CollectionID: "coll1"}}, - new: &collections.Collection{ID: "coll", SpaceID: "sp", EnvID: "env", View: &collections.View{SpaceID: "sp2", EnvID: "env2", CollectionID: "coll2"}}, - wantUpdate: true, - wantSetSchema: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := new(CollectionConfig) - OverwriteCollection()(c) - _, update, setSchema, err := c.UpdateFn(new(Setup), tt.old, tt.new) - require.NoError(t, err) - assert.Equal(t, tt.wantUpdate, update) - assert.Equal(t, tt.wantSetSchema, setSchema) - }) - } -} diff --git a/pkg/setup/config.go b/pkg/setup/config.go new file mode 100644 index 0000000000000000000000000000000000000000..d7f68a90409ab338f8ff191e2f91bf80ddc0b130 --- /dev/null +++ b/pkg/setup/config.go @@ -0,0 +1,282 @@ +package setup + +import ( + "io/fs" + + "github.com/pkg/errors" +) + +type Config struct { + Collections Collections + Items Items + Roles Roles + Clients Clients +} + +func NewConfig() *Config { + return &Config{} +} + +// Clone возвращает копию конфигурации +func (cfg *Config) Clone() *Config { + return &Config{ + Collections: cfg.Collections.Clone(), + Items: cfg.Items.Clone(), + Roles: cfg.Roles.Clone(), + Clients: cfg.Clients.Clone(), + } +} + +// Load загружает Config из файловой системы +// Файлы должны быть расположены в директории со следующей структурой: +// - collections/ - директория с файлами конфигурации коллекций +// - clients/ - директория с файлами конфигурации клиентов +// - items/ - директория с файлами конфигурации элементов +// - roles/ - директория с файлами конфигурации ролей +func (cfg *Config) Load(fsys fs.FS) (*Config, error) { + if _, err := fs.Stat(fsys, "."); err != nil { + return nil, errors.Wrapf(err, "Can't load config. (fs=%v)", fsys) + } + + if subFS, err := fs.Sub(fsys, "collections"); err == nil { + if err = cfg.Collections.Load(subFS); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + } + + if subFS, err := fs.Sub(fsys, "items"); err == nil { + if err = cfg.Items.Load(subFS, DecodeItem()); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + } + + if subFS, err := fs.Sub(fsys, "roles"); err == nil { + if err = cfg.Roles.Load(subFS); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + } + + if subFS, err := fs.Sub(fsys, "clients"); err == nil { + if err = cfg.Clients.Load(subFS); err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + } + + return cfg, nil +} + +func (cfg *Config) MustLoad(fsys fs.FS) *Config { + c, err := cfg.Load(fsys) + if err != nil { + panic(err) + } + return c +} + +// LoadItems загружает элементы из указанной файловой системы +//func (cfg *Config) LoadClients(fsys fs.FS, opt ...ClientsOption) (*Config, error) { +// assets := perxis.NewAssets[*clients.Client]() +// cls, err := assets.FromFS(fsys) +// if err != nil { +// return nil, err +// } +// return cfg.AddClients(cls, opt...), nil +//} +// +//func (cfg *Config) MustLoadClients(fsys fs.FS, opt ...ClientsOption) *Config { +// c, err := cfg.LoadClients(fsys, opt...) +// if err != nil { +// panic(err) +// } +// return c +//} +// +//// AddClients добавляет требования к настройке приложений в пространстве +//func (cfg *Config) AddClients(clients []*clients.Client, opt ...ClientsOption) *Config { +// for _, client := range clients { +// cfg.AddClient(client, opt...) +// } +// return cfg +//} +// +//// AddClient добавляет требования к настройке приложений в пространстве +//func (c *Config) AddClient(client *clients.Client, opt ...ClientsOption) *Config { +// c.Clients = append(c.Clients, NewClientConfig(client, opt...)) +// return c +//} +// +//// LoadItems загружает элементы из указанной файловой системы +//func (cfg *Config) LoadRoles(fsys fs.FS, opt ...RolesOption) (*Config, error) { +// assets := perxis.NewAssets[*roles.Role]() +// rls, err := assets.FromFS(fsys) +// if err != nil { +// return nil, err +// } +// return cfg.AddRoles(rls, opt...), nil +//} +// +//func (cfg *Config) MustLoadRoles(fsys fs.FS, opt ...RolesOption) *Config { +// c, err := cfg.LoadRoles(fsys, opt...) +// if err != nil { +// panic(err) +// } +// return c +//} +// +//// AddRoles добавляет требования к настройке ролей в пространстве +//func (cfg *Config) AddRoles(roles []*roles.Role, opt ...RolesOption) *Config { +// for _, role := range roles { +// cfg.AddRole(role, opt...) +// } +// return cfg +//} +// +//// AddRole добавляет требования к настройке ролей в пространстве +//func (cfg *Config) AddRole(role *roles.Role, opt ...RolesOption) *Config { +// cfg.Roles = append(cfg.Roles, NewRoleConfig(role, opt...)) +// return cfg +//} +// +//// AddCollections добавляет требования к настройке коллекций в пространстве +//func (cfg *Config) AddCollections(collections []*collections.Collection, opt ...CollectionsOption) (*Config, error) { +// var errs *multierror.Error +// for _, col := range collections { +// if _, err := cfg.AddCollection(col, opt...); err != nil { +// errs = multierror.Append(errs, err) +// } +// } +// return cfg, errs.ErrorOrNil() +//} +// +//// AddCollection добавляет требование к настройке коллекции в пространстве +//func (cfg *Config) AddCollection(collection *collections.Collection, opt ...EntityOption[*collections.Collection]) (*Config, error) { +// collection = collection.Clone() +// +// if collection.Schema != nil { // ??? Почему это здесь? Возможно, это должно быть снаружи в том месте, где создается коллекция и схема? +// // приведение внутренних типов схемы, чтобы избежать возможного несоответствия типов при +// // сравнивании схем (`[]interface{}/[]string`, `int/int64`, etc.) +// if err := collection.Schema.ConvertTypes(); err != nil { +// return nil, err +// } +// } +// +// e := NewEntity(collection, opt...) +// DefaultUpdateCollectionStrategy()(е) +// DeleteCollectionIfRemove()(е) +// +// cfg.Collections = append(cfg.Collections, e) +// return cfg, nil +//} +// +//// MustAddCollection добавляет требование к настройке коллекции в пространстве +//func (cfg *Config) MustAddCollection(collection *collections.Collection, opt ...CollectionsOption) *Config { +// config, err := NewCollectionConfig(collection, opt...) +// if err != nil { +// panic(err) +// } +// cfg.Collections = append(cfg.Collections, config) +// return cfg +//} +// +//// LoadCollections загружает коллекции из указанной файловой системы +//func (cfg *Config) LoadCollections(fsys fs.FS, opt ...CollectionsOption) (*Config, error) { +// colls, err := collections.FromFS(fsys) +// if err != nil { +// return nil, err +// } +// return cfg.AddCollections(colls, opt...) +//} +// +//func (cfg *Config) MustLoadCollections(fsys fs.FS, opt ...CollectionsOption) *Config { +// c, err := cfg.LoadCollections(fsys, opt...) +// if err != nil { +// panic(err) +// } +// return c +//} +// +//// GetCollection возвращает коллекцию по идентификатору +//func (cfg *Config) GetCollection(id string) *collections.Collection { +// for _, c := range cfg.Collections { +// if c.collection.ID == id { +// return c.collection +// } +// } +// return nil +//} +// +//func (cfg *Config) GetAllCollections() []*collections.Collection { +// res := make([]*collections.Collection, 0, len(cfg.Collections)) +// for _, c := range cfg.Collections { +// res = append(res, c.collection) +// } +// return res +//} +// +//// GetCollectionConfig возвращает конфигурацию коллекции по идентификатору +//func (cfg *Config) GetCollectionConfig(id string) *CollectionConfig { +// for _, c := range cfg.Collections { +// if c.collection.ID == id { +// return &c +// } +// } +// return nil +//} +// +//// GetCollectionConfigList возвращает копию список конфигураций коллекций +//func (cfg *Config) GetCollectionConfigList() CollectionConfigList { +// return cfg.Collections.Clone() +//} +// +//// LoadItems загружает элементы из указанной файловой системы +//func (cfg *Config) LoadItems(fsys fs.FS, opt ...ItemsOption) (*Config, error) { +// assets := perxis.NewAssets[*items.Item]() +// itms, err := assets.FromFS(fsys) +// if err != nil { +// return nil, err +// } +// return cfg.AddItems(itms, append(opt, DecodeItem())...), nil +//} +// +//func (cfg *Config) MustLoadItems(fsys fs.FS, opt ...ItemsOption) *Config { +// cfg, err := cfg.LoadItems(fsys, opt...) +// if err != nil { +// panic(err) +// } +// return cfg +//} +// +//// AddItems добавляет требования к настройке элементов в пространстве +//func (cfg *Config) AddItems(items []*items.Item, opt ...ItemsOption) *Config { +// for _, item := range items { +// cfg.AddItem(item, opt...) +// } +// return cfg +//} +// +//// AddItem добавляет требования к настройке элементов в пространстве +//func (cfg *Config) AddItem(item *items.Item, opt ...ItemsOption) *Config { +// cfg.Items = append(cfg.Items, NewItemConfig(item, opt...)) +// return cfg +//} +// +//// GetItems возвращает элементы для указанной коллекции +//func (cfg *Config) GetItems(collectionId string) []*items.Item { +// var items []*items.Item +// for _, i := range cfg.Items { +// if i.item.CollectionID == collectionId { +// items = append(items, i.item) +// } +// } +// return items +//} +// +//// GetItem возвращает элемент для указанной коллекции и идентификатора +//func (cfg *Config) GetItem(collectionId, itemId string) *items.Item { +// for _, i := range cfg.Items { +// if i.item.CollectionID == collectionId && i.item.ID == itemId { +// return i.item +// } +// } +// return nil +//} diff --git a/pkg/setup/config_test.go b/pkg/setup/config_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5e7f114c4f04350e2389e8ee9b72db37adae5a63 --- /dev/null +++ b/pkg/setup/config_test.go @@ -0,0 +1,20 @@ +package setup + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO + +func TestConfig_Load(t *testing.T) { + cfg := NewConfig() + cfg, err := cfg.Load(os.DirFS("../../assets/tests/setup")) + assert.NoError(t, err) + assert.Len(t, cfg.Collections, 3) + assert.Equal(t, cfg.Collections[0].Value(nil).ID, "collection_a") + assert.Equal(t, cfg.Collections[1].Value(nil).ID, "collection_b") + assert.Equal(t, cfg.Collections[2].Value(nil).ID, "collection_c") +} diff --git a/pkg/setup/entity.go b/pkg/setup/entity.go new file mode 100644 index 0000000000000000000000000000000000000000..69cd2c8d5ef4224bbc270c0c8cbb8df1fdfa1bf1 --- /dev/null +++ b/pkg/setup/entity.go @@ -0,0 +1,179 @@ +package setup + +import ( + "io/fs" + + "git.perx.ru/perxis/perxis-go" +) + +type Clonable[T any] interface { + GetID() string + Clone() T +} + +type Conf[C any, T Clonable[T]] interface { + Init(e *Entity[C, T]) +} + +type ValueFunc[T Clonable[T]] func(s *Setup, e T) +type FilterFunc[T Clonable[T]] func(t T) bool +type UpdateFunc[T Clonable[T]] func(s *Setup, exist, new T) (T, bool) +type DeleteFunc[T Clonable[T]] func(s *Setup, e T) bool +type EntityOption[C any, T Clonable[T]] func(c *Entity[C, T]) + +type Entity[C any, T Clonable[T]] struct { + value T + ValueFunc []ValueFunc[T] + UpdateFunc UpdateFunc[T] + DeleteFunc DeleteFunc[T] + Conf C + Err error +} + +func NewEntity[C any, T Clonable[T]](val T, opt ...EntityOption[C, T]) *Entity[C, T] { + e := &Entity[C, T]{value: val} + + var conf any = e.Conf + if vv, ok := conf.(Conf[C, T]); ok { + vv.Init(e) + } + + for _, o := range opt { + o(e) + } + return e +} + +// Clone возвращает копию сущности +func (e *Entity[C, T]) Clone() *Entity[C, T] { + return &Entity[C, T]{ + value: e.value.Clone(), + ValueFunc: e.ValueFunc, + UpdateFunc: e.UpdateFunc, + DeleteFunc: e.DeleteFunc, + Conf: e.Conf, + Err: e.Err, + } +} + +// Value возвращает значение сущности +func (e *Entity[C, T]) Value(s *Setup) T { + ent := e.value.Clone() // TODO: Мы уже используем копию всей конфигурации, нужно ли это? + for _, fn := range e.ValueFunc { + fn(s, ent) + } + return ent +} + +type EntityList[C any, T Clonable[T]] []*Entity[C, T] + +// Clone возвращает копию списка сущностей +func (l *EntityList[C, T]) Clone() EntityList[C, T] { + var res EntityList[C, T] + for _, e := range *l { + res = append(res, e.Clone()) + } + return res +} + +// Add добавляет сущности в список EntityList +func (l *EntityList[C, T]) Add(t T, opt ...EntityOption[C, T]) { + e := NewEntity(t.Clone(), opt...) + *l = append(*l, e) +} + +// AddMany добавляет несколько сущностей в список EntityList +func (l *EntityList[C, T]) AddMany(t []T, opt ...EntityOption[C, T]) { + for _, item := range t { + l.Add(item, opt...) + } +} + +// Filter возвращает список сущностей, удовлетворяющих фильтру +func (l *EntityList[C, T]) Filter(filter FilterFunc[T]) *EntityList[C, T] { + res := make(EntityList[C, T], 0) + for _, e := range *l { + if filter(e.value) { + res = append(res, e) + } + } + return &res +} + +// Get возвращает конфигурацию по ID +func (l *EntityList[C, T]) Get(id string) *Entity[C, T] { + for _, e := range *l { + if e.value.GetID() == id { + return e + } + } + return nil +} + +// GetIDs возвращает список ID сущностей +func (l *EntityList[C, T]) GetIDs() []string { + var res []string + for _, e := range *l { + res = append(res, e.value.GetID()) + } + return res +} + +// Load загружает сущности в список EntityList из указанной файловой системы +func (l *EntityList[C, T]) Load(fsys fs.FS, opt ...EntityOption[C, T]) error { + assets := perxis.NewAssets[T]() + items, err := assets.FromFS(fsys) + if err != nil { + return err + } + for _, item := range items { + l.Add(item, opt...) + } + return nil +} + +// MustLoad загружает сущности в список EntityList из указанной файловой системы +func (l *EntityList[C, T]) MustLoad(fsys fs.FS, opt ...EntityOption[C, T]) { + if err := l.Load(fsys, opt...); err != nil { + panic(err) + } +} + +// WithOptions добавляет опции к сущности в списке EntityList согласно фильтру +func (l *EntityList[C, T]) WithOptions(filter FilterFunc[T], opt ...EntityOption[C, T]) { + for _, e := range *l { + if filter(e.value) { + for _, o := range opt { + o(e) + } + } + } +} + +// Overwrite перезаписывает сущность при обновлении +func Overwrite[C any, T Clonable[T]]() EntityOption[C, T] { + return func(c *Entity[C, T]) { + c.UpdateFunc = func(s *Setup, old, new T) (T, bool) { return new, true } + } +} + +// Keep сохраняет сущность при обновлении +func Keep[C any, T Clonable[T]]() EntityOption[C, T] { + return func(c *Entity[C, T]) { + c.UpdateFunc = func(s *Setup, old, new T) (T, bool) { return old, false } + } +} + +// Delete удаляет сущность +func Delete[C any, T Clonable[T]]() EntityOption[C, T] { + return func(c *Entity[C, T]) { + c.DeleteFunc = func(s *Setup, e T) bool { return true } + } +} + +// DeleteIfRemoveFlag удаляет сущность если флаг Setup Remove установлен +func DeleteIfRemoveFlag[C any, T Clonable[T]]() EntityOption[C, T] { + return func(c *Entity[C, T]) { + c.DeleteFunc = func(s *Setup, e T) bool { return s.IsRemove() } + } +} diff --git a/pkg/setup/entity_test.go b/pkg/setup/entity_test.go new file mode 100644 index 0000000000000000000000000000000000000000..fd02d186a89504001954b4eeb041a3a21a1c64ce --- /dev/null +++ b/pkg/setup/entity_test.go @@ -0,0 +1,47 @@ +package setup + +import ( + "testing" + + "git.perx.ru/perxis/perxis-go/pkg/collections" + "github.com/stretchr/testify/assert" +) + +func TestEntityList_WithOptions(t *testing.T) { + colls := make(Collections, 0) + colls.Add(&collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env"}) + colls.Add(&collections.Collection{ID: "2", SpaceID: "sp", EnvID: "env"}) + colls.Add(&collections.Collection{ID: "3", SpaceID: "sp", EnvID: "env"}) + colls.Add(&collections.Collection{ID: "4", SpaceID: "sp", EnvID: "env"}) + colls.WithOptions(func(c *collections.Collection) bool { return c.ID == "1" || c.ID == "3" }, func(c *Collection) { + c.UpdateFunc = nil + }) + + assert.Nil(t, colls[0].UpdateFunc) + assert.NotNil(t, colls[1].UpdateFunc) + assert.Nil(t, colls[2].UpdateFunc) + assert.NotNil(t, colls[3].UpdateFunc) +} + +func TestEntityList_Add(t *testing.T) { + c := &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env"} + colls := make(Collections, 0) + colls.Add(c) + colls.Add(c) + assert.Equal(t, colls[0].value, c) + assert.Equal(t, colls[1].value, c) + assert.True(t, colls[0].value != c) + assert.True(t, colls[1].value != c) + assert.True(t, colls[0].value != colls[1].value) +} + +func TestEntityList_Get(t *testing.T) { + c := &collections.Collection{ID: "1", SpaceID: "sp", EnvID: "env"} + colls := make(Collections, 0) + colls.Add(c) + c1 := colls[0].Value(nil) + assert.Equal(t, c, c1) + assert.Equal(t, colls[0].value, c1) + assert.True(t, c != c1) + assert.True(t, colls[0].value != c1) +} diff --git a/pkg/setup/item.go b/pkg/setup/item.go index a17512d0c0ce38714cc52cd7752ec7149ae292b3..adf79935a7e55c212687907f0118112adfcc97ff 100644 --- a/pkg/setup/item.go +++ b/pkg/setup/item.go @@ -5,9 +5,11 @@ import ( "reflect" "strings" + "go.uber.org/zap" + + "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/items" - "go.uber.org/zap" ) var ( @@ -17,44 +19,60 @@ var ( ErrItemsNotFound = errors.New("item not found") ) -type ItemsOption func(c *ItemConfig) -type PublishItemFn func(s *Setup, item *items.Item) (*items.Item, bool) -type UpdateItemFn func(s *Setup, exist, new *items.Item) (*items.Item, bool) -type DeleteItemFn func(s *Setup, col *items.Item) bool +type ( + Item = Entity[ItemConf, *items.Item] + Items = EntityList[ItemConf, *items.Item] + ItemOption = EntityOption[ItemConf, *items.Item] -type ItemConfig struct { - item *items.Item - PublishFn PublishItemFn - UpdateFn UpdateItemFn - DeleteFn DeleteItemFn -} + ItemConf struct { + PublishFunc func(s *Setup, item *items.Item) (*items.Item, bool) + encoded bool // Если запись загружена из файла, необходимо выполнить Decode перед установкой + } +) -func NewItemConfig(item *items.Item, opt ...ItemsOption) ItemConfig { - c := ItemConfig{item: item} +var ( + NewItem = NewEntity[ItemConf, *items.Item] + OverwriteItem = Overwrite[ItemConf, *items.Item] + KeepExistingItem = Keep[ItemConf, *items.Item] + DeleteItem = Delete[ItemConf, *items.Item] + DeleteItemIfRemoveFlag = DeleteIfRemoveFlag[ItemConf, *items.Item] +) - PublishItem()(&c) - KeepExistingItem()(&c) - DeleteItemIfRemove()(&c) +func (ItemConf) Init(e *Entity[ItemConf, *items.Item]) { + PublishItem()(e) + KeepExistingItem()(e) + DeleteItemIfRemoveFlag()(e) +} - for _, o := range opt { - o(&c) +// OverwriteItem перезаписывает элемент +func PublishItem() ItemOption { + return func(c *Item) { + c.Conf.PublishFunc = func(s *Setup, item *items.Item) (*items.Item, bool) { return item, true } } - - return c } -func OverwriteItem() ItemsOption { - return func(c *ItemConfig) { - c.UpdateFn = func(s *Setup, old, new *items.Item) (*items.Item, bool) { return new, true } +// DraftItem не публикует элемент, сохраняет его в черновике +func DraftItem() ItemOption { + return func(c *Item) { + c.Conf.PublishFunc = func(s *Setup, item *items.Item) (*items.Item, bool) { return item, false } } } -func OverwriteFields(fields ...string) ItemsOption { - return func(c *ItemConfig) { - c.UpdateFn = func(s *Setup, old, new *items.Item) (*items.Item, bool) { +// DecodeItem декодирует элемент перед установкой +func DecodeItem() ItemOption { + return func(c *Item) { + c.Conf.encoded = true + } +} +// OverwriteFields разрешает перезаписывать указанные поля элемента, в противном случае считается что элемент не изменился +func OverwriteFields(fields ...string) ItemOption { + return func(c *Item) { + c.UpdateFunc = func(s *Setup, old, new *items.Item) (*items.Item, bool) { var changed bool + for _, field := range fields { + // Пропускаем системные поля if items.IsSystemField(field) { continue } @@ -63,8 +81,8 @@ func OverwriteFields(fields ...string) ItemsOption { if err != nil { continue } - oldValue, err := old.Get(field) + if err != nil || newValue != oldValue { changed = true if err = old.Set(field, newValue); err != nil { @@ -78,9 +96,10 @@ func OverwriteFields(fields ...string) ItemsOption { } } -func KeepFields(fields ...string) ItemsOption { - return func(c *ItemConfig) { - c.UpdateFn = func(s *Setup, old, new *items.Item) (*items.Item, bool) { +// KeepFields сохраняет указанные поля элемента +func KeepFields(fields ...string) ItemOption { + return func(c *Item) { + c.UpdateFunc = func(s *Setup, old, new *items.Item) (*items.Item, bool) { for _, field := range fields { if items.IsSystemField(field) { @@ -105,56 +124,104 @@ func KeepFields(fields ...string) ItemsOption { } } -func KeepExistingItem() ItemsOption { - return func(c *ItemConfig) { - c.UpdateFn = func(s *Setup, old, new *items.Item) (*items.Item, bool) { return old, false } - } -} +// +// Item Setup +// -func DeleteItem() ItemsOption { - return func(c *ItemConfig) { - c.DeleteFn = func(s *Setup, item *items.Item) bool { return true } - } +// AddItem добавляет требования к настройке элементов в пространстве +func (s *Setup) AddItem(item *items.Item, opt ...ItemOption) *Setup { + s.Config.Items.Add(item, opt...) + return s } -func DeleteItemIfRemove() ItemsOption { - return func(c *ItemConfig) { - c.DeleteFn = func(s *Setup, item *items.Item) bool { return s.IsRemove() } - } +// AddItems добавляет требования к настройке элементов в пространстве +func (s *Setup) AddItems(items []*items.Item, opt ...ItemOption) *Setup { + s.Config.Items.AddMany(items, opt...) + return s } -func PublishItem() ItemsOption { - return func(c *ItemConfig) { - c.PublishFn = func(s *Setup, item *items.Item) (*items.Item, bool) { return item, true } +// InstallItem настраивает элемент +func (s *Setup) InstallItem(ctx context.Context, exists map[string]*items.Item, c *Item) error { + item := c.Value(s) + item.SpaceID, item.EnvID = s.SpaceID, s.EnvironmentID + + exist, itemExists := exists[item.ID] + // Если элемент не существует, создаем его + if !itemExists { + if item, publish := c.Conf.PublishFunc(s, item); publish { + return items.CreateAndPublishItem(ctx, s.content.Items, item) + } + if _, err := s.content.Items.Create(ctx, item); err != nil { + return errors.Wrap(err, "create item") + } + return nil } -} -func KeepDraft() ItemsOption { - return func(c *ItemConfig) { - c.PublishFn = func(s *Setup, item *items.Item) (*items.Item, bool) { return item, false } + // Если элемент существует, обновляем его + if item, changed := c.UpdateFunc(s, exist, item); changed { + if _, publish := c.Conf.PublishFunc(s, item); publish { + return items.UpdateAndPublishItem(ctx, s.content.Items, item) + } + if err := s.content.Items.Update(ctx, item); err != nil { + return errors.Wrap(err, "update item") + } + if err := s.content.Items.Unpublish(ctx, item); err != nil { + return errors.Wrap(err, "unpublish item") + } + return nil } + + return nil } -func (s *Setup) InstallItems(ctx context.Context) error { +// InstallItems устанавливает все элементы +func (s *Setup) InstallItems(ctx context.Context) (err error) { if len(s.Items) == 0 { return nil } - s.logger.Debug("Install items", zap.Int("Items", len(s.Items))) + s.logger.Debug("Installing items", zap.Int("Items", len(s.Items))) + + for collID, itms := range groupByCollection(s.Items) { + var coll *collections.Collection + + for i, c := range itms { + // Пропускаем элементы, которые не требуют декодирования + if !c.Conf.encoded { + continue + } + + // Получаем коллекцию и схему для декодирования элемента + if coll == nil { + coll, err = s.content.Collections.Get(ctx, s.SpaceID, s.EnvironmentID, collID) + if err != nil { + return err + } + } + + // Декодируем элемент + decoded, err := c.value.Decode(ctx, coll.Schema) + if err != nil { + return err + } + + itms[i].value = decoded + } - for col, itms := range s.groupByCollection() { - exists, err := s.getExisting(ctx, col, itms) + // Получаем существующие элементы + exists, err := s.getItems(ctx, collID, itms) if err != nil { return err } + + // Устанавливаем элементы for _, c := range itms { if err := s.InstallItem(ctx, exists, c); err != nil { - s.logger.Error("Failed to install item", - zap.String("ID", c.item.ID), - zap.String("Collection", c.item.CollectionID), - zap.Error(err), - ) - return errors.WithDetailf(errors.Wrap(err, "failed to install item"), "Возникла ошибка при добавлении элемента %s(%s)", c.item.ID, c.item.CollectionID) + item := c.Value(s) + s.logger.Error("Failed to install item", zap.String("ID", item.ID), + zap.String("Collection", item.CollectionID), zap.Error(err)) + return errors.WithDetailf(errors.Wrap(err, "failed to install item"), + "Возникла ошибка при добавлении элемента %s(%s)", item.ID, item.CollectionID) } } } @@ -162,35 +229,15 @@ func (s *Setup) InstallItems(ctx context.Context) error { return nil } -func (s *Setup) InstallItem(ctx context.Context, exists map[string]*items.Item, c ItemConfig) error { - item := c.item - item.SpaceID, item.EnvID = s.SpaceID, s.EnvironmentID - - exist, ok := exists[item.ID] - if !ok { - if item, publish := c.PublishFn(s, item); publish { - return items.CreateAndPublishItem(ctx, s.content.Items, item) - } - if _, err := s.content.Items.Create(ctx, item); err != nil { - return errors.Wrap(err, "create item") - } - return nil - } - - if item, changed := c.UpdateFn(s, exist, item); changed { - if _, publish := c.PublishFn(s, item); publish { - return items.UpdateAndPublishItem(ctx, s.content.Items, item) - } - if err := s.content.Items.Update(ctx, item); err != nil { - return errors.Wrap(err, "update item") - } - if err := s.content.Items.Unpublish(ctx, item); err != nil { - return errors.Wrap(err, "unpublish item") +// UninstallItem удаляет элемент +func (s *Setup) UninstallItem(ctx context.Context, c *Item) error { + item := c.Value(s) + if c.DeleteFunc(s, item) { + err := s.content.Items.Delete(ctx, &items.Item{SpaceID: s.SpaceID, EnvID: s.EnvironmentID, CollectionID: item.CollectionID, ID: item.ID}) + if err != nil && !strings.Contains(err.Error(), items.ErrNotFound.Error()) { + return err } - return nil - } - return nil } @@ -203,28 +250,18 @@ func (s *Setup) UninstallItems(ctx context.Context) error { for _, c := range s.Items { if err := s.UninstallItem(ctx, c); err != nil { - s.logger.Error("Failed to uninstall item", - zap.String("Item", c.item.ID), - zap.String("Item", c.item.CollectionID), - zap.Error(err), + item := c.Value(s) + s.logger.Error("Failed to uninstall item", zap.String("Item", item.ID), + zap.String("Item", item.CollectionID), zap.Error(err), ) - return errors.WithDetailf(errors.Wrap(err, "failed to uninstall item"), "Возникла ошибка при удалении элемента %s(%s)", c.item.ID, c.item.CollectionID) + return errors.WithDetailf(errors.Wrap(err, "failed to uninstall item"), + "Возникла ошибка при удалении элемента %s(%s)", item.ID, item.CollectionID) } } return nil } -func (s *Setup) UninstallItem(ctx context.Context, c ItemConfig) error { - if c.DeleteFn(s, c.item) { - err := s.content.Items.Delete(ctx, &items.Item{SpaceID: s.SpaceID, EnvID: s.EnvironmentID, CollectionID: c.item.CollectionID, ID: c.item.ID}) - if err != nil && !strings.Contains(err.Error(), items.ErrNotFound.Error()) { - return err - } - } - return nil -} - func (s *Setup) CheckItems(ctx context.Context) error { if len(s.Items) == 0 { return nil @@ -233,15 +270,17 @@ func (s *Setup) CheckItems(ctx context.Context) error { var errs []error s.logger.Debug("Check items", zap.Int("Items", len(s.Items))) - for col, itms := range s.groupByCollection() { - exists, err := s.getExisting(ctx, col, itms) + for col, itms := range groupByCollection(s.Items) { + exists, err := s.getItems(ctx, col, itms) if err != nil { return err } for _, c := range itms { - if _, ok := exists[c.item.ID]; !ok { - errs = append(errs, errors.WithDetailf(errors.New("not found"), "Не найден элемент %s(%s)", c.item.ID, c.item.CollectionID)) + item := c.Value(s) + if _, ok := exists[item.ID]; !ok { + errs = append(errs, errors.WithDetailf(errors.New("not found"), + "Не найден элемент %s(%s)", item.ID, item.CollectionID)) } } } @@ -253,44 +292,44 @@ func (s *Setup) CheckItems(ctx context.Context) error { return nil } -func (s *Setup) removeItems(collID string) { - itms := make([]ItemConfig, 0, len(s.Items)) - for _, i := range s.Items { - if i.item.CollectionID != collID { - itms = append(itms, i) - } - } - s.Items = itms -} - -func (s *Setup) groupByCollection() map[string][]ItemConfig { - itemsByColl := map[string][]ItemConfig{} - for _, i := range s.Items { - cfg, ok := itemsByColl[i.item.CollectionID] +// +//func (s *Setup) removeItems(collID string) { +// itms := make([]ItemConfig, 0, len(s.Items)) +// for _, i := range s.Items { +// if i.item.CollectionID != collID { +// itms = append(itms, i) +// } +// } +// s.Items = itms +//} + +func groupByCollection(itms Items) map[string]Items { + res := map[string]Items{} + for _, conf := range itms { + collectionID := conf.value.CollectionID + l, ok := res[collectionID] if !ok { - itemsByColl[i.item.CollectionID] = []ItemConfig{i} - continue + res[collectionID] = make(Items, 0, 1) } - itemsByColl[i.item.CollectionID] = append(cfg, i) + res[collectionID] = append(l, conf) } - return itemsByColl + return res } -func (s *Setup) getExisting(ctx context.Context, collID string, configs []ItemConfig) (map[string]*items.Item, error) { +func (s *Setup) getItems(ctx context.Context, collID string, confs Items) (map[string]*items.Item, error) { itms, _, err := s.content.Items.Find( ctx, s.SpaceID, s.EnvironmentID, collID, - &items.Filter{ID: getItemIds(configs)}, + &items.Filter{ID: confs.GetIDs()}, &items.FindOptions{Regular: true, Hidden: true, Templates: true}, ) + if err != nil { - s.logger.Error("Failed to find existing items", - zap.String("Collection", collID), - zap.Error(err), - ) - return nil, errors.WithDetailf(errors.Wrap(err, "failed to find existing items"), "Возникла ошибка при поиске элементов в коллекции %s", collID) + s.logger.Error("Failed to find existing items", zap.String("Collection", collID), zap.Error(err)) + return nil, errors.WithDetailf(errors.Wrap(err, "failed to find existing items"), + "Возникла ошибка при получении элементов в коллекции %s", collID) } exists := make(map[string]*items.Item, len(itms)) @@ -299,11 +338,3 @@ func (s *Setup) getExisting(ctx context.Context, collID string, configs []ItemCo } return exists, nil } - -func getItemIds(items []ItemConfig) []string { - var ids []string - for _, i := range items { - ids = append(ids, i.item.ID) - } - return ids -} diff --git a/pkg/setup/item_test.go b/pkg/setup/item_test.go index 2d2e1a7705a80be6d4eb783af5ad81daf431e886..0a128625e7871d20aad0bceff7561197e97c01ea 100644 --- a/pkg/setup/item_test.go +++ b/pkg/setup/item_test.go @@ -6,10 +6,11 @@ import ( "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/errors" - "git.perx.ru/perxis/perxis-go/pkg/items" itemsMock "git.perx.ru/perxis/perxis-go/pkg/items/mocks" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + + "git.perx.ru/perxis/perxis-go/pkg/items" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -82,17 +83,16 @@ func TestItem_OverwriteFields(t *testing.T) { changed: false, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - c := ItemConfig{item: test.new} - OverwriteFields(test.fields...)(&c) - - got, changed := c.UpdateFn(nil, test.old, test.new) - require.Equal(t, test.changed, changed) - if !test.changed { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := NewItem(tt.new) + OverwriteFields(tt.fields...)(c) + got, changed := c.UpdateFunc(nil, tt.old, tt.new) + require.Equal(t, tt.changed, changed) + if !tt.changed { return } - assert.Equal(t, test.want, got) + assert.Equal(t, tt.want, got) }) } @@ -172,24 +172,22 @@ func TestItem_KeepFields(t *testing.T) { changed: true, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - c := ItemConfig{item: test.new} - KeepFields(test.fields...)(&c) - - got, changed := c.UpdateFn(nil, test.old, test.new) - require.Equal(t, test.changed, changed) - if !test.changed { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := NewItem(tt.new) + KeepFields(tt.fields...)(c) + got, changed := c.UpdateFunc(nil, tt.old, tt.new) + require.Equal(t, tt.changed, changed) + if !tt.changed { return } - assert.Equal(t, test.want, got) + assert.Equal(t, tt.want, got) }) } } func TestSetup_InstallItems(t *testing.T) { - tests := []struct { name string items []*items.Item @@ -279,7 +277,6 @@ func TestSetup_InstallItems(t *testing.T) { } func TestSetup_CreateDraft(t *testing.T) { - tests := []struct { name string items []*items.Item @@ -322,14 +319,13 @@ func TestSetup_CreateDraft(t *testing.T) { } s := NewSetup(&content.Content{Items: i}, "sp", "env", nil) - s.AddItems(tt.items, KeepDraft()) + s.AddItems(tt.items, DraftItem()) tt.wantErr(t, s.InstallItems(context.Background())) }) } } func TestSetup_UpdateDraft(t *testing.T) { - tests := []struct { name string items []*items.Item @@ -358,7 +354,7 @@ func TestSetup_UpdateDraft(t *testing.T) { } s := NewSetup(&content.Content{Items: i}, "sp", "env", nil) - s.AddItems(tt.items, KeepDraft()) + s.AddItems(tt.items, DraftItem()) tt.wantErr(t, s.InstallItems(context.Background())) }) } diff --git a/pkg/setup/role.go b/pkg/setup/role.go index ac6e641a97c6160cf29c5353f0176ef110a9bab3..2498e8456c474331ce648dbf48caaccf16718bb3 100644 --- a/pkg/setup/role.go +++ b/pkg/setup/role.go @@ -4,11 +4,12 @@ import ( "context" "strings" + "go.uber.org/zap" + "git.perx.ru/perxis/perxis-go/pkg/data" "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/permission" "git.perx.ru/perxis/perxis-go/pkg/roles" - "go.uber.org/zap" ) var ( @@ -17,67 +18,28 @@ var ( ErrUninstallRoles = errors.New("failed to uninstall role") ) -type RolesOption func(c *RoleConfig) -type UpdateRoleFn func(s *Setup, exist, new *roles.Role) (*roles.Role, bool) -type DeleteRoleFn func(s *Setup, role *roles.Role) bool - -type RoleConfig struct { - role *roles.Role - UpdateFn UpdateRoleFn - DeleteFn DeleteRoleFn -} - -func NewRoleConfig(role *roles.Role, opt ...RolesOption) RoleConfig { - c := RoleConfig{role: role} - - UpdateExistingRole()(&c) - DeleteRoleIfRemove()(&c) - - for _, o := range opt { - o(&c) - } - return c -} - -func OverwriteRole() RolesOption { - return func(c *RoleConfig) { - c.UpdateFn = func(s *Setup, old, new *roles.Role) (*roles.Role, bool) { return new, true } - } -} - -//func OverwriteRoleIfChanged() RolesOption { -// return func(c *RoleConfig) { -// c.UpdateFn = func(s *Setup, old, new *roles.Role) (*roles.Role, bool) { -// changed := old.Description != new.Description || old.AllowManagement != new.AllowManagement || -// !util.ElementsMatch(old.Environments, new.Environments) -// return new, changed -// } -// } -//} - -func KeepExistingRole() RolesOption { - return func(c *RoleConfig) { - c.UpdateFn = func(s *Setup, old, new *roles.Role) (*roles.Role, bool) { return old, false } - } -} - -func DeleteRole() RolesOption { - return func(c *RoleConfig) { - c.DeleteFn = func(s *Setup, role *roles.Role) bool { return true } - } -} +type Role = Entity[RoleConf, *roles.Role] +type Roles = EntityList[RoleConf, *roles.Role] +type RoleOption = EntityOption[RoleConf, *roles.Role] +type RoleConf struct{} -func DeleteRoleIfRemove() RolesOption { - return func(c *RoleConfig) { - c.DeleteFn = func(s *Setup, role *roles.Role) bool { return s.IsRemove() } - } +// Init инициализирует конфигурацию коллекции +func (RoleConf) Init(e *Entity[RoleConf, *roles.Role]) { + DefaultRoleUpdateFunc()(e) + DeleteRoleIfRemoveFlag()(e) } -func UpdateExistingRole() RolesOption { - return func(c *RoleConfig) { - c.UpdateFn = func(s *Setup, exist, new *roles.Role) (*roles.Role, bool) { +var ( + NewRole = NewEntity[RoleConf, *roles.Role] + OverwriteRole = Overwrite[RoleConf, *roles.Role] + KeepExistingRole = Keep[RoleConf, *roles.Role] + DeleteRole = Delete[RoleConf, *roles.Role] + DeleteRoleIfRemoveFlag = DeleteIfRemoveFlag[RoleConf, *roles.Role] +) - // если передан флаг force, то обновляем все поля роли на переданные +func DefaultRoleUpdateFunc() RoleOption { + return func(c *Role) { + c.UpdateFunc = func(s *Setup, exist, new *roles.Role) (*roles.Role, bool) { if s.IsForce() { return new, true } @@ -105,68 +67,74 @@ func UpdateExistingRole() RolesOption { } } -func (s *Setup) InstallRoles(ctx context.Context) error { - if len(s.Roles) == 0 { - return nil - } - - s.logger.Debug("Install role", zap.String("Space ID", s.SpaceID), zap.Int("Roles", len(s.Roles))) +// +// Role Setup +// - for _, c := range s.Roles { - if err := s.InstallRole(ctx, c); err != nil { - s.logger.Error("Failed to install role", zap.String("Role ID", c.role.ID), zap.Error(err)) - return errors.Wrap(errors.WithDetailf(err, "Возникла ошибка при настройке роли %s(%s)", c.role.ID, c.role.Description), "failed to install role") - } - } +// AddRoles добавляет требования к настройке ролей в пространстве +func (s *Setup) AddRoles(roles []*roles.Role, opt ...RoleOption) *Setup { + s.Config.Roles.AddMany(roles, opt...) + return s +} - return nil +// AddRole добавляет требования к настройке элементов в пространстве +func (s *Setup) AddRole(role *roles.Role, opt ...RoleOption) *Setup { + s.Config.Roles.Add(role, opt...) + return s } -func (s *Setup) InstallRole(ctx context.Context, c RoleConfig) error { - role := c.role +// InstallRole устанавливает роль +func (s *Setup) InstallRole(ctx context.Context, c *Role) error { + role := c.Value(s) role.SpaceID = s.SpaceID - if !data.Contains(s.EnvironmentID, c.role.Environments) { + if !data.Contains(s.EnvironmentID, role.Environments) { role.Environments = append(role.Environments, s.EnvironmentID) } exist, err := s.content.Roles.Get(ctx, s.SpaceID, role.ID) + + // Если роль не найдена, создаем новую if err != nil { if !strings.Contains(err.Error(), roles.ErrNotFound.Error()) { return err } - _, err = s.content.Roles.Create(ctx, role) return err } - if r, upd := c.UpdateFn(s, exist, role); upd { + // Если роль найдена, обновляем ее + if r, needUpdate := c.UpdateFunc(s, exist, role); needUpdate { return s.content.Roles.Update(ctx, r) } return nil } -func (s *Setup) UninstallRoles(ctx context.Context) error { +// InstallRoles устанавливает все роли +func (s *Setup) InstallRoles(ctx context.Context) error { if len(s.Roles) == 0 { return nil } - s.logger.Debug("Uninstall role", zap.String("Space ID", s.SpaceID), zap.Int("Roles", len(s.Roles))) + s.logger.Debug("Install roles", zap.String("Space ID", s.SpaceID), zap.Int("Roles", len(s.Roles))) for _, c := range s.Roles { - if err := s.UninstallRole(ctx, c); err != nil { - s.logger.Error("Failed to uninstall role", zap.String("Role ID", c.role.ID), zap.Error(err)) - return errors.WithDetailf(errors.Wrap(err, "failed to uninstall role"), "Возникла ошибка при удалении роли %s(%s)", c.role.ID, c.role.Description) + if err := s.InstallRole(ctx, c); err != nil { + role := c.Value(s) + s.logger.Error("Failed to install role", zap.String("Role ID", role.ID), zap.Error(err)) + return errors.Wrap(errors.WithDetailf(err, "Возникла ошибка при настройке роли %s(%s)", role.ID, role.Description), "failed to install role") } } return nil } -func (s *Setup) UninstallRole(ctx context.Context, c RoleConfig) error { - if c.DeleteFn(s, c.role) { - err := s.content.Roles.Delete(ctx, s.SpaceID, c.role.ID) +// UninstallRole удаляет роль +func (s *Setup) UninstallRole(ctx context.Context, c *Role) error { + role := c.Value(s) + if c.DeleteFunc(s, role) { + err := s.content.Roles.Delete(ctx, s.SpaceID, role.ID) if err != nil && !strings.Contains(err.Error(), roles.ErrNotFound.Error()) { return err } @@ -174,6 +142,34 @@ func (s *Setup) UninstallRole(ctx context.Context, c RoleConfig) error { return nil } +// UninstallRoles удаляет все роли +func (s *Setup) UninstallRoles(ctx context.Context) error { + if len(s.Roles) == 0 { + return nil + } + + s.logger.Debug("Uninstall role", zap.String("Space ID", s.SpaceID), zap.Int("Roles", len(s.Roles))) + + for _, c := range s.Roles { + if err := s.UninstallRole(ctx, c); err != nil { + role := c.Value(s) + s.logger.Error("Failed to uninstall role", zap.String("Role ID", role.ID), zap.Error(err)) + return errors.WithDetailf(errors.Wrap(err, "failed to uninstall role"), + "Возникла ошибка при удалении роли %s(%s)", role.ID, role.Description) + } + } + + return nil +} + +// CheckRole проверяет наличие роли +func (s *Setup) CheckRole(ctx context.Context, c *Role) error { + role := c.Value(s) + _, err := s.content.Roles.Get(ctx, s.SpaceID, role.ID) + return err +} + +// CheckRoles проверяет наличие всех ролей func (s *Setup) CheckRoles(ctx context.Context) error { if len(s.Roles) == 0 { return nil @@ -183,8 +179,9 @@ func (s *Setup) CheckRoles(ctx context.Context) error { var errs []error for _, c := range s.Roles { - if err := s.CheckRole(ctx, c.role); err != nil { - errs = append(errs, errors.WithDetailf(err, "Не найдена роль %s(%s)", c.role.ID, c.role.Description)) + if err := s.CheckRole(ctx, c); err != nil { + role := c.Value(s) + errs = append(errs, errors.WithDetailf(err, "Не найдена роль %s(%s)", role.ID, role.Description)) } } @@ -194,8 +191,3 @@ func (s *Setup) CheckRoles(ctx context.Context) error { return nil } - -func (s *Setup) CheckRole(ctx context.Context, role *roles.Role) error { - _, err := s.content.Roles.Get(ctx, s.SpaceID, role.ID) - return err -} diff --git a/pkg/setup/setup.go b/pkg/setup/setup.go index b087337fcb57e3cb1a76cad1e3354291b944bdb0..8855269638d1901b553ee4a6ecc6ed2c488f3d17 100644 --- a/pkg/setup/setup.go +++ b/pkg/setup/setup.go @@ -2,13 +2,10 @@ package setup import ( "context" + "io/fs" - "git.perx.ru/perxis/perxis-go/pkg/clients" - "git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/errors" - "git.perx.ru/perxis/perxis-go/pkg/items" - "git.perx.ru/perxis/perxis-go/pkg/roles" "git.perx.ru/perxis/perxis-go/pkg/spaces" "go.uber.org/zap" ) @@ -23,11 +20,6 @@ type Setup struct { SpaceID string EnvironmentID string - Roles []RoleConfig - Clients []ClientConfig - Collections []CollectionConfig - Items []ItemConfig - content *content.Content force bool @@ -39,6 +31,8 @@ type Setup struct { errors []error logger *zap.Logger + + *Config } func NewSetup(content *content.Content, spaceID, environmentID string, logger *zap.Logger) *Setup { @@ -54,9 +48,23 @@ func NewSetup(content *content.Content, spaceID, environmentID string, logger *z content: content, logger: logger, waitSpaceAvailable: true, + Config: NewConfig(), // Копируем конфигурацию, чтобы не изменять исходную в процессе работы } } +// Logger возвращает логгер +func (s *Setup) Logger() *zap.Logger { + return s.logger +} + +// WithConfig устанавливает конфигурацию требований к пространству +// копируем конфигурацию, чтобы не изменять исходную в процессе работы +func (s *Setup) WithConfig(config *Config) *Setup { + setup := *s + setup.Config = config.Clone() + return &setup +} + func (s *Setup) WithForce(force bool) *Setup { setup := *s setup.force = force @@ -99,63 +107,6 @@ func (s *Setup) Error() error { return errors.WithErrors(ErrInvalidSetupConfig, s.errors...) } -// AddRoles добавляет требования к настройке ролей в пространстве -func (s *Setup) AddRoles(roles []*roles.Role, opt ...RolesOption) *Setup { - for _, role := range roles { - s.AddRole(role, opt...) - } - return s -} - -func (s *Setup) AddRole(role *roles.Role, opt ...RolesOption) *Setup { - s.Roles = append(s.Roles, NewRoleConfig(role, opt...)) - return s -} - -// AddClients добавляет требования к настройке приложений в пространстве -func (s *Setup) AddClients(clients []*clients.Client, opt ...ClientsOption) *Setup { - for _, client := range clients { - s.AddClient(client, opt...) - } - return s -} - -func (s *Setup) AddClient(client *clients.Client, opt ...ClientsOption) *Setup { - s.Clients = append(s.Clients, NewClientConfig(client, opt...)) - return s -} - -// AddCollections добавляет требования к настройке коллекций в пространстве -func (s *Setup) AddCollections(collections []*collections.Collection, opt ...CollectionsOption) *Setup { - for _, col := range collections { - s.AddCollection(col, opt...) - } - return s -} - -func (s *Setup) AddCollection(collection *collections.Collection, opt ...CollectionsOption) *Setup { - config, err := NewCollectionConfig(collection, opt...) - if err != nil { - s.AddError(err) - return s - } - s.Collections = append(s.Collections, config) - return s -} - -// AddItems добавляет требования к настройке элементов в пространстве -func (s *Setup) AddItems(items []*items.Item, opt ...ItemsOption) *Setup { - for _, item := range items { - s.AddItem(item, opt...) - } - return s -} - -func (s *Setup) AddItem(item *items.Item, opt ...ItemsOption) *Setup { - s.Items = append(s.Items, NewItemConfig(item, opt...)) - return s -} - // Install выполняет установку необходимых требований func (s *Setup) Install(ctx context.Context) error { if s.waitSpaceAvailable { @@ -222,3 +173,12 @@ func (s *Setup) Uninstall(ctx context.Context) error { } return nil } + +func (s *Setup) Load(fsys fs.FS) *Setup { + var err error + s.Config, err = s.Config.Load(fsys) + if err != nil { + s.AddError(err) + } + return s +} diff --git a/pkg/setup/setup_test.go b/pkg/setup/setup_test.go index 604c2f6b29bae32756e2149ca572ce3b54920936..ff73b745deb0fcec807fa0c0f28b2ba5a0dd7258 100644 --- a/pkg/setup/setup_test.go +++ b/pkg/setup/setup_test.go @@ -2,26 +2,27 @@ package setup import ( "context" + "errors" "testing" - "git.perx.ru/perxis/perxis-go/pkg/clients" clientsMock "git.perx.ru/perxis/perxis-go/pkg/clients/mocks" - "git.perx.ru/perxis/perxis-go/pkg/collections" collectionMock "git.perx.ru/perxis/perxis-go/pkg/collections/mocks" - "git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/data" environmentMock "git.perx.ru/perxis/perxis-go/pkg/environments/mocks" - "git.perx.ru/perxis/perxis-go/pkg/errors" - "git.perx.ru/perxis/perxis-go/pkg/items" itemsMock "git.perx.ru/perxis/perxis-go/pkg/items/mocks" - "git.perx.ru/perxis/perxis-go/pkg/roles" rolesMock "git.perx.ru/perxis/perxis-go/pkg/roles/mocks" - "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/spaces" "git.perx.ru/perxis/perxis-go/pkg/spaces/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + + "git.perx.ru/perxis/perxis-go/pkg/clients" + "git.perx.ru/perxis/perxis-go/pkg/collections" + "git.perx.ru/perxis/perxis-go/pkg/content" + "git.perx.ru/perxis/perxis-go/pkg/items" + "git.perx.ru/perxis/perxis-go/pkg/roles" + "git.perx.ru/perxis/perxis-go/pkg/schema" "go.uber.org/zap/zaptest" ) @@ -78,13 +79,14 @@ func getActions() []*items.Item { } func newSetup(content *content.Content, t *testing.T) *Setup { - logger := zaptest.NewLogger(t, zaptest.WrapOptions()) - setup := NewSetup(content, spaceID, envID, logger) - setup.AddCollections(getCollections()) - setup.AddRoles(getRoles()) - setup.AddClients(getClients()) - setup.AddItems(getActions(), OverwriteItem()) + config := NewConfig() + config.Collections.AddMany(getCollections()) + config.Roles.AddMany(getRoles()) + config.Clients.AddMany(getClients()) + config.Items.AddMany(getActions(), OverwriteItem()) + logger := zaptest.NewLogger(t, zaptest.WrapOptions()) + setup := NewSetup(content, spaceID, envID, logger).WithConfig(config) return setup } @@ -101,10 +103,8 @@ func TestSetupInstall(t *testing.T) { spcMock.On("Get", mock.Anything, mock.Anything).Return(sps, nil).Once() setup := NewSetup(&content.Content{Spaces: spcMock}, spaceID, envID, logger) err := setup.Install(context.Background()) - require.NoError(t, err) spcMock.AssertExpectations(t) - }) t.Run("Success, no force", func(t *testing.T) { @@ -116,23 +116,19 @@ func TestSetupInstall(t *testing.T) { collsMock := &collectionMock.Collections{} for _, collection := range getCollections() { collsMock.On("Get", mock.Anything, spaceID, envID, collection.ID). - Return(nil, collections.ErrNotFound). - Once() + Return(nil, collections.ErrNotFound).Once() collsMock.On("Create", mock.Anything, collection). - Return(collection, nil). - Once() + Return(collection, nil).Once() collsMock.On("SetSchema", mock.Anything, spaceID, envID, collection.ID, collection.Schema). - Return(nil). - Once() + Return(nil).Once() } rMock := &rolesMock.Roles{} for _, role := range getRoles() { rMock.On("Get", mock.Anything, spaceID, role.ID). - Return(nil, roles.ErrNotFound). - Once() + Return(nil, roles.ErrNotFound).Once() rMock.On("Create", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { create := args[1].(*roles.Role) diff --git a/pkg/spaces/errors.go b/pkg/spaces/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..c9e66fa698198eb8b01034eb2bad83286d60297f --- /dev/null +++ b/pkg/spaces/errors.go @@ -0,0 +1,12 @@ +package spaces + +import ( + "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/pkg/service" +) + +var ( + ErrNotFound = service.ErrNotFound + ErrStateConflict = errors.New("state conflicts with current space state") + ErrOrgIDRequired = errors.New("organization id required") +) diff --git a/pkg/spaces/events.go b/pkg/spaces/events.go new file mode 100644 index 0000000000000000000000000000000000000000..418e4ea8a27237c39250433f3ff0cfa7c819e457 --- /dev/null +++ b/pkg/spaces/events.go @@ -0,0 +1,12 @@ +package spaces + +const ( + EventAbortTransfer = "spaces.abort_transfer" + EventCreate = "spaces.create" + EventDelete = "spaces.delete" + EventMove = "spaces.move" + EventTransfer = "spaces.transfer" + EventUpdate = "spaces.update" + EventUpdateConfig = "spaces.update_config" + EventMigrate = "spaces.migrate" +) diff --git a/pkg/spaces/middleware/access_logging_middleware.go b/pkg/spaces/middleware/access_logging_middleware.go index 7fca51ede8a87ba31ceb7293537e32c2db4c08d7..9596d7d4fc2daa611a0db631eef56fe6d5531488 100644 --- a/pkg/spaces/middleware/access_logging_middleware.go +++ b/pkg/spaces/middleware/access_logging_middleware.go @@ -11,6 +11,7 @@ import ( "time" "git.perx.ru/perxis/perxis-go/pkg/auth" + "git.perx.ru/perxis/perxis-go/pkg/options" "git.perx.ru/perxis/perxis-go/pkg/spaces" "go.uber.org/zap" ) @@ -86,6 +87,27 @@ func (m *accessLoggingMiddleware) Delete(ctx context.Context, spaceId string) (e return err } +func (m *accessLoggingMiddleware) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) (spaces []*spaces.Space, total int, err error) { + begin := time.Now() + + m.logger.Debug("Find.Request", + zap.Reflect("principal", auth.GetPrincipal(ctx)), + zap.Reflect("filter", filter), + zap.Reflect("fo", fo), + ) + + spaces, total, err = m.next.Find(ctx, filter, fo) + + m.logger.Debug("Find.Response", + zap.Duration("time", time.Since(begin)), + zap.Reflect("spaces", spaces), + zap.Reflect("total", total), + zap.Error(err), + ) + + return spaces, total, err +} + func (m *accessLoggingMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) { begin := time.Now() @@ -217,3 +239,22 @@ func (m *accessLoggingMiddleware) UpdateConfig(ctx context.Context, spaceId stri return err } + +func (m *accessLoggingMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) { + begin := time.Now() + + m.logger.Debug("SetState.Request", + zap.Reflect("principal", auth.GetPrincipal(ctx)), + zap.Reflect("spaceID", spaceID), + zap.Reflect("state", state), + ) + + err = m.next.SetState(ctx, spaceID, state) + + m.logger.Debug("SetState.Response", + zap.Duration("time", time.Since(begin)), + zap.Error(err), + ) + + return err +} diff --git a/pkg/spaces/middleware/caching_middleware.go b/pkg/spaces/middleware/caching_middleware.go index f99e21a1f4a254ef6fb0890d09776b9b4738fd38..c7f35de12106e9aa828e56ebd6f6ec4361c70da7 100644 --- a/pkg/spaces/middleware/caching_middleware.go +++ b/pkg/spaces/middleware/caching_middleware.go @@ -4,6 +4,8 @@ import ( "context" "git.perx.ru/perxis/perxis-go/pkg/cache" + "git.perx.ru/perxis/perxis-go/pkg/data" + "git.perx.ru/perxis/perxis-go/pkg/options" service "git.perx.ru/perxis/perxis-go/pkg/spaces" ) @@ -29,7 +31,7 @@ func (m cachingMiddleware) Create(ctx context.Context, space *service.Space) (sp sp, err = m.next.Create(ctx, space) if err == nil { - m.cache.Remove(orgKey(sp.OrgID)) + _ = m.cache.Remove(orgKey(sp.OrgID)) } return sp, err } @@ -38,29 +40,35 @@ func (m cachingMiddleware) Get(ctx context.Context, spaceId string) (sp *service value, e := m.cache.Get(spaceId) if e == nil { - return value.(*service.Space), err + return value.(*service.Space).Clone(), nil } sp, err = m.next.Get(ctx, spaceId) if err == nil { - m.cache.Set(spaceId, sp) + _ = m.cache.Set(spaceId, sp) + return sp.Clone(), nil } - return sp, err + return nil, err } func (m cachingMiddleware) List(ctx context.Context, orgId string) (spaces []*service.Space, err error) { value, e := m.cache.Get(orgKey(orgId)) if e == nil { - return value.([]*service.Space), err + return data.CloneSlice(value.([]*service.Space)), nil } spaces, err = m.next.List(ctx, orgId) if err == nil { - m.cache.Set(orgKey(orgId), spaces) + _ = m.cache.Set(orgKey(orgId), spaces) for _, s := range spaces { - m.cache.Set(s.ID, s) + _ = m.cache.Set(s.ID, s) } + return data.CloneSlice(spaces), nil } - return spaces, err + return nil, err +} + +func (m cachingMiddleware) Find(ctx context.Context, filter *service.Filter, fo *options.FindOptions) (spaces []*service.Space, total int, err error) { + return m.next.Find(ctx, filter, fo) } func (m cachingMiddleware) Update(ctx context.Context, space *service.Space) (err error) { @@ -70,9 +78,9 @@ func (m cachingMiddleware) Update(ctx context.Context, space *service.Space) (er value, e := m.cache.Get(space.ID) if e == nil { space := value.(*service.Space) - m.cache.Remove(orgKey(space.OrgID)) + _ = m.cache.Remove(orgKey(space.OrgID)) } - m.cache.Remove(space.ID) + _ = m.cache.Remove(space.ID) } return err } @@ -84,9 +92,23 @@ func (m cachingMiddleware) UpdateConfig(ctx context.Context, spaceId string, con value, e := m.cache.Get(spaceId) if e == nil { space := value.(*service.Space) - m.cache.Remove(orgKey(space.OrgID)) + _ = m.cache.Remove(orgKey(space.OrgID)) + } + _ = m.cache.Remove(spaceId) + } + return err +} + +func (m cachingMiddleware) SetState(ctx context.Context, spaceID string, state *service.StateInfo) (err error) { + + err = m.next.SetState(ctx, spaceID, state) + if err == nil { + value, e := m.cache.Get(spaceID) + if e == nil { + space := value.(*service.Space) + _ = m.cache.Remove(orgKey(space.OrgID)) } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceID) } return err } @@ -98,9 +120,9 @@ func (m cachingMiddleware) Delete(ctx context.Context, spaceId string) (err erro value, e := m.cache.Get(spaceId) if e == nil { space := value.(*service.Space) - m.cache.Remove(orgKey(space.OrgID)) + _ = m.cache.Remove(orgKey(space.OrgID)) } - m.cache.Remove(spaceId) + _ = m.cache.Remove(spaceId) } return err } @@ -111,11 +133,11 @@ func (m cachingMiddleware) Transfer(ctx context.Context, spaceID, transferToOrg value, e := m.cache.Get(spaceID) if e == nil { space := value.(*service.Space) - m.cache.Remove(orgKey(space.OrgID)) - m.cache.Remove(orgKey(space.TransferToOrg)) + _ = m.cache.Remove(orgKey(space.OrgID)) + _ = m.cache.Remove(orgKey(space.TransferToOrg)) } - m.cache.Remove(spaceID) - m.cache.Remove(transferToOrg) + _ = m.cache.Remove(spaceID) + _ = m.cache.Remove(transferToOrg) } return err } @@ -126,10 +148,10 @@ func (m cachingMiddleware) AbortTransfer(ctx context.Context, spaceID string) er value, e := m.cache.Get(spaceID) if e == nil { space := value.(*service.Space) - m.cache.Remove(orgKey(space.OrgID)) - m.cache.Remove(orgKey(space.TransferToOrg)) + _ = m.cache.Remove(orgKey(space.OrgID)) + _ = m.cache.Remove(orgKey(space.TransferToOrg)) } - m.cache.Remove(spaceID) + _ = m.cache.Remove(spaceID) } return err } @@ -144,11 +166,11 @@ func (m cachingMiddleware) Move(ctx context.Context, spaceID, orgID string) erro value, e := m.cache.Get(spaceID) if e == nil { space := value.(*service.Space) - m.cache.Remove(orgKey(space.OrgID)) - m.cache.Remove(orgKey(space.TransferToOrg)) + _ = m.cache.Remove(orgKey(space.OrgID)) + _ = m.cache.Remove(orgKey(space.TransferToOrg)) } - m.cache.Remove(spaceID) - m.cache.Remove(orgID) + _ = m.cache.Remove(spaceID) + _ = m.cache.Remove(orgID) } return err } diff --git a/pkg/spaces/middleware/caching_middleware_test.go b/pkg/spaces/middleware/caching_middleware_test.go index e87ceb38c79c6b15d76ab6f6ff8f628a680a5aa6..0674c932eb4e5f9d519a587a45cc4c5003b8f7d7 100644 --- a/pkg/spaces/middleware/caching_middleware_test.go +++ b/pkg/spaces/middleware/caching_middleware_test.go @@ -40,7 +40,8 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) sp.AssertExpectations(t) }) @@ -57,7 +58,8 @@ func TestRolesCache(t *testing.T) { vl2, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) sp.AssertExpectations(t) }) @@ -76,14 +78,16 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) vl1, err := svc.List(ctx, orgID) require.NoError(t, err) vl2, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) sp.On("Update", mock.Anything, mock.Anything).Return(nil).Once() @@ -95,11 +99,11 @@ func TestRolesCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, v2, v3, "Ожидается что кеш объекта был удален после обновления объекта.") + assert.NotEqual(t, v2, v3, "Ожидается что кеш объекта был удален после обновления объекта.") vl3, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после обновления объекта.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после обновления объекта.") sp.AssertExpectations(t) }) @@ -117,14 +121,16 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) vl1, err := svc.List(ctx, orgID) require.NoError(t, err) vl2, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) sp.On("UpdateConfig", mock.Anything, spaceID, mock.Anything).Return(nil).Once() @@ -136,11 +142,11 @@ func TestRolesCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.NotSame(t, v2, v3, "Ожидается что кеш объекта был удален после обновления объекта.") + assert.NotEqual(t, v2, v3, "Ожидается что кеш объекта был удален после обновления объекта.") vl3, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.NotSame(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после обновления объекта.") + assert.NotEqual(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после обновления объекта.") sp.AssertExpectations(t) }) @@ -158,14 +164,16 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) vl1, err := svc.List(ctx, orgID) require.NoError(t, err) vl2, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) sp.On("Delete", mock.Anything, spaceID).Return(nil).Once() @@ -198,7 +206,8 @@ func TestRolesCache(t *testing.T) { vl2, err := svc.List(ctx, orgID) require.NoError(t, err) - assert.Same(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.Equal(t, vl1[0], vl2[0], "Ожидается при повторном запросе получение объектов из кэша.") + assert.NotSame(t, vl1[0], vl2[0]) sp.On("Create", mock.Anything, mock.Anything).Return(&spaces.Space{ID: "spaceID2", OrgID: orgID, Name: "Space2"}, nil).Once() @@ -210,6 +219,8 @@ func TestRolesCache(t *testing.T) { vl3, err := svc.List(ctx, orgID) require.NoError(t, err) assert.NotSame(t, vl2[0], vl3[0], "Ожидается что кеш объектов был удален после создания нового объекта.") + assert.Equal(t, vl2[0], vl3[0]) + assert.NotSame(t, vl2[0], vl3[0]) sp.AssertExpectations(t) }) @@ -226,7 +237,8 @@ func TestRolesCache(t *testing.T) { v2, err := svc.Get(ctx, spaceID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается при повторном запросе получение объекта из кэша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) sp.On("Get", mock.Anything, spaceID).Return(&spaces.Space{ID: spaceID, OrgID: orgID, Name: "Space"}, nil).Once() @@ -234,6 +246,8 @@ func TestRolesCache(t *testing.T) { v3, err := svc.Get(ctx, spaceID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается удаление объекта из кэша по истечению ttl.") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) sp.AssertExpectations(t) }) diff --git a/pkg/spaces/middleware/error_logging_middleware.go b/pkg/spaces/middleware/error_logging_middleware.go index 2b11838b51f1a033e9963a729c6378401e193d0c..677b48366b6304e47988578bcb694ad758ba3ab0 100644 --- a/pkg/spaces/middleware/error_logging_middleware.go +++ b/pkg/spaces/middleware/error_logging_middleware.go @@ -9,6 +9,7 @@ package middleware import ( "context" + "git.perx.ru/perxis/perxis-go/pkg/options" "git.perx.ru/perxis/perxis-go/pkg/spaces" "go.uber.org/zap" ) @@ -59,6 +60,16 @@ func (m *errorLoggingMiddleware) Delete(ctx context.Context, spaceId string) (er return m.next.Delete(ctx, spaceId) } +func (m *errorLoggingMiddleware) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) (spaces []*spaces.Space, total int, err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.Find(ctx, filter, fo) +} + func (m *errorLoggingMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) { logger := m.logger defer func() { @@ -99,6 +110,16 @@ func (m *errorLoggingMiddleware) Move(ctx context.Context, spaceID string, orgID return m.next.Move(ctx, spaceID, orgID) } +func (m *errorLoggingMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) { + logger := m.logger + defer func() { + if err != nil { + logger.Warn("response error", zap.Error(err)) + } + }() + return m.next.SetState(ctx, spaceID, state) +} + func (m *errorLoggingMiddleware) Transfer(ctx context.Context, spaceID string, transferToOrg string) (err error) { logger := m.logger defer func() { diff --git a/pkg/spaces/middleware/logging_middleware.go b/pkg/spaces/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..a45ec2df50923d480f9c94f3c2f26bf266121aff --- /dev/null +++ b/pkg/spaces/middleware/logging_middleware.go @@ -0,0 +1,236 @@ +package middleware + +import ( + "context" + "fmt" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/options" + "git.perx.ru/perxis/perxis-go/pkg/spaces" + + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next spaces.Spaces +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next spaces.Spaces) spaces.Spaces { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Spaces")), + } + } +} + +func (m *loggingMiddleware) AbortTransfer(ctx context.Context, spaceID string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventAbortTransfer), + logzap.Object(id.NewSpaceId(spaceID)), + ) + + err = m.next.AbortTransfer(ctx, spaceID) + if err != nil { + logger.Error("Failed to abort transfer", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Aborted space transfer", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Create(ctx context.Context, space *spaces.Space) (created *spaces.Space, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventCreate), + ) + + created, err = m.next.Create(ctx, space) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(space)) + return + } + + logger.Info("Space created", logzap.Channels(logzap.Userlog), logzap.Object(created)) + + return created, err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, spaceId string) (err error) { + space, err := m.Get(ctx, spaceId) + if err != nil { + return err + } + + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventDelete), + logzap.Object(id.NewOrganizationId(space.OrgID)), + ) + + err = m.next.Delete(ctx, spaceId) + if err != nil { + logger.Error(fmt.Sprintf("Failed to delete space '%s'", spaceId), zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info(fmt.Sprintf("Space '%s' deleted", spaceId), logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewSpaceId(spaceId)), + ) + + space, err = m.next.Get(ctx, spaceId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return space, err +} + +func (m *loggingMiddleware) List(ctx context.Context, orgId string) (spaces []*spaces.Space, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + spaces, err = m.next.List(ctx, orgId) + if err != nil { + logger.Error("Failed to list", zap.Error(err)) + return + } + + return spaces, err +} + +func (m *loggingMiddleware) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) (spaces []*spaces.Space, total int, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + spaces, total, err = m.next.Find(ctx, filter, fo) + if err != nil { + logger.Error("Failed to find", zap.Error(err)) + return + } + + return spaces, total, err +} + +func (m *loggingMiddleware) ListTransfers(ctx context.Context, orgID string) (spaces []*spaces.Space, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + spaces, err = m.next.ListTransfers(ctx, orgID) + if err != nil { + logger.Error("Failed to list transfers", zap.Error(err)) + return + } + + return spaces, err +} + +func (m *loggingMiddleware) Move(ctx context.Context, spaceID string, orgID string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventMove), + logzap.Object(id.NewSpaceId(spaceID)), + ) + + err = m.next.Move(ctx, spaceID, orgID) + if err != nil { + logger.Error("Failed to move", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Space moved", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Transfer(ctx context.Context, spaceID string, transferToOrg string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventTransfer), + logzap.Object(id.NewSpaceId(spaceID)), + ) + + err = m.next.Transfer(ctx, spaceID, transferToOrg) + if err != nil { + logger.Error("Failed to transfer", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Space transferred", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Update(ctx context.Context, space *spaces.Space) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventUpdate), + logzap.Object(space), + ) + + err = m.next.Update(ctx, space) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Space updated", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventUpdate), + logzap.Object(id.NewSpaceId(spaceID)), + ) + + var st spaces.State + if state != nil { + st = state.State + } + + err = m.next.SetState(ctx, spaceID, state) + if err != nil { + logger.Error(fmt.Sprintf("Failed to set state '%s' to space", st), zap.Error(err)) + return + } + + logger.Info(fmt.Sprintf("Set state '%s' to space", st)) + return err +} + +func (m *loggingMiddleware) UpdateConfig(ctx context.Context, spaceId string, config *spaces.Config) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(spaces.EventUpdateConfig), + logzap.Object(id.NewSpaceId(spaceId)), + ) + + err = m.next.UpdateConfig(ctx, spaceId, config) + if err != nil { + logger.Error("Failed to update config", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("Updated space config", logzap.Channels(logzap.Userlog)) + + return err +} diff --git a/pkg/spaces/middleware/middleware.go b/pkg/spaces/middleware/middleware.go index 73c3b8c3538e6bf9a6457617afc35f68f429aaf3..15f2bc259beacd5ea312632ba042a33b59022f32 100644 --- a/pkg/spaces/middleware/middleware.go +++ b/pkg/spaces/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s spaces.Spaces, logger *zap.Logger, log_access bool) spaces.Spaces if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/spaces/middleware/recovering_middleware.go b/pkg/spaces/middleware/recovering_middleware.go index 7b9b64ed276aa9a91dd9e07ee1b463ff8bb06003..cca581b6643b32bf21f31964aac200bb9613515d 100644 --- a/pkg/spaces/middleware/recovering_middleware.go +++ b/pkg/spaces/middleware/recovering_middleware.go @@ -10,6 +10,7 @@ import ( "context" "fmt" + "git.perx.ru/perxis/perxis-go/pkg/options" "git.perx.ru/perxis/perxis-go/pkg/spaces" "go.uber.org/zap" ) @@ -66,6 +67,18 @@ func (m *recoveringMiddleware) Delete(ctx context.Context, spaceId string) (err return m.next.Delete(ctx, spaceId) } +func (m *recoveringMiddleware) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) (spaces []*spaces.Space, total int, err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.Find(ctx, filter, fo) +} + func (m *recoveringMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) { logger := m.logger defer func() { @@ -114,6 +127,18 @@ func (m *recoveringMiddleware) Move(ctx context.Context, spaceID string, orgID s return m.next.Move(ctx, spaceID, orgID) } +func (m *recoveringMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) { + logger := m.logger + defer func() { + if r := recover(); r != nil { + logger.Error("panic", zap.Error(fmt.Errorf("%v", r))) + err = fmt.Errorf("%v", r) + } + }() + + return m.next.SetState(ctx, spaceID, state) +} + func (m *recoveringMiddleware) Transfer(ctx context.Context, spaceID string, transferToOrg string) (err error) { logger := m.logger defer func() { diff --git a/pkg/spaces/middleware/telemetry_middleware.go b/pkg/spaces/middleware/telemetry_middleware.go index 90597815e8e7aa0a3a364c3e29aa208f3473d690..e9623692afe644e58cb1b406b4b06a3208edc710 100644 --- a/pkg/spaces/middleware/telemetry_middleware.go +++ b/pkg/spaces/middleware/telemetry_middleware.go @@ -1,10 +1,10 @@ // Code generated by gowrap. DO NOT EDIT. -// template: ..\..\..\assets\templates\middleware\telemetry +// template: ../../../assets/templates/middleware/telemetry // gowrap: http://github.com/hexdigest/gowrap package middleware -//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/spaces -i Spaces -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l "" +//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/spaces -i Spaces -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l "" // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry @@ -12,6 +12,7 @@ import ( "context" "time" + "git.perx.ru/perxis/perxis-go/pkg/options" "git.perx.ru/perxis/perxis-go/pkg/spaces" "git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics" "go.opentelemetry.io/otel" @@ -148,6 +149,42 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string) (err e return _d.Spaces.Delete(ctx, spaceId) } +// Find implements spaces.Spaces +func (_d telemetryMiddleware) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) (spaces []*spaces.Space, total int, err error) { + attributes := otelmetric.WithAttributeSet(attribute.NewSet( + attribute.String("service", "Spaces"), + attribute.String("method", "Find"), + )) + + _d.requestMetrics.Total.Add(ctx, 1, attributes) + + start := time.Now() + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Find") + + defer func() { + _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes) + + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "filter": filter, + "fo": fo}, map[string]interface{}{ + "spaces": spaces, + "total": total, + "err": err}) + } else if err != nil { + _d.requestMetrics.FailedTotal.Add(ctx, 1, attributes) + + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.Find(ctx, filter, fo) +} + // Get implements spaces.Spaces func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) { attributes := otelmetric.WithAttributeSet(attribute.NewSet( @@ -284,6 +321,40 @@ func (_d telemetryMiddleware) Move(ctx context.Context, spaceID string, orgID st return _d.Spaces.Move(ctx, spaceID, orgID) } +// SetState implements spaces.Spaces +func (_d telemetryMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) { + attributes := otelmetric.WithAttributeSet(attribute.NewSet( + attribute.String("service", "Spaces"), + attribute.String("method", "SetState"), + )) + + _d.requestMetrics.Total.Add(ctx, 1, attributes) + + start := time.Now() + ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.SetState") + + defer func() { + _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes) + + if _d._spanDecorator != nil { + _d._spanDecorator(_span, map[string]interface{}{ + "ctx": ctx, + "spaceID": spaceID, + "state": state}, map[string]interface{}{ + "err": err}) + } else if err != nil { + _d.requestMetrics.FailedTotal.Add(ctx, 1, attributes) + + _span.RecordError(err) + _span.SetAttributes(attribute.String("event", "error")) + _span.SetAttributes(attribute.String("message", err.Error())) + } + + _span.End() + }() + return _d.Spaces.SetState(ctx, spaceID, state) +} + // Transfer implements spaces.Spaces func (_d telemetryMiddleware) Transfer(ctx context.Context, spaceID string, transferToOrg string) (err error) { attributes := otelmetric.WithAttributeSet(attribute.NewSet( diff --git a/pkg/spaces/mocks/SpaceCreatedObserver.go b/pkg/spaces/mocks/SpaceCreatedObserver.go index a85eced793564cc3fc27304881486329041c3d75..049a741a757f5d107d347f826363eafeb29d85ac 100644 --- a/pkg/spaces/mocks/SpaceCreatedObserver.go +++ b/pkg/spaces/mocks/SpaceCreatedObserver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.40.3. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type SpaceCreatedObserver struct { func (_m *SpaceCreatedObserver) OnSpaceCreated(ctx context.Context, space *spaces.Space) error { ret := _m.Called(ctx, space) + if len(ret) == 0 { + panic("no return value specified for OnSpaceCreated") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { r0 = rf(ctx, space) @@ -28,13 +32,12 @@ func (_m *SpaceCreatedObserver) OnSpaceCreated(ctx context.Context, space *space return r0 } -type mockConstructorTestingTNewSpaceCreatedObserver interface { +// NewSpaceCreatedObserver creates a new instance of SpaceCreatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSpaceCreatedObserver(t interface { mock.TestingT Cleanup(func()) -} - -// NewSpaceCreatedObserver creates a new instance of SpaceCreatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSpaceCreatedObserver(t mockConstructorTestingTNewSpaceCreatedObserver) *SpaceCreatedObserver { +}) *SpaceCreatedObserver { mock := &SpaceCreatedObserver{} mock.Mock.Test(t) diff --git a/pkg/spaces/mocks/SpaceDeletedObserver.go b/pkg/spaces/mocks/SpaceDeletedObserver.go index 450173b03b0007c86b4dffee69a0c36522f9ce28..d4e65da6af20b85ab56159fcafed103f92b9c26b 100644 --- a/pkg/spaces/mocks/SpaceDeletedObserver.go +++ b/pkg/spaces/mocks/SpaceDeletedObserver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.40.3. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type SpaceDeletedObserver struct { func (_m *SpaceDeletedObserver) OnSpaceDeleted(ctx context.Context, space *spaces.Space) error { ret := _m.Called(ctx, space) + if len(ret) == 0 { + panic("no return value specified for OnSpaceDeleted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { r0 = rf(ctx, space) @@ -28,13 +32,12 @@ func (_m *SpaceDeletedObserver) OnSpaceDeleted(ctx context.Context, space *space return r0 } -type mockConstructorTestingTNewSpaceDeletedObserver interface { +// NewSpaceDeletedObserver creates a new instance of SpaceDeletedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSpaceDeletedObserver(t interface { mock.TestingT Cleanup(func()) -} - -// NewSpaceDeletedObserver creates a new instance of SpaceDeletedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSpaceDeletedObserver(t mockConstructorTestingTNewSpaceDeletedObserver) *SpaceDeletedObserver { +}) *SpaceDeletedObserver { mock := &SpaceDeletedObserver{} mock.Mock.Test(t) diff --git a/pkg/spaces/mocks/SpaceObserver.go b/pkg/spaces/mocks/SpaceObserver.go index 9c5006bf80047884f45637207d3ea6fdf0b702aa..589a7755a4cd86c025c816d652081e0597720d5e 100644 --- a/pkg/spaces/mocks/SpaceObserver.go +++ b/pkg/spaces/mocks/SpaceObserver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.40.3. DO NOT EDIT. package mocks @@ -9,13 +9,12 @@ type SpaceObserver struct { mock.Mock } -type mockConstructorTestingTNewSpaceObserver interface { +// NewSpaceObserver creates a new instance of SpaceObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSpaceObserver(t interface { mock.TestingT Cleanup(func()) -} - -// NewSpaceObserver creates a new instance of SpaceObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSpaceObserver(t mockConstructorTestingTNewSpaceObserver) *SpaceObserver { +}) *SpaceObserver { mock := &SpaceObserver{} mock.Mock.Test(t) diff --git a/pkg/spaces/mocks/SpaceUpdatedObserver.go b/pkg/spaces/mocks/SpaceUpdatedObserver.go index a7ced9b2d7bab0618013b5f73cef304c40cecb57..adfa9ea58992d08746ae6072743fe59a21a4bd10 100644 --- a/pkg/spaces/mocks/SpaceUpdatedObserver.go +++ b/pkg/spaces/mocks/SpaceUpdatedObserver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.40.3. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type SpaceUpdatedObserver struct { func (_m *SpaceUpdatedObserver) OnSpaceUpdated(ctx context.Context, before *spaces.Space, space *spaces.Space) error { ret := _m.Called(ctx, before, space) + if len(ret) == 0 { + panic("no return value specified for OnSpaceUpdated") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space, *spaces.Space) error); ok { r0 = rf(ctx, before, space) @@ -28,13 +32,12 @@ func (_m *SpaceUpdatedObserver) OnSpaceUpdated(ctx context.Context, before *spac return r0 } -type mockConstructorTestingTNewSpaceUpdatedObserver interface { +// NewSpaceUpdatedObserver creates a new instance of SpaceUpdatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSpaceUpdatedObserver(t interface { mock.TestingT Cleanup(func()) -} - -// NewSpaceUpdatedObserver creates a new instance of SpaceUpdatedObserver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSpaceUpdatedObserver(t mockConstructorTestingTNewSpaceUpdatedObserver) *SpaceUpdatedObserver { +}) *SpaceUpdatedObserver { mock := &SpaceUpdatedObserver{} mock.Mock.Test(t) diff --git a/pkg/spaces/mocks/Spaces.go b/pkg/spaces/mocks/Spaces.go index 0f7a187f31a572c96205427dae3438aac768c5e5..76121895f428dbcd8aa8117f4a8e376845d81e0b 100644 --- a/pkg/spaces/mocks/Spaces.go +++ b/pkg/spaces/mocks/Spaces.go @@ -1,12 +1,14 @@ -// Code generated by mockery v2.27.1. DO NOT EDIT. +// Code generated by mockery v2.40.3. DO NOT EDIT. package mocks import ( context "context" - spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" + options "git.perx.ru/perxis/perxis-go/pkg/options" mock "github.com/stretchr/testify/mock" + + spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" ) // Spaces is an autogenerated mock type for the Spaces type @@ -18,6 +20,10 @@ type Spaces struct { func (_m *Spaces) AbortTransfer(ctx context.Context, spaceID string) error { ret := _m.Called(ctx, spaceID) + if len(ret) == 0 { + panic("no return value specified for AbortTransfer") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { r0 = rf(ctx, spaceID) @@ -32,6 +38,10 @@ func (_m *Spaces) AbortTransfer(ctx context.Context, spaceID string) error { func (_m *Spaces) Create(ctx context.Context, space *spaces.Space) (*spaces.Space, error) { ret := _m.Called(ctx, space) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 *spaces.Space var r1 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) (*spaces.Space, error)); ok { @@ -58,6 +68,10 @@ func (_m *Spaces) Create(ctx context.Context, space *spaces.Space) (*spaces.Spac func (_m *Spaces) Delete(ctx context.Context, spaceId string) error { ret := _m.Called(ctx, spaceId) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { r0 = rf(ctx, spaceId) @@ -68,10 +82,51 @@ func (_m *Spaces) Delete(ctx context.Context, spaceId string) error { return r0 } +// Find provides a mock function with given fields: ctx, filter, fo +func (_m *Spaces) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) ([]*spaces.Space, int, error) { + ret := _m.Called(ctx, filter, fo) + + if len(ret) == 0 { + panic("no return value specified for Find") + } + + var r0 []*spaces.Space + var r1 int + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Filter, *options.FindOptions) ([]*spaces.Space, int, error)); ok { + return rf(ctx, filter, fo) + } + if rf, ok := ret.Get(0).(func(context.Context, *spaces.Filter, *options.FindOptions) []*spaces.Space); ok { + r0 = rf(ctx, filter, fo) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*spaces.Space) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *spaces.Filter, *options.FindOptions) int); ok { + r1 = rf(ctx, filter, fo) + } else { + r1 = ret.Get(1).(int) + } + + if rf, ok := ret.Get(2).(func(context.Context, *spaces.Filter, *options.FindOptions) error); ok { + r2 = rf(ctx, filter, fo) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // Get provides a mock function with given fields: ctx, spaceId func (_m *Spaces) Get(ctx context.Context, spaceId string) (*spaces.Space, error) { ret := _m.Called(ctx, spaceId) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *spaces.Space var r1 error if rf, ok := ret.Get(0).(func(context.Context, string) (*spaces.Space, error)); ok { @@ -98,6 +153,10 @@ func (_m *Spaces) Get(ctx context.Context, spaceId string) (*spaces.Space, error func (_m *Spaces) List(ctx context.Context, orgId string) ([]*spaces.Space, error) { ret := _m.Called(ctx, orgId) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []*spaces.Space var r1 error if rf, ok := ret.Get(0).(func(context.Context, string) ([]*spaces.Space, error)); ok { @@ -124,6 +183,10 @@ func (_m *Spaces) List(ctx context.Context, orgId string) ([]*spaces.Space, erro func (_m *Spaces) ListTransfers(ctx context.Context, orgID string) ([]*spaces.Space, error) { ret := _m.Called(ctx, orgID) + if len(ret) == 0 { + panic("no return value specified for ListTransfers") + } + var r0 []*spaces.Space var r1 error if rf, ok := ret.Get(0).(func(context.Context, string) ([]*spaces.Space, error)); ok { @@ -150,6 +213,10 @@ func (_m *Spaces) ListTransfers(ctx context.Context, orgID string) ([]*spaces.Sp func (_m *Spaces) Move(ctx context.Context, spaceID string, orgID string) error { ret := _m.Called(ctx, spaceID, orgID) + if len(ret) == 0 { + panic("no return value specified for Move") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { r0 = rf(ctx, spaceID, orgID) @@ -160,10 +227,32 @@ func (_m *Spaces) Move(ctx context.Context, spaceID string, orgID string) error return r0 } +// SetState provides a mock function with given fields: ctx, spaceID, state +func (_m *Spaces) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) error { + ret := _m.Called(ctx, spaceID, state) + + if len(ret) == 0 { + panic("no return value specified for SetState") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, *spaces.StateInfo) error); ok { + r0 = rf(ctx, spaceID, state) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Transfer provides a mock function with given fields: ctx, spaceID, transferToOrg func (_m *Spaces) Transfer(ctx context.Context, spaceID string, transferToOrg string) error { ret := _m.Called(ctx, spaceID, transferToOrg) + if len(ret) == 0 { + panic("no return value specified for Transfer") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { r0 = rf(ctx, spaceID, transferToOrg) @@ -178,6 +267,10 @@ func (_m *Spaces) Transfer(ctx context.Context, spaceID string, transferToOrg st func (_m *Spaces) Update(ctx context.Context, space *spaces.Space) error { ret := _m.Called(ctx, space) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { r0 = rf(ctx, space) @@ -192,6 +285,10 @@ func (_m *Spaces) Update(ctx context.Context, space *spaces.Space) error { func (_m *Spaces) UpdateConfig(ctx context.Context, spaceId string, config *spaces.Config) error { ret := _m.Called(ctx, spaceId, config) + if len(ret) == 0 { + panic("no return value specified for UpdateConfig") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *spaces.Config) error); ok { r0 = rf(ctx, spaceId, config) @@ -202,13 +299,12 @@ func (_m *Spaces) UpdateConfig(ctx context.Context, spaceId string, config *spac return r0 } -type mockConstructorTestingTNewSpaces interface { +// NewSpaces creates a new instance of Spaces. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSpaces(t interface { mock.TestingT Cleanup(func()) -} - -// NewSpaces creates a new instance of Spaces. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSpaces(t mockConstructorTestingTNewSpaces) *Spaces { +}) *Spaces { mock := &Spaces{} mock.Mock.Test(t) diff --git a/pkg/spaces/mocks/Storage.go b/pkg/spaces/mocks/Storage.go index 0f61e8c4d5796032d6e6103b070512dc8c5b87b7..078993cebec0cb2a5748c0d5bf1c50fb68d4def0 100644 --- a/pkg/spaces/mocks/Storage.go +++ b/pkg/spaces/mocks/Storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.27.1. DO NOT EDIT. +// Code generated by mockery v2.40.3. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type Storage struct { func (_m *Storage) Create(ctx context.Context, space *spaces.Space) error { ret := _m.Called(ctx, space) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Space) error); ok { r0 = rf(ctx, space) @@ -34,6 +38,10 @@ func (_m *Storage) Create(ctx context.Context, space *spaces.Space) error { func (_m *Storage) Delete(ctx context.Context, filter *spaces.Filter) (int, error) { ret := _m.Called(ctx, filter) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 int var r1 error if rf, ok := ret.Get(0).(func(context.Context, *spaces.Filter) (int, error)); ok { @@ -58,6 +66,10 @@ func (_m *Storage) Delete(ctx context.Context, filter *spaces.Filter) (int, erro func (_m *Storage) Find(ctx context.Context, filter *spaces.Filter, opts *options.FindOptions) ([]*spaces.Space, int, error) { ret := _m.Called(ctx, filter, opts) + if len(ret) == 0 { + panic("no return value specified for Find") + } + var r0 []*spaces.Space var r1 int var r2 error @@ -91,6 +103,10 @@ func (_m *Storage) Find(ctx context.Context, filter *spaces.Filter, opts *option func (_m *Storage) Init(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Init") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -105,6 +121,10 @@ func (_m *Storage) Init(ctx context.Context) error { func (_m *Storage) Reset(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Reset") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -119,6 +139,10 @@ func (_m *Storage) Reset(ctx context.Context) error { func (_m *Storage) Update(ctx context.Context, update *spaces.Space, filter *spaces.Filter) (int, int, error) { ret := _m.Called(ctx, update, filter) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 int var r1 int var r2 error @@ -146,13 +170,12 @@ func (_m *Storage) Update(ctx context.Context, update *spaces.Space, filter *spa return r0, r1, r2 } -type mockConstructorTestingTNewStorage interface { +// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewStorage(t interface { mock.TestingT Cleanup(func()) -} - -// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewStorage(t mockConstructorTestingTNewStorage) *Storage { +}) *Storage { mock := &Storage{} mock.Mock.Test(t) diff --git a/pkg/spaces/service.go b/pkg/spaces/service.go index 25d106407450fd111f88690c7de1a60f1670a09c..249221692684110e96c62fce37d70fc650d06945 100644 --- a/pkg/spaces/service.go +++ b/pkg/spaces/service.go @@ -2,11 +2,12 @@ package spaces import ( "context" + "slices" "time" - "github.com/avast/retry-go/v4" - "git.perx.ru/perxis/perxis-go/pkg/errors" + "git.perx.ru/perxis/perxis-go/pkg/options" + "github.com/avast/retry-go/v4" ) // @microgen grpc @@ -27,8 +28,12 @@ type Spaces interface { Create(ctx context.Context, space *Space) (created *Space, err error) Get(ctx context.Context, spaceId string) (space *Space, err error) List(ctx context.Context, orgId string) (spaces []*Space, err error) + Find(ctx context.Context, filter *Filter, fo *options.FindOptions) (spaces []*Space, total int, err error) Update(ctx context.Context, space *Space) (err error) UpdateConfig(ctx context.Context, spaceId string, config *Config) (err error) + + // @microgen - + SetState(ctx context.Context, spaceID string, state *StateInfo) (err error) Delete(ctx context.Context, spaceId string) (err error) // Transfer устанавливает для пространства значение поля RequestedMoveTo. После этого пространство @@ -62,17 +67,15 @@ var ( ErrSpaceNotAvailable = errors.New("space not available") ) -// IsSpaceAvailable проверяет доступность пространства для работы -// Если пространство находится в состоянии StateNew или StateReady, то оно доступно для работы func IsSpaceAvailable(ctx context.Context, svc Spaces, spaceID string) error { sp, err := svc.Get(ctx, spaceID) if err != nil { return errors.Wrap(err, "fail to get space") } - if sp.StateInfo == nil || sp.StateInfo != nil && (sp.StateInfo.State == StateNew || sp.StateInfo.State == StateReady) { + if sp.StateInfo == nil || slices.Contains(WriteAllowedStates, sp.StateInfo.State) { return nil } - return ErrSpaceNotAvailable + return errors.WithContext(ErrSpaceNotAvailable, "state", sp.StateInfo.State) } func IsSpaceReadable(ctx context.Context, svc Spaces, spaceID string) error { @@ -80,7 +83,7 @@ func IsSpaceReadable(ctx context.Context, svc Spaces, spaceID string) error { if err != nil { return errors.Wrap(err, "fail to get space") } - if sp.StateInfo == nil || sp.StateInfo != nil && sp.StateInfo.State == StateNew || sp.StateInfo.State == StateReady || sp.StateInfo.State == StateMigration { + if sp.StateInfo == nil || slices.Contains(ReadAllowedStates, sp.StateInfo.State) { return nil } return errors.WithContext(ErrSpaceNotAvailable, "state", sp.StateInfo.State) diff --git a/pkg/spaces/space.go b/pkg/spaces/space.go index 83edb3f14706793aed6077adcee856598358b044..baa44124b6830aa8c4f666f0300661952eadbc9d 100644 --- a/pkg/spaces/space.go +++ b/pkg/spaces/space.go @@ -10,13 +10,58 @@ const ( StateReady // Пространство готово к использованию StatePreparing // Пространство готовится в использованию StateMaintenance // Пространство находится на обслуживании - StateMigration // Пространство в состоянии выполнения миграций - StateDeleting // Пространство удаляется, данные будут удалены - StateError // Произошла ошибка при конфигурации пространства (см. Space.Error) + + // StateMigrationScheduled Для пространства запланирована миграция + // При планировании запуска миграции пространства это состояние выступает в роли Lock'а, который не + // позволяет запустить несколько миграций одновременно. Логика планировщика миграций сначала пытается + // установить для пространства состояние StateMigrationScheduled, что удается только в двух случаях: + // пространство находится в состоянии StateReady или же в состояниях StateMigration, StateMigrationScheduled, + // но последнее обновление состояния было более 15-ти минут назад + StateMigrationScheduled + StateMigration // Пространство в состоянии выполнения миграций + StateDeleting // Пространство удаляется, данные будут удалены + StateError // Произошла ошибка при конфигурации пространства (см. Space.Error) +) + +func (s State) String() string { + switch s { + case StateNew: + return "New" + case StateReady: + return "Ready" + case StatePreparing: + return "Preparing" + case StateMaintenance: + return "Maintenance" + case StateMigrationScheduled: + return "MigrationScheduled" + case StateMigration: + return "Migration" + case StateDeleting: + return "Deleting" + case StateError: + return "Error" + default: + return "Unknown" + } +} + +var ( + ReadAllowedStates = []State{ + StateNew, + StateReady, + StateMigrationScheduled, + StateMigration, + } + + WriteAllowedStates = []State{ + StateNew, + StateReady, + } ) type Config struct { - Features []string //Deprecated Возможности используемые пространством + Features []string // Deprecated Возможности используемые пространством } const StateInfoEmpty = "EMPTY" @@ -34,12 +79,12 @@ type Space struct { } type StateInfo struct { - State State `json:"state" bson:"state"` - Info string `json:"info" bson:"info"` + State State `json:"state" bson:"state,omitempty"` + Info string `json:"info" bson:"info,omitempty"` Time time.Time `json:"time,omitempty" bson:"time,omitempty"` - DBVersion uint32 `json:"db_version" bson:"db_version"` + DBVersion uint32 `json:"db_version" bson:"db_version,omitempty"` } func (s Space) Clone() *Space { return &s -} \ No newline at end of file +} diff --git a/pkg/spaces/storage.go b/pkg/spaces/storage.go index 798dd96bb859e31a6b49ca5a882918519c3e020f..a489c0b56104fdd47c479f1cd89a960f097f4d70 100644 --- a/pkg/spaces/storage.go +++ b/pkg/spaces/storage.go @@ -21,4 +21,5 @@ type Filter struct { Name []string `json:"name,omitempty" bson:"name"` State []State `json:"state,omitempty" bson:"state"` TransferToOrg []string `json:"transfer_to_org" bson:"transfer_to_org"` + Q []string `json:"q" bson:"q"` } diff --git a/pkg/spaces/transport/client.go b/pkg/spaces/transport/client.go index 26900dad00a30d5c685ce507626dd7d93d847c87..52a30a561eb51812831f15b26c1b1665691ee6d3 100644 --- a/pkg/spaces/transport/client.go +++ b/pkg/spaces/transport/client.go @@ -5,6 +5,7 @@ package transport import ( "context" + "git.perx.ru/perxis/perxis-go/pkg/options" spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" ) @@ -35,6 +36,15 @@ func (set EndpointsSet) List(arg0 context.Context, arg1 string) (res0 []*spaces. return response.(*ListResponse).Spaces, res1 } +func (set EndpointsSet) Find(arg0 context.Context, arg1 *spaces.Filter, arg2 *options.FindOptions) (res0 []*spaces.Space, res1 int, res2 error) { + request := FindRequest{Filter: arg1, Options: arg2} + response, res2 := set.FindEndpoint(arg0, &request) + if res2 != nil { + return + } + return response.(*FindResponse).Spaces, response.(*FindResponse).Total, res2 +} + func (set EndpointsSet) Update(arg0 context.Context, arg1 *spaces.Space) (res0 error) { request := UpdateRequest{Space: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) @@ -56,6 +66,10 @@ func (set EndpointsSet) UpdateConfig(arg0 context.Context, arg1 string, arg2 *sp return res0 } +func (set EndpointsSet) SetState(arg0 context.Context, arg1 string, arg2 *spaces.StateInfo) (res0 error) { + return +} + func (set EndpointsSet) Delete(arg0 context.Context, arg1 string) (res0 error) { request := DeleteRequest{SpaceId: arg1} _, res0 = set.DeleteEndpoint(arg0, &request) diff --git a/pkg/spaces/transport/endpoints.microgen.go b/pkg/spaces/transport/endpoints.microgen.go index 335f9ca4f52a6378f41563733e4b6f4f84b77d4c..8ab541ba98b0a4475addcd7e6e7dd4f7c1f2ed2d 100644 --- a/pkg/spaces/transport/endpoints.microgen.go +++ b/pkg/spaces/transport/endpoints.microgen.go @@ -9,6 +9,7 @@ type EndpointsSet struct { CreateEndpoint endpoint.Endpoint GetEndpoint endpoint.Endpoint ListEndpoint endpoint.Endpoint + FindEndpoint endpoint.Endpoint UpdateEndpoint endpoint.Endpoint UpdateConfigEndpoint endpoint.Endpoint DeleteEndpoint endpoint.Endpoint diff --git a/pkg/spaces/transport/exchanges.microgen.go b/pkg/spaces/transport/exchanges.microgen.go index 414ec9702c29fc0bef9fe84f728d1deaa816667a..5fe6cfbad14530dc543091ea0df0dc960f75a023 100644 --- a/pkg/spaces/transport/exchanges.microgen.go +++ b/pkg/spaces/transport/exchanges.microgen.go @@ -2,7 +2,10 @@ package transport -import spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" +import ( + "git.perx.ru/perxis/perxis-go/pkg/options" + spaces "git.perx.ru/perxis/perxis-go/pkg/spaces" +) type ( CreateRequest struct { @@ -26,6 +29,15 @@ type ( Spaces []*spaces.Space `json:"spaces"` } + FindRequest struct { + Filter *spaces.Filter `json:"filter"` + Options *options.FindOptions `json:"options"` + } + FindResponse struct { + Spaces []*spaces.Space `json:"spaces"` + Total int `json:"total"` + } + UpdateRequest struct { Space *spaces.Space `json:"space"` } diff --git a/pkg/spaces/transport/grpc/client.go b/pkg/spaces/transport/grpc/client.go index 67e3f4019f1b1351d9985403ed39f17912913625..a4c431a7d80e0953a46fb9e7048ef63fa8f31a93 100644 --- a/pkg/spaces/transport/grpc/client.go +++ b/pkg/spaces/transport/grpc/client.go @@ -15,6 +15,7 @@ func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.En CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), ListEndpoint: grpcerr.ClientMiddleware(c.ListEndpoint), + FindEndpoint: grpcerr.ClientMiddleware(c.FindEndpoint), UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), UpdateConfigEndpoint: grpcerr.ClientMiddleware(c.UpdateConfigEndpoint), DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), diff --git a/pkg/spaces/transport/grpc/client.microgen.go b/pkg/spaces/transport/grpc/client.microgen.go index 9a92bde894407be7520aa0f27a2112c5f4294cf0..1e7095cd261f03111fafaafc361ca49b7f12cb70 100644 --- a/pkg/spaces/transport/grpc/client.microgen.go +++ b/pkg/spaces/transport/grpc/client.microgen.go @@ -50,6 +50,13 @@ func NewGRPCClient(conn *grpc.ClientConn, addr string, opts ...grpckit.ClientOpt pb.ListResponse{}, opts..., ).Endpoint(), + FindEndpoint: grpckit.NewClient( + conn, addr, "Find", + _Encode_Find_Request, + _Decode_Find_Response, + pb.FindResponse{}, + opts..., + ).Endpoint(), ListTransfersEndpoint: grpckit.NewClient( conn, addr, "ListTransfers", _Encode_ListTransfers_Request, diff --git a/pkg/spaces/transport/grpc/protobuf_endpoint_converters.microgen.go b/pkg/spaces/transport/grpc/protobuf_endpoint_converters.microgen.go index efe05ac83e9006e3d8345d25beca40fa0f4187ac..6797cc200801de828c8cefe14c085280188a6a75 100644 --- a/pkg/spaces/transport/grpc/protobuf_endpoint_converters.microgen.go +++ b/pkg/spaces/transport/grpc/protobuf_endpoint_converters.microgen.go @@ -7,6 +7,7 @@ import ( "context" "errors" + transportgrpc "git.perx.ru/perxis/perxis-go/pkg/items/transport/grpc" transport "git.perx.ru/perxis/perxis-go/pkg/spaces/transport" pb "git.perx.ru/perxis/perxis-go/proto/spaces" empty "google.golang.org/protobuf/types/known/emptypb" @@ -40,6 +41,22 @@ func _Encode_List_Request(ctx context.Context, request interface{}) (interface{} return &pb.ListRequest{OrgId: req.OrgId}, nil } +func _Encode_Find_Request(ctx context.Context, request interface{}) (interface{}, error) { + if request == nil { + return nil, errors.New("nil FindRequest") + } + req := request.(*transport.FindRequest) + reqFilter, err := SpaceFilterToProto(req.Filter) + if err != nil { + return nil, err + } + reqOptions, err := transportgrpc.PtrServicesFindOptionsToProto(req.Options) + if err != nil { + return nil, err + } + return &pb.FindRequest{Filter: reqFilter, Options: reqOptions}, nil +} + func _Encode_Update_Request(ctx context.Context, request interface{}) (interface{}, error) { if request == nil { return nil, errors.New("nil UpdateRequest") @@ -111,6 +128,18 @@ func _Encode_List_Response(ctx context.Context, response interface{}) (interface return &pb.ListResponse{Spaces: respSpaces}, nil } +func _Encode_Find_Response(ctx context.Context, response interface{}) (interface{}, error) { + if response == nil { + return nil, errors.New("nil FindResponse") + } + resp := response.(*transport.FindResponse) + respSpaces, err := ListPtrSpaceToProto(resp.Spaces) + if err != nil { + return nil, err + } + return &pb.FindResponse{Spaces: respSpaces, Total: int32(resp.Total)}, nil +} + func _Encode_Update_Response(ctx context.Context, response interface{}) (interface{}, error) { return &empty.Empty{}, nil } @@ -151,6 +180,24 @@ func _Decode_List_Request(ctx context.Context, request interface{}) (interface{} return &transport.ListRequest{OrgId: string(req.OrgId)}, nil } +func _Decode_Find_Request(ctx context.Context, request interface{}) (interface{}, error) { + if request == nil { + return nil, errors.New("nil FindRequest") + } + req := request.(*pb.FindRequest) + + opts, err := transportgrpc.ProtoToPtrServicesFindOptions(req.Options) + if err != nil { + return nil, err + } + filter, err := ProtoToPtrSpaceFilter(req.Filter) + if err != nil { + return nil, err + } + + return &transport.FindRequest{Filter: filter, Options: opts}, nil +} + func _Decode_Update_Request(ctx context.Context, request interface{}) (interface{}, error) { if request == nil { return nil, errors.New("nil UpdateRequest") @@ -222,6 +269,18 @@ func _Decode_List_Response(ctx context.Context, response interface{}) (interface return &transport.ListResponse{Spaces: respSpaces}, nil } +func _Decode_Find_Response(ctx context.Context, response interface{}) (interface{}, error) { + if response == nil { + return nil, errors.New("nil FindResponse") + } + resp := response.(*pb.FindResponse) + respSpaces, err := ProtoToListPtrSpace(resp.Spaces) + if err != nil { + return nil, err + } + return &transport.FindResponse{Spaces: respSpaces, Total: int(resp.Total)}, nil +} + func _Decode_Update_Response(ctx context.Context, response interface{}) (interface{}, error) { return &empty.Empty{}, nil } diff --git a/pkg/spaces/transport/grpc/protobuf_type_converters.microgen.go b/pkg/spaces/transport/grpc/protobuf_type_converters.microgen.go index 70081af310c72b62f2cc1a7ac0bc32fed007ac60..d7231bdba357885b1506b3f5d2301149feb8cd5a 100644 --- a/pkg/spaces/transport/grpc/protobuf_type_converters.microgen.go +++ b/pkg/spaces/transport/grpc/protobuf_type_converters.microgen.go @@ -108,3 +108,41 @@ func ProtoToListPtrSpace(protoSpaces []*pb.Space) ([]*service.Space, error) { } return spaces, nil } + +func ProtoToPtrSpaceFilter(protoSpaceFilter *pb.Filter) (*service.Filter, error) { + if protoSpaceFilter == nil { + return nil, nil + } + var srvState []service.State + if len(protoSpaceFilter.State) != 0 { + for _, state := range protoSpaceFilter.State { + srvState = append(srvState, service.State(state)) + } + } + return &service.Filter{ + ID: protoSpaceFilter.Id, + OrgID: protoSpaceFilter.OrgId, + Name: protoSpaceFilter.Name, + State: srvState, + TransferToOrg: protoSpaceFilter.TransferToOrg, + }, nil +} + +func SpaceFilterToProto(spaceFilter *service.Filter) (*pb.Filter, error) { + if spaceFilter == nil { + return nil, nil + } + var pbState []pb.State + if len(spaceFilter.State) != 0 { + for _, state := range spaceFilter.State { + pbState = append(pbState, pb.State(state)) + } + } + return &pb.Filter{ + Id: spaceFilter.ID, + OrgId: spaceFilter.OrgID, + Name: spaceFilter.Name, + State: pbState, + TransferToOrg: spaceFilter.TransferToOrg, + }, nil +} diff --git a/pkg/spaces/transport/grpc/server.go b/pkg/spaces/transport/grpc/server.go index 8819d2a3637ae8bc1b3820b1e8cb110580a9b37f..01574994044d527046ad6f33ac631c37bbb03e1f 100644 --- a/pkg/spaces/transport/grpc/server.go +++ b/pkg/spaces/transport/grpc/server.go @@ -14,6 +14,7 @@ func NewServer(svc spaces.Spaces, opts ...grpckit.ServerOption) pb.SpacesServer CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), ListEndpoint: grpcerr.ServerMiddleware(eps.ListEndpoint), + FindEndpoint: grpcerr.ServerMiddleware(eps.FindEndpoint), UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), UpdateConfigEndpoint: grpcerr.ServerMiddleware(eps.UpdateConfigEndpoint), DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), diff --git a/pkg/spaces/transport/grpc/server.microgen.go b/pkg/spaces/transport/grpc/server.microgen.go index bf33dbbeea79339df43617ab97f460ca27d927b4..2a39455033e628b9ac7766b6057575793e2f8f6c 100644 --- a/pkg/spaces/transport/grpc/server.microgen.go +++ b/pkg/spaces/transport/grpc/server.microgen.go @@ -15,6 +15,7 @@ type spacesServer struct { create grpc.Handler get grpc.Handler list grpc.Handler + find grpc.Handler update grpc.Handler updateConfig grpc.Handler delete grpc.Handler @@ -58,6 +59,12 @@ func NewGRPCServer(endpoints *transport.EndpointsSet, opts ...grpc.ServerOption) _Encode_List_Response, opts..., ), + find: grpc.NewServer( + endpoints.FindEndpoint, + _Decode_Find_Request, + _Encode_Find_Response, + opts..., + ), listTransfers: grpc.NewServer( endpoints.ListTransfersEndpoint, _Decode_ListTransfers_Request, @@ -115,6 +122,14 @@ func (S *spacesServer) List(ctx context.Context, req *pb.ListRequest) (*pb.ListR return resp.(*pb.ListResponse), nil } +func (S *spacesServer) Find(ctx context.Context, req *pb.FindRequest) (*pb.FindResponse, error) { + _, resp, err := S.find.ServeGRPC(ctx, req) + if err != nil { + return nil, err + } + return resp.(*pb.FindResponse), nil +} + func (S *spacesServer) Update(ctx context.Context, req *pb.UpdateRequest) (*empty.Empty, error) { _, resp, err := S.update.ServeGRPC(ctx, req) if err != nil { diff --git a/pkg/spaces/transport/server.microgen.go b/pkg/spaces/transport/server.microgen.go index 60a07de0bf59846a2695f3c7625b3565044e823b..ece65a8fefe877cb031a9dc7854c141d3545d8fe 100644 --- a/pkg/spaces/transport/server.microgen.go +++ b/pkg/spaces/transport/server.microgen.go @@ -16,6 +16,7 @@ func Endpoints(svc spaces.Spaces) EndpointsSet { DeleteEndpoint: DeleteEndpoint(svc), GetEndpoint: GetEndpoint(svc), ListEndpoint: ListEndpoint(svc), + FindEndpoint: FindEndpoint(svc), ListTransfersEndpoint: ListTransfersEndpoint(svc), MoveEndpoint: MoveEndpoint(svc), TransferEndpoint: TransferEndpoint(svc), @@ -48,6 +49,14 @@ func ListEndpoint(svc spaces.Spaces) endpoint.Endpoint { } } +func FindEndpoint(svc spaces.Spaces) endpoint.Endpoint { + return func(arg0 context.Context, request interface{}) (interface{}, error) { + req := request.(*FindRequest) + res0, res1, res2 := svc.Find(arg0, req.Filter, req.Options) + return &FindResponse{Spaces: res0, Total: res1}, res2 + } +} + func UpdateEndpoint(svc spaces.Spaces) endpoint.Endpoint { return func(arg0 context.Context, request interface{}) (interface{}, error) { req := request.(*UpdateRequest) diff --git a/pkg/users/events.go b/pkg/users/events.go new file mode 100644 index 0000000000000000000000000000000000000000..c262c017afe6146e1b7c91e031d5575c381c3cc6 --- /dev/null +++ b/pkg/users/events.go @@ -0,0 +1,7 @@ +package users + +const ( + EventCreate = "users.create" + EventUpdate = "users.update" + EventDelete = "users.delete" +) diff --git a/pkg/users/middleware/caching_middleware.go b/pkg/users/middleware/caching_middleware.go index 8397bfd3a5c2a02c9ff52c42f9d1e23d431aed8e..825da6a28caabeee0f71d9030b60c8152e884570 100644 --- a/pkg/users/middleware/caching_middleware.go +++ b/pkg/users/middleware/caching_middleware.go @@ -30,16 +30,17 @@ func (m cachingMiddleware) Get(ctx context.Context, userId string) (user *servic value, e := m.cache.Get(userId) if e == nil { - return value.(*service.User), err + return value.(*service.User).Clone(), nil } user, err = m.next.Get(ctx, userId) if err == nil { - m.cache.Set(user.ID, user) + _ = m.cache.Set(user.ID, user) for _, i := range user.Identities { - m.cache.Set(i, user) + _ = m.cache.Set(i, user) } + return user.Clone(), nil } - return user, err + return nil, err } func (m cachingMiddleware) Find(ctx context.Context, filter *service.Filter, options *services.FindOptions) (users []*service.User, total int, err error) { @@ -52,9 +53,9 @@ func (m cachingMiddleware) Update(ctx context.Context, update *service.User) (er value, e := m.cache.Get(update.ID) if err == nil && e == nil { usr := value.(*service.User) - m.cache.Remove(usr.ID) + _ = m.cache.Remove(usr.ID) for _, i := range usr.Identities { - m.cache.Remove(i) + _ = m.cache.Remove(i) } } return err @@ -66,9 +67,9 @@ func (m cachingMiddleware) Delete(ctx context.Context, userId string) (err error value, e := m.cache.Get(userId) if err == nil && e == nil { usr := value.(*service.User) - m.cache.Remove(usr.ID) + _ = m.cache.Remove(usr.ID) for _, i := range usr.Identities { - m.cache.Remove(i) + _ = m.cache.Remove(i) } } return err @@ -78,14 +79,15 @@ func (m cachingMiddleware) GetByIdentity(ctx context.Context, identity string) ( value, e := m.cache.Get(identity) if e == nil { - return value.(*service.User), err + return value.(*service.User).Clone(), nil } user, err = m.next.GetByIdentity(ctx, identity) if err == nil { - m.cache.Set(user.ID, user) + _ = m.cache.Set(user.ID, user) for _, i := range user.Identities { - m.cache.Set(i, user) + _ = m.cache.Set(i, user) } + return user.Clone(), nil } - return user, err + return nil, err } diff --git a/pkg/users/middleware/caching_middleware_test.go b/pkg/users/middleware/caching_middleware_test.go index edc9176baac6656a1d70995b0881055b83642293..c5755407c6ffbc163f86ed548ad4b50c5d8bfc94 100644 --- a/pkg/users/middleware/caching_middleware_test.go +++ b/pkg/users/middleware/caching_middleware_test.go @@ -38,11 +38,13 @@ func TestUsersCache(t *testing.T) { v2, err := svc.Get(ctx, userID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.GetByIdentity(ctx, identity) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша при запросе по Identity.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша при запросе по Identity.") + assert.NotSame(t, v2, v3) usrs.AssertExpectations(t) }) @@ -60,11 +62,13 @@ func TestUsersCache(t *testing.T) { v2, err := svc.GetByIdentity(ctx, identity) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) v3, err := svc.Get(ctx, userID) require.NoError(t, err) - assert.Same(t, v2, v3, "Ожидается получение объекта из кэша при запросе по userID.") + assert.Equal(t, v2, v3, "Ожидается получение объекта из кэша при запросе по userID.") + assert.NotSame(t, v2, v3) usrs.AssertExpectations(t) }) @@ -84,7 +88,8 @@ func TestUsersCache(t *testing.T) { v2, err := svc.GetByIdentity(ctx, identity) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) err = svc.Update(ctx, &users.User{ID: userID, Name: "New User", Identities: []string{identity}}) require.NoError(t, err) @@ -93,12 +98,13 @@ func TestUsersCache(t *testing.T) { v3, err := svc.GetByIdentity(ctx, identity) require.NoError(t, err) - assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кеша после обновления и получение его заново из сервиса.") + assert.NotEqual(t, v3, v2, "Ожидается удаление объекта из кеша после обновления и получение его заново из сервиса.") v4, err := svc.Get(ctx, userID) require.NoError(t, err) - assert.NotSame(t, v4, v2) - assert.Same(t, v4, v3, "Ожидается получение нового обьекта из кеша.") + assert.NotEqual(t, v4, v2) + assert.Equal(t, v4, v3, "Ожидается получение нового обьекта из кеша.") + assert.NotSame(t, v4, v3) usrs.AssertExpectations(t) }) @@ -117,7 +123,8 @@ func TestUsersCache(t *testing.T) { v2, err := svc.GetByIdentity(ctx, identity) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) err = svc.Delete(ctx, userID) require.NoError(t, err) @@ -149,7 +156,8 @@ func TestUsersCache(t *testing.T) { v2, err := svc.Get(ctx, userID) require.NoError(t, err) - assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.Equal(t, v1, v2, "Ожидается получение объекта из кэша.") + assert.NotSame(t, v1, v2) time.Sleep(2 * ttl) @@ -158,6 +166,8 @@ func TestUsersCache(t *testing.T) { v3, err := svc.Get(ctx, userID) require.NoError(t, err) assert.NotSame(t, v2, v3, "Ожидается получение объекта из кэша при запросе по Identity.") + assert.Equal(t, v2, v3) + assert.NotSame(t, v2, v3) usrs.AssertExpectations(t) }) diff --git a/pkg/users/middleware/logging_middleware.go b/pkg/users/middleware/logging_middleware.go new file mode 100644 index 0000000000000000000000000000000000000000..3350d36d87b5715c043455428cc6e4aa0c0f981d --- /dev/null +++ b/pkg/users/middleware/logging_middleware.go @@ -0,0 +1,121 @@ +package middleware + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/id" + "git.perx.ru/perxis/perxis-go/pkg/options" + "git.perx.ru/perxis/perxis-go/pkg/users" + logzap "git.perx.ru/perxis/perxis-go/zap" + "go.uber.org/zap" +) + +type loggingMiddleware struct { + logger *zap.Logger + next users.Users +} + +func LoggingMiddleware(logger *zap.Logger) Middleware { + return func(next users.Users) users.Users { + return &loggingMiddleware{ + next: next, + logger: logger.With(logzap.Component("Users")), + } + } +} + +func (m *loggingMiddleware) Create(ctx context.Context, create *users.User) (user *users.User, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(users.EventCreate), + ) + + user, err = m.next.Create(ctx, create) + if err != nil { + logger.Error("Failed to create", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog), logzap.Object(user)) + return + } + + logger.Info("User created", logzap.Channels(logzap.Userlog), logzap.Object(user)) + + return user, err +} + +func (m *loggingMiddleware) Get(ctx context.Context, userId string) (user *users.User, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewUserId(userId)), + ) + + user, err = m.next.Get(ctx, userId) + if err != nil { + logger.Error("Failed to get", zap.Error(err)) + return + } + + return user, err +} + +func (m *loggingMiddleware) Find(ctx context.Context, filter *users.Filter, options *options.FindOptions) (found []*users.User, total int, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + ) + + found, total, err = m.next.Find(ctx, filter, options) + if err != nil { + logger.Error("Failed to find", zap.Error(err)) + return + } + + return found, total, err +} + +func (m *loggingMiddleware) Update(ctx context.Context, update *users.User) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(users.EventUpdate), + logzap.Object(update), + ) + + err = m.next.Update(ctx, update) + if err != nil { + logger.Error("Failed to update", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("User updated", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) Delete(ctx context.Context, userId string) (err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Event(users.EventDelete), + logzap.Object(id.NewUserId(userId)), + ) + + err = m.next.Delete(ctx, userId) + if err != nil { + logger.Error("Failed to delete", zap.Error(err), logzap.Channels(logzap.Userlog, logzap.Syslog)) + return + } + + logger.Info("User deleted", logzap.Channels(logzap.Userlog)) + + return err +} + +func (m *loggingMiddleware) GetByIdentity(ctx context.Context, identity string) (user *users.User, err error) { + logger := m.logger.With( + logzap.Caller(ctx), + logzap.Object(id.NewUserId(identity)), + ) + + user, err = m.next.GetByIdentity(ctx, identity) + if err != nil { + logger.Error("Failed to get by identity", zap.Error(err)) + return + } + return user, err +} diff --git a/pkg/users/middleware/middleware.go b/pkg/users/middleware/middleware.go index d94190827de3028c96000df15bf06c719e30cf92..ed64ceeddae0ab089c1746356ece1d85a0c69e83 100644 --- a/pkg/users/middleware/middleware.go +++ b/pkg/users/middleware/middleware.go @@ -21,7 +21,7 @@ func WithLog(s users.Users, logger *zap.Logger, log_access bool) users.Users { if log_access { s = AccessLoggingMiddleware(logger)(s) } - s = ErrorLoggingMiddleware(logger)(s) + s = LoggingMiddleware(logger)(s) s = RecoveringMiddleware(logger)(s) return s diff --git a/pkg/users/transport/client.microgen.go b/pkg/users/transport/client.go similarity index 66% rename from pkg/users/transport/client.microgen.go rename to pkg/users/transport/client.go index 74ca261a3bc5ec1cf99c655c82ec5b0345489ce3..01537b1123040311fcd9fb036c8765066d2f65b1 100644 --- a/pkg/users/transport/client.microgen.go +++ b/pkg/users/transport/client.go @@ -4,21 +4,15 @@ package transport import ( "context" - "errors" options "git.perx.ru/perxis/perxis-go/pkg/options" users "git.perx.ru/perxis/perxis-go/pkg/users" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) func (set EndpointsSet) Create(arg0 context.Context, arg1 *users.User) (res0 *users.User, res1 error) { request := CreateRequest{Create: arg1} response, res1 := set.CreateEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*CreateResponse).User, res1 @@ -28,9 +22,6 @@ func (set EndpointsSet) Get(arg0 context.Context, arg1 string) (res0 *users.User request := GetRequest{UserId: arg1} response, res1 := set.GetEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetResponse).User, res1 @@ -43,9 +34,6 @@ func (set EndpointsSet) Find(arg0 context.Context, arg1 *users.Filter, arg2 *opt } response, res2 := set.FindEndpoint(arg0, &request) if res2 != nil { - if e, ok := status.FromError(res2); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res2 = errors.New(e.Message()) - } return } return response.(*FindResponse).Users, response.(*FindResponse).Total, res2 @@ -55,9 +43,6 @@ func (set EndpointsSet) Update(arg0 context.Context, arg1 *users.User) (res0 err request := UpdateRequest{Update: arg1} _, res0 = set.UpdateEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -67,9 +52,6 @@ func (set EndpointsSet) Delete(arg0 context.Context, arg1 string) (res0 error) { request := DeleteRequest{UserId: arg1} _, res0 = set.DeleteEndpoint(arg0, &request) if res0 != nil { - if e, ok := status.FromError(res0); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res0 = errors.New(e.Message()) - } return } return res0 @@ -79,9 +61,6 @@ func (set EndpointsSet) GetByIdentity(arg0 context.Context, arg1 string) (res0 * request := GetByIdentityRequest{Identity: arg1} response, res1 := set.GetByIdentityEndpoint(arg0, &request) if res1 != nil { - if e, ok := status.FromError(res1); ok || e.Code() == codes.Internal || e.Code() == codes.Unknown { - res1 = errors.New(e.Message()) - } return } return response.(*GetByIdentityResponse).User, res1 diff --git a/pkg/users/transport/grpc/client.go b/pkg/users/transport/grpc/client.go new file mode 100644 index 0000000000000000000000000000000000000000..7364d5fce73a58580ed59bd71539bab3a1e68668 --- /dev/null +++ b/pkg/users/transport/grpc/client.go @@ -0,0 +1,22 @@ +// Code generated by microgen 0.9.1. DO NOT EDIT. + +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + transport "git.perx.ru/perxis/perxis-go/pkg/users/transport" + grpckit "github.com/go-kit/kit/transport/grpc" + grpc "google.golang.org/grpc" +) + +func NewClient(conn *grpc.ClientConn, opts ...grpckit.ClientOption) transport.EndpointsSet { + c := NewGRPCClient(conn, "", opts...) + return transport.EndpointsSet{ + CreateEndpoint: grpcerr.ClientMiddleware(c.CreateEndpoint), + DeleteEndpoint: grpcerr.ClientMiddleware(c.DeleteEndpoint), + FindEndpoint: grpcerr.ClientMiddleware(c.FindEndpoint), + GetByIdentityEndpoint: grpcerr.ClientMiddleware(c.GetByIdentityEndpoint), + GetEndpoint: grpcerr.ClientMiddleware(c.GetEndpoint), + UpdateEndpoint: grpcerr.ClientMiddleware(c.UpdateEndpoint), + } +} diff --git a/pkg/users/transport/grpc/server.go b/pkg/users/transport/grpc/server.go new file mode 100644 index 0000000000000000000000000000000000000000..07211008e3d631e1c23a658a31fa67f8f983a058 --- /dev/null +++ b/pkg/users/transport/grpc/server.go @@ -0,0 +1,22 @@ +package transportgrpc + +import ( + grpcerr "git.perx.ru/perxis/perxis-go/pkg/errors/grpc" + "git.perx.ru/perxis/perxis-go/pkg/users" + "git.perx.ru/perxis/perxis-go/pkg/users/transport" + pb "git.perx.ru/perxis/perxis-go/proto/users" + grpckit "github.com/go-kit/kit/transport/grpc" +) + +func NewServer(svc users.Users, opts ...grpckit.ServerOption) pb.UsersServer { + eps := transport.Endpoints(svc) + eps = transport.EndpointsSet{ + CreateEndpoint: grpcerr.ServerMiddleware(eps.CreateEndpoint), + DeleteEndpoint: grpcerr.ServerMiddleware(eps.DeleteEndpoint), + FindEndpoint: grpcerr.ServerMiddleware(eps.FindEndpoint), + GetByIdentityEndpoint: grpcerr.ServerMiddleware(eps.GetByIdentityEndpoint), + GetEndpoint: grpcerr.ServerMiddleware(eps.GetEndpoint), + UpdateEndpoint: grpcerr.ServerMiddleware(eps.UpdateEndpoint), + } + return NewGRPCServer(&eps, opts...) +} diff --git a/proto/clients/clients.pb.go b/proto/clients/clients.pb.go index a492dbad2bd2bfa0dd320e869f28f9b1ea5146fd..250cdd86d74dd1bf53f58b9c56109e270b25443f 100644 --- a/proto/clients/clients.pb.go +++ b/proto/clients/clients.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: clients/clients.proto package clients @@ -1026,7 +1026,7 @@ func file_clients_clients_proto_rawDescGZIP() []byte { } var file_clients_clients_proto_msgTypes = make([]protoimpl.MessageInfo, 15) -var file_clients_clients_proto_goTypes = []interface{}{ +var file_clients_clients_proto_goTypes = []any{ (*Client)(nil), // 0: content.clients.Client (*CreateRequest)(nil), // 1: content.clients.CreateRequest (*CreateResponse)(nil), // 2: content.clients.CreateResponse @@ -1081,7 +1081,7 @@ func file_clients_clients_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_clients_clients_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Client); i { case 0: return &v.state @@ -1093,7 +1093,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -1105,7 +1105,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -1117,7 +1117,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -1129,7 +1129,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -1141,7 +1141,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*GetByRequest); i { case 0: return &v.state @@ -1153,7 +1153,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*GetByResponse); i { case 0: return &v.state @@ -1165,7 +1165,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1177,7 +1177,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ListRequest); i { case 0: return &v.state @@ -1189,7 +1189,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*ListResponse); i { case 0: return &v.state @@ -1201,7 +1201,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -1213,7 +1213,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*EnableRequest); i { case 0: return &v.state @@ -1225,7 +1225,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*Client_OAuth); i { case 0: return &v.state @@ -1237,7 +1237,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*Client_APIKey); i { case 0: return &v.state @@ -1249,7 +1249,7 @@ func file_clients_clients_proto_init() { return nil } } - file_clients_clients_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_clients_clients_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*Client_TLS); i { case 0: return &v.state @@ -1262,7 +1262,7 @@ func file_clients_clients_proto_init() { } } } - file_clients_clients_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_clients_clients_proto_msgTypes[0].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/proto/clients/clients_grpc.pb.go b/proto/clients/clients_grpc.pb.go index f8fdf0cda264fa6e99aa20ecf495050dc1231fc7..b2e006de4d8bed8870a7094a63fafde21cff5e5c 100644 --- a/proto/clients/clients_grpc.pb.go +++ b/proto/clients/clients_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: clients/clients.proto package clients @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Clients_Create_FullMethodName = "/content.clients.Clients/Create" @@ -58,8 +58,9 @@ func NewClientsClient(cc grpc.ClientConnInterface) ClientsClient { } func (c *clientsClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Clients_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -67,8 +68,9 @@ func (c *clientsClient) Create(ctx context.Context, in *CreateRequest, opts ...g } func (c *clientsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Clients_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -76,8 +78,9 @@ func (c *clientsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Ca } func (c *clientsClient) GetBy(ctx context.Context, in *GetByRequest, opts ...grpc.CallOption) (*GetByResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetByResponse) - err := c.cc.Invoke(ctx, Clients_GetBy_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_GetBy_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -85,8 +88,9 @@ func (c *clientsClient) GetBy(ctx context.Context, in *GetByRequest, opts ...grp } func (c *clientsClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Clients_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -94,8 +98,9 @@ func (c *clientsClient) Update(ctx context.Context, in *UpdateRequest, opts ...g } func (c *clientsClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListResponse) - err := c.cc.Invoke(ctx, Clients_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_List_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -103,8 +108,9 @@ func (c *clientsClient) List(ctx context.Context, in *ListRequest, opts ...grpc. } func (c *clientsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Clients_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -112,8 +118,9 @@ func (c *clientsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...g } func (c *clientsClient) Enable(ctx context.Context, in *EnableRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Clients_Enable_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Clients_Enable_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -122,7 +129,7 @@ func (c *clientsClient) Enable(ctx context.Context, in *EnableRequest, opts ...g // ClientsServer is the server API for Clients service. // All implementations must embed UnimplementedClientsServer -// for forward compatibility +// for forward compatibility. type ClientsServer interface { // Create - создает клиента (приложение) для работы с API Create(context.Context, *CreateRequest) (*CreateResponse, error) @@ -141,9 +148,12 @@ type ClientsServer interface { mustEmbedUnimplementedClientsServer() } -// UnimplementedClientsServer must be embedded to have forward compatible implementations. -type UnimplementedClientsServer struct { -} +// UnimplementedClientsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedClientsServer struct{} func (UnimplementedClientsServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -167,6 +177,7 @@ func (UnimplementedClientsServer) Enable(context.Context, *EnableRequest) (*empt return nil, status.Errorf(codes.Unimplemented, "method Enable not implemented") } func (UnimplementedClientsServer) mustEmbedUnimplementedClientsServer() {} +func (UnimplementedClientsServer) testEmbeddedByValue() {} // UnsafeClientsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ClientsServer will @@ -176,6 +187,13 @@ type UnsafeClientsServer interface { } func RegisterClientsServer(s grpc.ServiceRegistrar, srv ClientsServer) { + // If the following call pancis, it indicates UnimplementedClientsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Clients_ServiceDesc, srv) } diff --git a/proto/collaborators/collaborators.pb.go b/proto/collaborators/collaborators.pb.go index e07247b5dce02708390f23a576462dcb965b772d..bb3aad637b6f28510d386714eac5698a6451d484 100644 --- a/proto/collaborators/collaborators.pb.go +++ b/proto/collaborators/collaborators.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: collaborators/collaborators.proto package collaborators @@ -521,7 +521,7 @@ func file_collaborators_collaborators_proto_rawDescGZIP() []byte { } var file_collaborators_collaborators_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_collaborators_collaborators_proto_goTypes = []interface{}{ +var file_collaborators_collaborators_proto_goTypes = []any{ (*SetRequest)(nil), // 0: content.collaborators.SetRequest (*GetRequest)(nil), // 1: content.collaborators.GetRequest (*GetResponse)(nil), // 2: content.collaborators.GetResponse @@ -559,7 +559,7 @@ func file_collaborators_collaborators_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_collaborators_collaborators_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*SetRequest); i { case 0: return &v.state @@ -571,7 +571,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -583,7 +583,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -595,7 +595,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*RemoveRequest); i { case 0: return &v.state @@ -607,7 +607,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*ListCollaboratorsRequest); i { case 0: return &v.state @@ -619,7 +619,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ListCollaboratorsResponse); i { case 0: return &v.state @@ -631,7 +631,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ListSpacesRequest); i { case 0: return &v.state @@ -643,7 +643,7 @@ func file_collaborators_collaborators_proto_init() { return nil } } - file_collaborators_collaborators_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_collaborators_collaborators_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ListSpacesResponse); i { case 0: return &v.state diff --git a/proto/collaborators/collaborators_grpc.pb.go b/proto/collaborators/collaborators_grpc.pb.go index 47ff522c1b57c72665fbca4741f698e6bb97b80f..85262442d0f9389cbb258cca420b8eb757b5df1f 100644 --- a/proto/collaborators/collaborators_grpc.pb.go +++ b/proto/collaborators/collaborators_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: collaborators/collaborators.proto package collaborators @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Collaborators_Set_FullMethodName = "/content.collaborators.Collaborators/Set" @@ -47,8 +47,9 @@ func NewCollaboratorsClient(cc grpc.ClientConnInterface) CollaboratorsClient { } func (c *collaboratorsClient) Set(ctx context.Context, in *SetRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Collaborators_Set_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collaborators_Set_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -56,8 +57,9 @@ func (c *collaboratorsClient) Set(ctx context.Context, in *SetRequest, opts ...g } func (c *collaboratorsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Collaborators_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collaborators_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -65,8 +67,9 @@ func (c *collaboratorsClient) Get(ctx context.Context, in *GetRequest, opts ...g } func (c *collaboratorsClient) Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Collaborators_Remove_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collaborators_Remove_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -74,8 +77,9 @@ func (c *collaboratorsClient) Remove(ctx context.Context, in *RemoveRequest, opt } func (c *collaboratorsClient) ListCollaborators(ctx context.Context, in *ListCollaboratorsRequest, opts ...grpc.CallOption) (*ListCollaboratorsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListCollaboratorsResponse) - err := c.cc.Invoke(ctx, Collaborators_ListCollaborators_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collaborators_ListCollaborators_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -83,8 +87,9 @@ func (c *collaboratorsClient) ListCollaborators(ctx context.Context, in *ListCol } func (c *collaboratorsClient) ListSpaces(ctx context.Context, in *ListSpacesRequest, opts ...grpc.CallOption) (*ListSpacesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListSpacesResponse) - err := c.cc.Invoke(ctx, Collaborators_ListSpaces_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collaborators_ListSpaces_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -93,7 +98,7 @@ func (c *collaboratorsClient) ListSpaces(ctx context.Context, in *ListSpacesRequ // CollaboratorsServer is the server API for Collaborators service. // All implementations must embed UnimplementedCollaboratorsServer -// for forward compatibility +// for forward compatibility. type CollaboratorsServer interface { Set(context.Context, *SetRequest) (*emptypb.Empty, error) Get(context.Context, *GetRequest) (*GetResponse, error) @@ -103,9 +108,12 @@ type CollaboratorsServer interface { mustEmbedUnimplementedCollaboratorsServer() } -// UnimplementedCollaboratorsServer must be embedded to have forward compatible implementations. -type UnimplementedCollaboratorsServer struct { -} +// UnimplementedCollaboratorsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCollaboratorsServer struct{} func (UnimplementedCollaboratorsServer) Set(context.Context, *SetRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Set not implemented") @@ -123,6 +131,7 @@ func (UnimplementedCollaboratorsServer) ListSpaces(context.Context, *ListSpacesR return nil, status.Errorf(codes.Unimplemented, "method ListSpaces not implemented") } func (UnimplementedCollaboratorsServer) mustEmbedUnimplementedCollaboratorsServer() {} +func (UnimplementedCollaboratorsServer) testEmbeddedByValue() {} // UnsafeCollaboratorsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to CollaboratorsServer will @@ -132,6 +141,13 @@ type UnsafeCollaboratorsServer interface { } func RegisterCollaboratorsServer(s grpc.ServiceRegistrar, srv CollaboratorsServer) { + // If the following call pancis, it indicates UnimplementedCollaboratorsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Collaborators_ServiceDesc, srv) } diff --git a/proto/collections/collections.pb.go b/proto/collections/collections.pb.go index 164a8644d7fe74966f55b22880c97cfe05587d8b..01d4dc128c49fae67c535821092e9b60f497add1 100644 --- a/proto/collections/collections.pb.go +++ b/proto/collections/collections.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: collections/collections.proto package collections @@ -10,6 +10,7 @@ import ( common "git.perx.ru/perxis/perxis-go/proto/common" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" emptypb "google.golang.org/protobuf/types/known/emptypb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" @@ -188,6 +189,19 @@ type Collection struct { StateInfo *Collection_StateInfo `protobuf:"bytes,10,opt,name=state_info,json=stateInfo,proto3" json:"state_info,omitempty"` Tags []string `protobuf:"bytes,16,rep,name=tags,proto3" json:"tags,omitempty"` Access *Access `protobuf:"bytes,20,opt,name=access,proto3" json:"access,omitempty"` // Возможные действия с коллекцией на основе контекста запроса + // Коллекция без истории изменений (ревизии) + // История изменений записей в коллекции не будет сохраняться и вернуться к предыдущим версиям будет нельзя + NoRevisions bool `protobuf:"varint,30,opt,name=no_revisions,json=noRevisions,proto3" json:"no_revisions,omitempty"` + MaxRevisions uint32 `protobuf:"varint,31,opt,name=max_revisions,json=maxRevisions,proto3" json:"max_revisions,omitempty"` // старые ревизии сверх указанного количества будут автоматически удаляться. 0, пусто - без ограничений + RevisionTtl *durationpb.Duration `protobuf:"bytes,32,opt,name=revision_ttl,json=revisionTtl,proto3" json:"revision_ttl,omitempty"` // ревизии старше указанного времени хранения будут автоматически удалятся. 0, пусто - без ограничений + // Коллекция без архива + // Включение опции приведет к удалению всех записей в архиве, а функция архивирования станет недоступна + NoArchive bool `protobuf:"varint,35,opt,name=no_archive,json=noArchive,proto3" json:"no_archive,omitempty"` + // Коллекция без публикации + // Все записи коллекции считаются опубликованными, функции публикации и снятия с публикации недоступны. + // При включении параметра коллекции "без публикации" все записи, независимо от статуса, будут считаться опубликованными. + // При отключении параметра "без публикации" статусы публикации будут восстановлены. + NoPublish bool `protobuf:"varint,40,opt,name=no_publish,json=noPublish,proto3" json:"no_publish,omitempty"` } func (x *Collection) Reset() { @@ -313,6 +327,41 @@ func (x *Collection) GetAccess() *Access { return nil } +func (x *Collection) GetNoRevisions() bool { + if x != nil { + return x.NoRevisions + } + return false +} + +func (x *Collection) GetMaxRevisions() uint32 { + if x != nil { + return x.MaxRevisions + } + return 0 +} + +func (x *Collection) GetRevisionTtl() *durationpb.Duration { + if x != nil { + return x.RevisionTtl + } + return nil +} + +func (x *Collection) GetNoArchive() bool { + if x != nil { + return x.NoArchive + } + return false +} + +func (x *Collection) GetNoPublish() bool { + if x != nil { + return x.NoPublish + } + return false +} + type CreateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1088,7 +1137,9 @@ var file_collections_collections_proto_rawDesc = []byte{ 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x81, 0x02, 0x0a, 0x06, 0x41, 0x63, 0x63, 0x65, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x81, 0x02, 0x0a, 0x06, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, @@ -1104,7 +1155,7 @@ var file_collections_collections_proto_rawDesc = []byte{ 0x0e, 0x64, 0x65, 0x6e, 0x79, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x6e, 0x79, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x6e, 0x79, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0xae, 0x06, 0x0a, 0x0a, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0xf2, 0x07, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, @@ -1132,137 +1183,150 @@ var file_collections_collections_proto_rawDesc = []byte{ 0x12, 0x33, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x06, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x1a, 0x75, 0x0a, 0x04, 0x56, 0x69, 0x65, 0x77, 0x12, 0x19, 0x0a, - 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, - 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x97, 0x01, 0x0a, - 0x09, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x39, 0x0a, 0x0a, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x42, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x07, 0x0a, 0x03, 0x4e, 0x45, 0x57, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x52, 0x45, 0x50, - 0x41, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, 0x59, - 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0b, 0x0a, - 0x07, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x44, 0x10, 0x04, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, - 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6e, 0x6f, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x50, 0x0a, 0x0d, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, - 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4b, - 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x39, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x44, 0x0a, 0x0a, 0x47, - 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x64, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x64, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, - 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, - 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x47, - 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x4e, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x6f, 0x5f, 0x72, 0x65, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x52, + 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0c, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, + 0x0c, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x74, 0x6c, 0x18, 0x20, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x74, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, + 0x6f, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x18, 0x23, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x6e, 0x6f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, + 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x18, 0x28, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x6e, 0x6f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x1a, 0x75, 0x0a, 0x04, 0x56, 0x69, 0x65, + 0x77, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, + 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, + 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x1a, 0x97, 0x01, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, + 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, + 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x42, 0x0a, 0x05, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x45, 0x57, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, + 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, + 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, + 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x44, 0x10, 0x04, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6e, 0x6f, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x22, 0x50, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0xa5, 0x02, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, - 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x6e, 0x76, 0x49, 0x64, 0x12, 0x3f, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0xa2, 0x01, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x5f, 0x6e, 0x6f, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4e, 0x6f, 0x44, 0x61, 0x74, 0x61, 0x12, - 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x68, 0x69, 0x64, 0x64, 0x65, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x48, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x51, 0x0a, 0x0c, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0b, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x50, 0x0a, - 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, - 0x0a, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x81, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x22, 0x66, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x6f, 0x6e, 0x22, 0x4b, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, + 0x44, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x36, 0x0a, + 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x49, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, 0xdb, 0x03, 0x0a, 0x0b, - 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x53, 0x0a, 0x06, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x4e, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa5, 0x02, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x3f, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0xa2, 0x01, 0x0a, 0x06, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, + 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x65, 0x78, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x26, 0x0a, 0x0f, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6e, 0x6f, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4e, 0x6f, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x68, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x48, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x51, + 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, + 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x50, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x81, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x66, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, + 0xdb, 0x03, 0x0a, 0x0b, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x53, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x4a, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x04, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x06, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, - 0x00, 0x12, 0x46, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x6f, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, - 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, - 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x4d, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x46, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, + 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x3c, 0x5a, + 0x3a, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, + 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -1279,7 +1343,7 @@ func file_collections_collections_proto_rawDescGZIP() []byte { var file_collections_collections_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_collections_collections_proto_msgTypes = make([]protoimpl.MessageInfo, 15) -var file_collections_collections_proto_goTypes = []interface{}{ +var file_collections_collections_proto_goTypes = []any{ (Collection_State)(0), // 0: content.collections.Collection.State (*Access)(nil), // 1: content.collections.Access (*Collection)(nil), // 2: content.collections.Collection @@ -1297,40 +1361,42 @@ var file_collections_collections_proto_goTypes = []interface{}{ (*Collection_StateInfo)(nil), // 14: content.collections.Collection.StateInfo (*ListRequest_Filter)(nil), // 15: content.collections.ListRequest.Filter (common.Action)(0), // 16: common.Action - (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 18: google.protobuf.Empty + (*durationpb.Duration)(nil), // 17: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 19: google.protobuf.Empty } var file_collections_collections_proto_depIdxs = []int32{ 16, // 0: content.collections.Access.actions:type_name -> common.Action 13, // 1: content.collections.Collection.view:type_name -> content.collections.Collection.View 14, // 2: content.collections.Collection.state_info:type_name -> content.collections.Collection.StateInfo 1, // 3: content.collections.Collection.access:type_name -> content.collections.Access - 2, // 4: content.collections.CreateRequest.collection:type_name -> content.collections.Collection - 2, // 5: content.collections.CreateResponse.created:type_name -> content.collections.Collection - 5, // 6: content.collections.GetRequest.options:type_name -> content.collections.GetOptions - 2, // 7: content.collections.GetResponse.collection:type_name -> content.collections.Collection - 15, // 8: content.collections.ListRequest.filter:type_name -> content.collections.ListRequest.Filter - 2, // 9: content.collections.ListResponse.collections:type_name -> content.collections.Collection - 2, // 10: content.collections.UpdateRequest.collection:type_name -> content.collections.Collection - 0, // 11: content.collections.Collection.StateInfo.state:type_name -> content.collections.Collection.State - 17, // 12: content.collections.Collection.StateInfo.started_at:type_name -> google.protobuf.Timestamp - 3, // 13: content.collections.Collections.Create:input_type -> content.collections.CreateRequest - 6, // 14: content.collections.Collections.Get:input_type -> content.collections.GetRequest - 8, // 15: content.collections.Collections.List:input_type -> content.collections.ListRequest - 10, // 16: content.collections.Collections.Update:input_type -> content.collections.UpdateRequest - 11, // 17: content.collections.Collections.SetSchema:input_type -> content.collections.SetSchemaRequest - 12, // 18: content.collections.Collections.Delete:input_type -> content.collections.DeleteRequest - 4, // 19: content.collections.Collections.Create:output_type -> content.collections.CreateResponse - 7, // 20: content.collections.Collections.Get:output_type -> content.collections.GetResponse - 9, // 21: content.collections.Collections.List:output_type -> content.collections.ListResponse - 18, // 22: content.collections.Collections.Update:output_type -> google.protobuf.Empty - 18, // 23: content.collections.Collections.SetSchema:output_type -> google.protobuf.Empty - 18, // 24: content.collections.Collections.Delete:output_type -> google.protobuf.Empty - 19, // [19:25] is the sub-list for method output_type - 13, // [13:19] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 17, // 4: content.collections.Collection.revision_ttl:type_name -> google.protobuf.Duration + 2, // 5: content.collections.CreateRequest.collection:type_name -> content.collections.Collection + 2, // 6: content.collections.CreateResponse.created:type_name -> content.collections.Collection + 5, // 7: content.collections.GetRequest.options:type_name -> content.collections.GetOptions + 2, // 8: content.collections.GetResponse.collection:type_name -> content.collections.Collection + 15, // 9: content.collections.ListRequest.filter:type_name -> content.collections.ListRequest.Filter + 2, // 10: content.collections.ListResponse.collections:type_name -> content.collections.Collection + 2, // 11: content.collections.UpdateRequest.collection:type_name -> content.collections.Collection + 0, // 12: content.collections.Collection.StateInfo.state:type_name -> content.collections.Collection.State + 18, // 13: content.collections.Collection.StateInfo.started_at:type_name -> google.protobuf.Timestamp + 3, // 14: content.collections.Collections.Create:input_type -> content.collections.CreateRequest + 6, // 15: content.collections.Collections.Get:input_type -> content.collections.GetRequest + 8, // 16: content.collections.Collections.List:input_type -> content.collections.ListRequest + 10, // 17: content.collections.Collections.Update:input_type -> content.collections.UpdateRequest + 11, // 18: content.collections.Collections.SetSchema:input_type -> content.collections.SetSchemaRequest + 12, // 19: content.collections.Collections.Delete:input_type -> content.collections.DeleteRequest + 4, // 20: content.collections.Collections.Create:output_type -> content.collections.CreateResponse + 7, // 21: content.collections.Collections.Get:output_type -> content.collections.GetResponse + 9, // 22: content.collections.Collections.List:output_type -> content.collections.ListResponse + 19, // 23: content.collections.Collections.Update:output_type -> google.protobuf.Empty + 19, // 24: content.collections.Collections.SetSchema:output_type -> google.protobuf.Empty + 19, // 25: content.collections.Collections.Delete:output_type -> google.protobuf.Empty + 20, // [20:26] is the sub-list for method output_type + 14, // [14:20] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_collections_collections_proto_init() } @@ -1339,7 +1405,7 @@ func file_collections_collections_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_collections_collections_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Access); i { case 0: return &v.state @@ -1351,7 +1417,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Collection); i { case 0: return &v.state @@ -1363,7 +1429,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -1375,7 +1441,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -1387,7 +1453,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*GetOptions); i { case 0: return &v.state @@ -1399,7 +1465,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -1411,7 +1477,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -1423,7 +1489,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ListRequest); i { case 0: return &v.state @@ -1435,7 +1501,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ListResponse); i { case 0: return &v.state @@ -1447,7 +1513,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1459,7 +1525,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*SetSchemaRequest); i { case 0: return &v.state @@ -1471,7 +1537,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -1483,7 +1549,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*Collection_View); i { case 0: return &v.state @@ -1495,7 +1561,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*Collection_StateInfo); i { case 0: return &v.state @@ -1507,7 +1573,7 @@ func file_collections_collections_proto_init() { return nil } } - file_collections_collections_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_collections_collections_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*ListRequest_Filter); i { case 0: return &v.state @@ -1520,7 +1586,7 @@ func file_collections_collections_proto_init() { } } } - file_collections_collections_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_collections_collections_proto_msgTypes[1].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/proto/collections/collections_grpc.pb.go b/proto/collections/collections_grpc.pb.go index 392ef1841c36ee9ca29d6ccc3bfffd9e97ec0054..8d5bc339a5bdba376478a59bb88df68fbf5566c8 100644 --- a/proto/collections/collections_grpc.pb.go +++ b/proto/collections/collections_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: collections/collections.proto package collections @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Collections_Create_FullMethodName = "/content.collections.Collections/Create" @@ -63,8 +63,9 @@ func NewCollectionsClient(cc grpc.ClientConnInterface) CollectionsClient { } func (c *collectionsClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Collections_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collections_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -72,8 +73,9 @@ func (c *collectionsClient) Create(ctx context.Context, in *CreateRequest, opts } func (c *collectionsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Collections_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collections_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -81,8 +83,9 @@ func (c *collectionsClient) Get(ctx context.Context, in *GetRequest, opts ...grp } func (c *collectionsClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListResponse) - err := c.cc.Invoke(ctx, Collections_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collections_List_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -90,8 +93,9 @@ func (c *collectionsClient) List(ctx context.Context, in *ListRequest, opts ...g } func (c *collectionsClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Collections_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collections_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -99,8 +103,9 @@ func (c *collectionsClient) Update(ctx context.Context, in *UpdateRequest, opts } func (c *collectionsClient) SetSchema(ctx context.Context, in *SetSchemaRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Collections_SetSchema_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collections_SetSchema_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -108,8 +113,9 @@ func (c *collectionsClient) SetSchema(ctx context.Context, in *SetSchemaRequest, } func (c *collectionsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Collections_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Collections_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -118,7 +124,7 @@ func (c *collectionsClient) Delete(ctx context.Context, in *DeleteRequest, opts // CollectionsServer is the server API for Collections service. // All implementations must embed UnimplementedCollectionsServer -// for forward compatibility +// for forward compatibility. type CollectionsServer interface { // Создать коллекцию. Установка схемы производится через отдельный метод `SetSchema` и методом `Create` игнорируется Create(context.Context, *CreateRequest) (*CreateResponse, error) @@ -143,9 +149,12 @@ type CollectionsServer interface { mustEmbedUnimplementedCollectionsServer() } -// UnimplementedCollectionsServer must be embedded to have forward compatible implementations. -type UnimplementedCollectionsServer struct { -} +// UnimplementedCollectionsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCollectionsServer struct{} func (UnimplementedCollectionsServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -166,6 +175,7 @@ func (UnimplementedCollectionsServer) Delete(context.Context, *DeleteRequest) (* return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func (UnimplementedCollectionsServer) mustEmbedUnimplementedCollectionsServer() {} +func (UnimplementedCollectionsServer) testEmbeddedByValue() {} // UnsafeCollectionsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to CollectionsServer will @@ -175,6 +185,13 @@ type UnsafeCollectionsServer interface { } func RegisterCollectionsServer(s grpc.ServiceRegistrar, srv CollectionsServer) { + // If the following call pancis, it indicates UnimplementedCollectionsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Collections_ServiceDesc, srv) } diff --git a/proto/common/common.pb.go b/proto/common/common.pb.go index ea585fe3435096d877fa4bbc3649fe96a4b0649f..3495031fb399fabaa59992460d63f40654e69f3e 100644 --- a/proto/common/common.pb.go +++ b/proto/common/common.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: common/common.proto package common @@ -125,6 +125,9 @@ func (Action) EnumDescriptor() ([]byte, []int) { return file_common_common_proto_rawDescGZIP(), []int{1} } +// Deprecated +// Поддержка этой реализации фильтра осталась только в запросе поиска записей (Items.Find) +// Возможно, его поддержка будет прекращена в следующих версиях системы type Filter struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -639,7 +642,7 @@ func file_common_common_proto_rawDescGZIP() []byte { var file_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_common_common_proto_goTypes = []interface{}{ +var file_common_common_proto_goTypes = []any{ (Access)(0), // 0: common.Access (Action)(0), // 1: common.Action (*Filter)(nil), // 2: common.Filter @@ -666,7 +669,7 @@ func file_common_common_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_common_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_common_common_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Filter); i { case 0: return &v.state @@ -678,7 +681,7 @@ func file_common_common_proto_init() { return nil } } - file_common_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_common_common_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*FindOptions); i { case 0: return &v.state @@ -690,7 +693,7 @@ func file_common_common_proto_init() { return nil } } - file_common_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_common_common_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Rule); i { case 0: return &v.state @@ -702,7 +705,7 @@ func file_common_common_proto_init() { return nil } } - file_common_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_common_common_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*Collaborator); i { case 0: return &v.state @@ -714,7 +717,7 @@ func file_common_common_proto_init() { return nil } } - file_common_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_common_common_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*Version); i { case 0: return &v.state diff --git a/proto/common/error.pb.go b/proto/common/error.pb.go index 444bea97b4c027067c4675b3d606a3f9c85f64b8..6eeb8c55eed7f7c04c9882dc2f8d8537da01b4be 100644 --- a/proto/common/error.pb.go +++ b/proto/common/error.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: common/error.proto package common @@ -556,7 +556,7 @@ func file_common_error_proto_rawDescGZIP() []byte { } var file_common_error_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_common_error_proto_goTypes = []interface{}{ +var file_common_error_proto_goTypes = []any{ (*Error)(nil), // 0: common.Error (*Error_BadRequest)(nil), // 1: common.Error.BadRequest (*Error_Help)(nil), // 2: common.Error.Help @@ -588,7 +588,7 @@ func file_common_error_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_common_error_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Error); i { case 0: return &v.state @@ -600,7 +600,7 @@ func file_common_error_proto_init() { return nil } } - file_common_error_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Error_BadRequest); i { case 0: return &v.state @@ -612,7 +612,7 @@ func file_common_error_proto_init() { return nil } } - file_common_error_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Error_Help); i { case 0: return &v.state @@ -624,7 +624,7 @@ func file_common_error_proto_init() { return nil } } - file_common_error_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*Error_DebugInfo); i { case 0: return &v.state @@ -636,7 +636,7 @@ func file_common_error_proto_init() { return nil } } - file_common_error_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*Error_LocalizedMessage); i { case 0: return &v.state @@ -648,7 +648,7 @@ func file_common_error_proto_init() { return nil } } - file_common_error_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*Error_BadRequest_FieldViolation); i { case 0: return &v.state @@ -660,7 +660,7 @@ func file_common_error_proto_init() { return nil } } - file_common_error_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_common_error_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*Error_Help_Link); i { case 0: return &v.state diff --git a/proto/common/operation.pb.go b/proto/common/operation.pb.go index fd84dde80f2875d3282987fb19e8df17aabed780..3f72af24932eec58d77f558c988e5e197605198e 100644 --- a/proto/common/operation.pb.go +++ b/proto/common/operation.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: common/operation.proto package common @@ -224,7 +224,7 @@ func file_common_operation_proto_rawDescGZIP() []byte { } var file_common_operation_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_common_operation_proto_goTypes = []interface{}{ +var file_common_operation_proto_goTypes = []any{ (*Operation)(nil), // 0: common.Operation (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp (*anypb.Any)(nil), // 2: google.protobuf.Any @@ -250,7 +250,7 @@ func file_common_operation_proto_init() { } file_common_error_proto_init() if !protoimpl.UnsafeEnabled { - file_common_operation_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_common_operation_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Operation); i { case 0: return &v.state @@ -263,7 +263,7 @@ func file_common_operation_proto_init() { } } } - file_common_operation_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_common_operation_proto_msgTypes[0].OneofWrappers = []any{ (*Operation_Response)(nil), (*Operation_Error)(nil), } diff --git a/proto/common/operation_service.pb.go b/proto/common/operation_service.pb.go index 93876246a4f69845688755a3a88bfde6330cbcd7..d0bd8e57acdc3298dbf9841feef256978805dd07 100644 --- a/proto/common/operation_service.pb.go +++ b/proto/common/operation_service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: common/operation_service.proto package common @@ -159,7 +159,7 @@ func file_common_operation_service_proto_rawDescGZIP() []byte { } var file_common_operation_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_common_operation_service_proto_goTypes = []interface{}{ +var file_common_operation_service_proto_goTypes = []any{ (*GetOperationRequest)(nil), // 0: common.GetOperationRequest (*CancelOperationRequest)(nil), // 1: common.CancelOperationRequest (*Operation)(nil), // 2: common.Operation @@ -184,7 +184,7 @@ func file_common_operation_service_proto_init() { file_common_operation_proto_init() file_common_validation_proto_init() if !protoimpl.UnsafeEnabled { - file_common_operation_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_common_operation_service_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*GetOperationRequest); i { case 0: return &v.state @@ -196,7 +196,7 @@ func file_common_operation_service_proto_init() { return nil } } - file_common_operation_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_common_operation_service_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*CancelOperationRequest); i { case 0: return &v.state diff --git a/proto/common/operation_service_grpc.pb.go b/proto/common/operation_service_grpc.pb.go index d323b0be496411363ba80de50f70246382663307..ff590c80c97d7d31863c2643c93bb359c3bfec92 100644 --- a/proto/common/operation_service_grpc.pb.go +++ b/proto/common/operation_service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: common/operation_service.proto package common @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( OperationService_Get_FullMethodName = "/common.OperationService/Get" @@ -42,8 +42,9 @@ func NewOperationServiceClient(cc grpc.ClientConnInterface) OperationServiceClie } func (c *operationServiceClient) Get(ctx context.Context, in *GetOperationRequest, opts ...grpc.CallOption) (*Operation, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Operation) - err := c.cc.Invoke(ctx, OperationService_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, OperationService_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -51,8 +52,9 @@ func (c *operationServiceClient) Get(ctx context.Context, in *GetOperationReques } func (c *operationServiceClient) Cancel(ctx context.Context, in *CancelOperationRequest, opts ...grpc.CallOption) (*Operation, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Operation) - err := c.cc.Invoke(ctx, OperationService_Cancel_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, OperationService_Cancel_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -61,7 +63,7 @@ func (c *operationServiceClient) Cancel(ctx context.Context, in *CancelOperation // OperationServiceServer is the server API for OperationService service. // All implementations must embed UnimplementedOperationServiceServer -// for forward compatibility +// for forward compatibility. type OperationServiceServer interface { // Возвращает статус операции и ее результат, если она завершена Get(context.Context, *GetOperationRequest) (*Operation, error) @@ -70,9 +72,12 @@ type OperationServiceServer interface { mustEmbedUnimplementedOperationServiceServer() } -// UnimplementedOperationServiceServer must be embedded to have forward compatible implementations. -type UnimplementedOperationServiceServer struct { -} +// UnimplementedOperationServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedOperationServiceServer struct{} func (UnimplementedOperationServiceServer) Get(context.Context, *GetOperationRequest) (*Operation, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") @@ -81,6 +86,7 @@ func (UnimplementedOperationServiceServer) Cancel(context.Context, *CancelOperat return nil, status.Errorf(codes.Unimplemented, "method Cancel not implemented") } func (UnimplementedOperationServiceServer) mustEmbedUnimplementedOperationServiceServer() {} +func (UnimplementedOperationServiceServer) testEmbeddedByValue() {} // UnsafeOperationServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to OperationServiceServer will @@ -90,6 +96,13 @@ type UnsafeOperationServiceServer interface { } func RegisterOperationServiceServer(s grpc.ServiceRegistrar, srv OperationServiceServer) { + // If the following call pancis, it indicates UnimplementedOperationServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&OperationService_ServiceDesc, srv) } diff --git a/proto/common/validation.pb.go b/proto/common/validation.pb.go index cca43ab540da1592a3bb4c21a91ba2be6f1d22bb..8fe6a0c097dea4ef9b71217c94dbbd309de0f55d 100644 --- a/proto/common/validation.pb.go +++ b/proto/common/validation.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: common/validation.proto package common @@ -251,7 +251,7 @@ func file_common_validation_proto_rawDescGZIP() []byte { } var file_common_validation_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_common_validation_proto_goTypes = []interface{}{ +var file_common_validation_proto_goTypes = []any{ (*MapKeySpec)(nil), // 0: common.MapKeySpec (*descriptorpb.OneofOptions)(nil), // 1: google.protobuf.OneofOptions (*descriptorpb.FieldOptions)(nil), // 2: google.protobuf.FieldOptions @@ -280,7 +280,7 @@ func file_common_validation_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_common_validation_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_common_validation_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*MapKeySpec); i { case 0: return &v.state diff --git a/proto/delivery/delivery.pb.go b/proto/delivery/delivery.pb.go index a8673b3e6f8ded57f397a25ca78ae7538d3351ee..81f70e6644e803bf9e33bcce1f6f1d5ea1d73cf7 100644 --- a/proto/delivery/delivery.pb.go +++ b/proto/delivery/delivery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: delivery/delivery.proto package delivery @@ -1144,7 +1144,7 @@ func file_delivery_delivery_proto_rawDescGZIP() []byte { } var file_delivery_delivery_proto_msgTypes = make([]protoimpl.MessageInfo, 18) -var file_delivery_delivery_proto_goTypes = []interface{}{ +var file_delivery_delivery_proto_goTypes = []any{ (*ListLocalesRequest)(nil), // 0: delivery.ListLocalesRequest (*ListLocalesResponse)(nil), // 1: delivery.ListLocalesResponse (*GetEnvironmentRequest)(nil), // 2: delivery.GetEnvironmentRequest @@ -1216,7 +1216,7 @@ func file_delivery_delivery_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_delivery_delivery_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*ListLocalesRequest); i { case 0: return &v.state @@ -1228,7 +1228,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*ListLocalesResponse); i { case 0: return &v.state @@ -1240,7 +1240,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*GetEnvironmentRequest); i { case 0: return &v.state @@ -1252,7 +1252,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*GetEnvironmentResponse); i { case 0: return &v.state @@ -1264,7 +1264,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*ListEnvironmentsRequest); i { case 0: return &v.state @@ -1276,7 +1276,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ListEnvironmentsResponse); i { case 0: return &v.state @@ -1288,7 +1288,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*GetCollectionRequest); i { case 0: return &v.state @@ -1300,7 +1300,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*GetCollectionResponse); i { case 0: return &v.state @@ -1312,7 +1312,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ListCollectionsRequest); i { case 0: return &v.state @@ -1324,7 +1324,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*ListCollectionsResponse); i { case 0: return &v.state @@ -1336,7 +1336,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*GetItemRequest); i { case 0: return &v.state @@ -1348,7 +1348,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*GetItemResponse); i { case 0: return &v.state @@ -1360,7 +1360,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*FindItemsRequest); i { case 0: return &v.state @@ -1372,7 +1372,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*FindItemsResponse); i { case 0: return &v.state @@ -1384,7 +1384,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*AggregateOptions); i { case 0: return &v.state @@ -1396,7 +1396,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*AggregateRequest); i { case 0: return &v.state @@ -1408,7 +1408,7 @@ func file_delivery_delivery_proto_init() { return nil } } - file_delivery_delivery_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_delivery_delivery_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*AggregateResponse); i { case 0: return &v.state diff --git a/proto/delivery/delivery_grpc.pb.go b/proto/delivery/delivery_grpc.pb.go index 3840ca0fc32236f38b8c92eac59c56994996be23..a0a14e9b14e4cc3d0fb7e1bfeb0d418b708b998d 100644 --- a/proto/delivery/delivery_grpc.pb.go +++ b/proto/delivery/delivery_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: delivery/delivery.proto package delivery @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Delivery_ListLocales_FullMethodName = "/delivery.Delivery/ListLocales" @@ -52,8 +52,9 @@ func NewDeliveryClient(cc grpc.ClientConnInterface) DeliveryClient { } func (c *deliveryClient) ListLocales(ctx context.Context, in *ListLocalesRequest, opts ...grpc.CallOption) (*ListLocalesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListLocalesResponse) - err := c.cc.Invoke(ctx, Delivery_ListLocales_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_ListLocales_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -61,8 +62,9 @@ func (c *deliveryClient) ListLocales(ctx context.Context, in *ListLocalesRequest } func (c *deliveryClient) GetEnvironment(ctx context.Context, in *GetEnvironmentRequest, opts ...grpc.CallOption) (*GetEnvironmentResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetEnvironmentResponse) - err := c.cc.Invoke(ctx, Delivery_GetEnvironment_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_GetEnvironment_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -70,8 +72,9 @@ func (c *deliveryClient) GetEnvironment(ctx context.Context, in *GetEnvironmentR } func (c *deliveryClient) ListEnvironments(ctx context.Context, in *ListEnvironmentsRequest, opts ...grpc.CallOption) (*ListEnvironmentsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListEnvironmentsResponse) - err := c.cc.Invoke(ctx, Delivery_ListEnvironments_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_ListEnvironments_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -79,8 +82,9 @@ func (c *deliveryClient) ListEnvironments(ctx context.Context, in *ListEnvironme } func (c *deliveryClient) GetCollection(ctx context.Context, in *GetCollectionRequest, opts ...grpc.CallOption) (*GetCollectionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetCollectionResponse) - err := c.cc.Invoke(ctx, Delivery_GetCollection_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_GetCollection_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -88,8 +92,9 @@ func (c *deliveryClient) GetCollection(ctx context.Context, in *GetCollectionReq } func (c *deliveryClient) ListCollections(ctx context.Context, in *ListCollectionsRequest, opts ...grpc.CallOption) (*ListCollectionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListCollectionsResponse) - err := c.cc.Invoke(ctx, Delivery_ListCollections_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_ListCollections_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -97,8 +102,9 @@ func (c *deliveryClient) ListCollections(ctx context.Context, in *ListCollection } func (c *deliveryClient) GetItem(ctx context.Context, in *GetItemRequest, opts ...grpc.CallOption) (*GetItemResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetItemResponse) - err := c.cc.Invoke(ctx, Delivery_GetItem_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_GetItem_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -106,8 +112,9 @@ func (c *deliveryClient) GetItem(ctx context.Context, in *GetItemRequest, opts . } func (c *deliveryClient) FindItems(ctx context.Context, in *FindItemsRequest, opts ...grpc.CallOption) (*FindItemsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindItemsResponse) - err := c.cc.Invoke(ctx, Delivery_FindItems_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_FindItems_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -115,8 +122,9 @@ func (c *deliveryClient) FindItems(ctx context.Context, in *FindItemsRequest, op } func (c *deliveryClient) Aggregate(ctx context.Context, in *AggregateRequest, opts ...grpc.CallOption) (*AggregateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AggregateResponse) - err := c.cc.Invoke(ctx, Delivery_Aggregate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Delivery_Aggregate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -125,7 +133,7 @@ func (c *deliveryClient) Aggregate(ctx context.Context, in *AggregateRequest, op // DeliveryServer is the server API for Delivery service. // All implementations must embed UnimplementedDeliveryServer -// for forward compatibility +// for forward compatibility. type DeliveryServer interface { ListLocales(context.Context, *ListLocalesRequest) (*ListLocalesResponse, error) GetEnvironment(context.Context, *GetEnvironmentRequest) (*GetEnvironmentResponse, error) @@ -138,9 +146,12 @@ type DeliveryServer interface { mustEmbedUnimplementedDeliveryServer() } -// UnimplementedDeliveryServer must be embedded to have forward compatible implementations. -type UnimplementedDeliveryServer struct { -} +// UnimplementedDeliveryServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedDeliveryServer struct{} func (UnimplementedDeliveryServer) ListLocales(context.Context, *ListLocalesRequest) (*ListLocalesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListLocales not implemented") @@ -167,6 +178,7 @@ func (UnimplementedDeliveryServer) Aggregate(context.Context, *AggregateRequest) return nil, status.Errorf(codes.Unimplemented, "method Aggregate not implemented") } func (UnimplementedDeliveryServer) mustEmbedUnimplementedDeliveryServer() {} +func (UnimplementedDeliveryServer) testEmbeddedByValue() {} // UnsafeDeliveryServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to DeliveryServer will @@ -176,6 +188,13 @@ type UnsafeDeliveryServer interface { } func RegisterDeliveryServer(s grpc.ServiceRegistrar, srv DeliveryServer) { + // If the following call pancis, it indicates UnimplementedDeliveryServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Delivery_ServiceDesc, srv) } diff --git a/proto/environments/environments.pb.go b/proto/environments/environments.pb.go index 8dd2d620cd51e0df031c738d8409585481974062..9bff8500c7c303f5cbeec05f36d3ce4c24809b47 100644 --- a/proto/environments/environments.pb.go +++ b/proto/environments/environments.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: environments/environments.proto package environments @@ -1082,7 +1082,7 @@ func file_environments_environments_proto_rawDescGZIP() []byte { var file_environments_environments_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_environments_environments_proto_msgTypes = make([]protoimpl.MessageInfo, 15) -var file_environments_environments_proto_goTypes = []interface{}{ +var file_environments_environments_proto_goTypes = []any{ (StateInfo_State)(0), // 0: content.environments.StateInfo.State (*Environment)(nil), // 1: content.environments.Environment (*StateInfo)(nil), // 2: content.environments.StateInfo @@ -1142,7 +1142,7 @@ func file_environments_environments_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_environments_environments_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Environment); i { case 0: return &v.state @@ -1154,7 +1154,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*StateInfo); i { case 0: return &v.state @@ -1166,7 +1166,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Config); i { case 0: return &v.state @@ -1178,7 +1178,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -1190,7 +1190,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -1202,7 +1202,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ListRequest); i { case 0: return &v.state @@ -1214,7 +1214,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ListResponse); i { case 0: return &v.state @@ -1226,7 +1226,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -1238,7 +1238,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -1250,7 +1250,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1262,7 +1262,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*SetAliasRequest); i { case 0: return &v.state @@ -1274,7 +1274,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*RemoveAliasRequest); i { case 0: return &v.state @@ -1286,7 +1286,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -1298,7 +1298,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*MigrateRequest); i { case 0: return &v.state @@ -1310,7 +1310,7 @@ func file_environments_environments_proto_init() { return nil } } - file_environments_environments_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_environments_environments_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*MigrateOptions); i { case 0: return &v.state diff --git a/proto/environments/environments_grpc.pb.go b/proto/environments/environments_grpc.pb.go index 63268a0ba508b1e00b189a7588573fd12c47c0fb..b0d65500e40a5822a0675deb061db968742dc955 100644 --- a/proto/environments/environments_grpc.pb.go +++ b/proto/environments/environments_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: environments/environments.proto package environments @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Environments_Create_FullMethodName = "/content.environments.Environments/Create" @@ -60,8 +60,9 @@ func NewEnvironmentsClient(cc grpc.ClientConnInterface) EnvironmentsClient { } func (c *environmentsClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Environments_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -69,8 +70,9 @@ func (c *environmentsClient) Create(ctx context.Context, in *CreateRequest, opts } func (c *environmentsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Environments_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -78,8 +80,9 @@ func (c *environmentsClient) Get(ctx context.Context, in *GetRequest, opts ...gr } func (c *environmentsClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListResponse) - err := c.cc.Invoke(ctx, Environments_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_List_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -87,8 +90,9 @@ func (c *environmentsClient) List(ctx context.Context, in *ListRequest, opts ... } func (c *environmentsClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Environments_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -96,8 +100,9 @@ func (c *environmentsClient) Update(ctx context.Context, in *UpdateRequest, opts } func (c *environmentsClient) SetAlias(ctx context.Context, in *SetAliasRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Environments_SetAlias_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_SetAlias_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -105,8 +110,9 @@ func (c *environmentsClient) SetAlias(ctx context.Context, in *SetAliasRequest, } func (c *environmentsClient) RemoveAlias(ctx context.Context, in *RemoveAliasRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Environments_RemoveAlias_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_RemoveAlias_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -114,8 +120,9 @@ func (c *environmentsClient) RemoveAlias(ctx context.Context, in *RemoveAliasReq } func (c *environmentsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Environments_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -123,8 +130,9 @@ func (c *environmentsClient) Delete(ctx context.Context, in *DeleteRequest, opts } func (c *environmentsClient) Migrate(ctx context.Context, in *MigrateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Environments_Migrate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Environments_Migrate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -133,7 +141,7 @@ func (c *environmentsClient) Migrate(ctx context.Context, in *MigrateRequest, op // EnvironmentsServer is the server API for Environments service. // All implementations must embed UnimplementedEnvironmentsServer -// for forward compatibility +// for forward compatibility. type EnvironmentsServer interface { Create(context.Context, *CreateRequest) (*CreateResponse, error) Get(context.Context, *GetRequest) (*GetResponse, error) @@ -153,9 +161,12 @@ type EnvironmentsServer interface { mustEmbedUnimplementedEnvironmentsServer() } -// UnimplementedEnvironmentsServer must be embedded to have forward compatible implementations. -type UnimplementedEnvironmentsServer struct { -} +// UnimplementedEnvironmentsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedEnvironmentsServer struct{} func (UnimplementedEnvironmentsServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -182,6 +193,7 @@ func (UnimplementedEnvironmentsServer) Migrate(context.Context, *MigrateRequest) return nil, status.Errorf(codes.Unimplemented, "method Migrate not implemented") } func (UnimplementedEnvironmentsServer) mustEmbedUnimplementedEnvironmentsServer() {} +func (UnimplementedEnvironmentsServer) testEmbeddedByValue() {} // UnsafeEnvironmentsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to EnvironmentsServer will @@ -191,6 +203,13 @@ type UnsafeEnvironmentsServer interface { } func RegisterEnvironmentsServer(s grpc.ServiceRegistrar, srv EnvironmentsServer) { + // If the following call pancis, it indicates UnimplementedEnvironmentsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Environments_ServiceDesc, srv) } diff --git a/proto/extensions/extension.pb.go b/proto/extensions/extension.pb.go index 0c1501b6d088570de34d5bb617346f620ed643ef..042f307b258e3fdff0921f06d3b8ca15118c6b61 100644 --- a/proto/extensions/extension.pb.go +++ b/proto/extensions/extension.pb.go @@ -10,8 +10,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: extensions/extension.proto package extensions @@ -490,6 +490,8 @@ type ActionRequest struct { CollectionId string `protobuf:"bytes,10520,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` ItemId string `protobuf:"bytes,10530,opt,name=item_id,json=itemId,proto3" json:"item_id,omitempty"` ItemIds []string `protobuf:"bytes,10540,rep,name=item_ids,json=itemIds,proto3" json:"item_ids,omitempty"` + // Идентификатор локали в пространстве: поле может использоваться расширением, если действие возможно выполнить на разных локалях + LocaleId string `protobuf:"bytes,11050,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Поля к которым применимо действие. В случае если действие выполняется из списка записей, содержит перечень // полей которые пользователь выбрал для отображения в интерфейсе. Fields []string `protobuf:"bytes,10550,rep,name=fields,proto3" json:"fields,omitempty"` @@ -582,6 +584,13 @@ func (x *ActionRequest) GetItemIds() []string { return nil } +func (x *ActionRequest) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + func (x *ActionRequest) GetFields() []string { if x != nil { return x.Fields @@ -675,7 +684,7 @@ var file_extensions_extension_proto_rawDesc = []byte{ 0x44, 0x44, 0x45, 0x4e, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x4e, 0x55, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x4e, 0x55, 0x5f, 0x42, 0x4f, 0x54, - 0x54, 0x4f, 0x4d, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, 0x03, 0x22, 0xdf, 0x03, 0x0a, 0x0d, 0x41, + 0x54, 0x4f, 0x4d, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, 0x03, 0x22, 0xfd, 0x03, 0x0a, 0x0d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x06, 0x61, @@ -689,34 +698,36 @@ var file_extensions_extension_proto_rawDesc = []byte{ 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0xa2, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x73, 0x18, 0xac, 0x52, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x69, 0x74, 0x65, - 0x6d, 0x49, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0xb6, - 0x52, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x44, 0x0a, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0xf8, 0x55, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x73, 0x18, 0x82, 0x56, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x52, 0x04, 0x72, 0x65, 0x66, 0x73, 0x12, 0x36, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x18, 0x8c, 0x56, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, - 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x67, 0x0a, 0x06, - 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, - 0x54, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f, 0x44, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x08, - 0x0a, 0x04, 0x57, 0x49, 0x44, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x49, 0x4e, - 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x52, 0x41, 0x57, 0x45, 0x52, 0x10, 0x05, 0x12, 0x10, - 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x06, - 0x12, 0x09, 0x0a, 0x05, 0x42, 0x4c, 0x41, 0x4e, 0x4b, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4e, - 0x4f, 0x4e, 0x45, 0x10, 0x64, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, - 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, - 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x49, 0x64, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0xaa, 0x56, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x49, 0x64, 0x12, 0x17, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0xb6, 0x52, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0xf8, 0x55, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x32, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x73, 0x18, 0x82, 0x56, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, + 0x04, 0x72, 0x65, 0x66, 0x73, 0x12, 0x36, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, + 0x8c, 0x56, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x3b, 0x0a, + 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x67, 0x0a, 0x06, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, + 0x00, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x4f, 0x44, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, + 0x57, 0x49, 0x44, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x49, 0x4e, 0x10, 0x04, + 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x52, 0x41, 0x57, 0x45, 0x52, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, + 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x12, 0x09, + 0x0a, 0x05, 0x42, 0x4c, 0x41, 0x4e, 0x4b, 0x10, 0x07, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, + 0x45, 0x10, 0x64, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, + 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, + 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -733,7 +744,7 @@ func file_extensions_extension_proto_rawDescGZIP() []byte { var file_extensions_extension_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_extensions_extension_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_extensions_extension_proto_goTypes = []interface{}{ +var file_extensions_extension_proto_goTypes = []any{ (Target)(0), // 0: extensions.Target (Action_Kind)(0), // 1: extensions.Action.Kind (Action_View)(0), // 2: extensions.Action.View @@ -765,7 +776,7 @@ func file_extensions_extension_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_extensions_extension_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_extensions_extension_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Action); i { case 0: return &v.state @@ -777,7 +788,7 @@ func file_extensions_extension_proto_init() { return nil } } - file_extensions_extension_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_extensions_extension_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*ActionRequest); i { case 0: return &v.state diff --git a/proto/extensions/extension_service.pb.go b/proto/extensions/extension_service.pb.go index ef0d0a82baa9f2683c12b24d8ca85e917904d655..39424e069bb4ea0d1e6efeb6b44542fd8c2a6827 100644 --- a/proto/extensions/extension_service.pb.go +++ b/proto/extensions/extension_service.pb.go @@ -10,8 +10,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: extensions/extension_service.proto package extensions @@ -582,7 +582,7 @@ func file_extensions_extension_service_proto_rawDescGZIP() []byte { var file_extensions_extension_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_extensions_extension_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_extensions_extension_service_proto_goTypes = []interface{}{ +var file_extensions_extension_service_proto_goTypes = []any{ (ActionResponse_State)(0), // 0: extensions.ActionResponse.State (ActionResponse_Format)(0), // 1: extensions.ActionResponse.Format (*InstallRequest)(nil), // 2: extensions.InstallRequest @@ -625,7 +625,7 @@ func file_extensions_extension_service_proto_init() { } file_extensions_extension_proto_init() if !protoimpl.UnsafeEnabled { - file_extensions_extension_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_extensions_extension_service_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*InstallRequest); i { case 0: return &v.state @@ -637,7 +637,7 @@ func file_extensions_extension_service_proto_init() { return nil } } - file_extensions_extension_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_extensions_extension_service_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*UninstallRequest); i { case 0: return &v.state @@ -649,7 +649,7 @@ func file_extensions_extension_service_proto_init() { return nil } } - file_extensions_extension_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_extensions_extension_service_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CheckRequest); i { case 0: return &v.state @@ -661,7 +661,7 @@ func file_extensions_extension_service_proto_init() { return nil } } - file_extensions_extension_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_extensions_extension_service_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ActionResponse); i { case 0: return &v.state diff --git a/proto/extensions/extension_service_grpc.pb.go b/proto/extensions/extension_service_grpc.pb.go index 3cd37b839f83963d40818ddb7f094894c56f2f12..a5a1a98180108b1c0663862db4150aec9a64ff24 100644 --- a/proto/extensions/extension_service_grpc.pb.go +++ b/proto/extensions/extension_service_grpc.pb.go @@ -10,8 +10,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: extensions/extension_service.proto package extensions @@ -26,8 +26,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( ExtensionService_Install_FullMethodName = "/extensions.ExtensionService/Install" @@ -39,6 +39,9 @@ const ( // ExtensionServiceClient is the client API for ExtensionService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// ExtensionService - API расширения +// Сервис должен реализовывать методы `common.OperationService` для работы операциями. type ExtensionServiceClient interface { // Install выполняет установку указанных расширений. Если // расширение уже установлены выполняет процесс переустановки. Возвращает longtime операцию @@ -79,8 +82,9 @@ func NewExtensionServiceClient(cc grpc.ClientConnInterface) ExtensionServiceClie } func (c *extensionServiceClient) Install(ctx context.Context, in *InstallRequest, opts ...grpc.CallOption) (*common.Operation, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(common.Operation) - err := c.cc.Invoke(ctx, ExtensionService_Install_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionService_Install_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -88,8 +92,9 @@ func (c *extensionServiceClient) Install(ctx context.Context, in *InstallRequest } func (c *extensionServiceClient) Uninstall(ctx context.Context, in *UninstallRequest, opts ...grpc.CallOption) (*common.Operation, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(common.Operation) - err := c.cc.Invoke(ctx, ExtensionService_Uninstall_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionService_Uninstall_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -97,8 +102,9 @@ func (c *extensionServiceClient) Uninstall(ctx context.Context, in *UninstallReq } func (c *extensionServiceClient) Check(ctx context.Context, in *CheckRequest, opts ...grpc.CallOption) (*common.Operation, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(common.Operation) - err := c.cc.Invoke(ctx, ExtensionService_Check_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionService_Check_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -106,8 +112,9 @@ func (c *extensionServiceClient) Check(ctx context.Context, in *CheckRequest, op } func (c *extensionServiceClient) Action(ctx context.Context, in *ActionRequest, opts ...grpc.CallOption) (*ActionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ActionResponse) - err := c.cc.Invoke(ctx, ExtensionService_Action_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionService_Action_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -116,7 +123,10 @@ func (c *extensionServiceClient) Action(ctx context.Context, in *ActionRequest, // ExtensionServiceServer is the server API for ExtensionService service. // All implementations must embed UnimplementedExtensionServiceServer -// for forward compatibility +// for forward compatibility. +// +// ExtensionService - API расширения +// Сервис должен реализовывать методы `common.OperationService` для работы операциями. type ExtensionServiceServer interface { // Install выполняет установку указанных расширений. Если // расширение уже установлены выполняет процесс переустановки. Возвращает longtime операцию @@ -149,9 +159,12 @@ type ExtensionServiceServer interface { mustEmbedUnimplementedExtensionServiceServer() } -// UnimplementedExtensionServiceServer must be embedded to have forward compatible implementations. -type UnimplementedExtensionServiceServer struct { -} +// UnimplementedExtensionServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedExtensionServiceServer struct{} func (UnimplementedExtensionServiceServer) Install(context.Context, *InstallRequest) (*common.Operation, error) { return nil, status.Errorf(codes.Unimplemented, "method Install not implemented") @@ -166,6 +179,7 @@ func (UnimplementedExtensionServiceServer) Action(context.Context, *ActionReques return nil, status.Errorf(codes.Unimplemented, "method Action not implemented") } func (UnimplementedExtensionServiceServer) mustEmbedUnimplementedExtensionServiceServer() {} +func (UnimplementedExtensionServiceServer) testEmbeddedByValue() {} // UnsafeExtensionServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ExtensionServiceServer will @@ -175,6 +189,13 @@ type UnsafeExtensionServiceServer interface { } func RegisterExtensionServiceServer(s grpc.ServiceRegistrar, srv ExtensionServiceServer) { + // If the following call pancis, it indicates UnimplementedExtensionServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&ExtensionService_ServiceDesc, srv) } diff --git a/proto/extensions/manager_service.pb.go b/proto/extensions/manager_service.pb.go index 92434b607cb4263c4173979b390c034ce562238e..e0a1160ec1d129af4e10528cfba8635b2dc87569 100644 --- a/proto/extensions/manager_service.pb.go +++ b/proto/extensions/manager_service.pb.go @@ -27,8 +27,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: extensions/manager_service.proto package extensions @@ -967,7 +967,7 @@ func file_extensions_manager_service_proto_rawDescGZIP() []byte { var file_extensions_manager_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_extensions_manager_service_proto_msgTypes = make([]protoimpl.MessageInfo, 12) -var file_extensions_manager_service_proto_goTypes = []interface{}{ +var file_extensions_manager_service_proto_goTypes = []any{ (State)(0), // 0: extensions.State (*ListExtensionsRequest)(nil), // 1: extensions.ListExtensionsRequest (*ListExtensionsResponse)(nil), // 2: extensions.ListExtensionsResponse @@ -1012,7 +1012,7 @@ func file_extensions_manager_service_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_extensions_manager_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*ListExtensionsRequest); i { case 0: return &v.state @@ -1024,7 +1024,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*ListExtensionsResponse); i { case 0: return &v.state @@ -1036,7 +1036,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*ExtensionDescriptor); i { case 0: return &v.state @@ -1048,7 +1048,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*RegisterExtensionsRequest); i { case 0: return &v.state @@ -1060,7 +1060,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*RegisterExtensionsResponse); i { case 0: return &v.state @@ -1072,7 +1072,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*UnregisterExtensionsRequest); i { case 0: return &v.state @@ -1084,7 +1084,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*UnregisterExtensionsResponse); i { case 0: return &v.state @@ -1096,7 +1096,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ListRegisteredExtensionsRequest); i { case 0: return &v.state @@ -1108,7 +1108,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ListRegisteredExtensionsResponse); i { case 0: return &v.state @@ -1120,7 +1120,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*SpaceExtensions); i { case 0: return &v.state @@ -1132,7 +1132,7 @@ func file_extensions_manager_service_proto_init() { return nil } } - file_extensions_manager_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_extensions_manager_service_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*ListExtensionsResponse_ExtensionInfo); i { case 0: return &v.state diff --git a/proto/extensions/manager_service_grpc.pb.go b/proto/extensions/manager_service_grpc.pb.go index c75c7cc3ddcc26817ec7baae4bf59cb5ec37f455..07ee35f5122e15a16f9434657f7b397a7f2d1196 100644 --- a/proto/extensions/manager_service_grpc.pb.go +++ b/proto/extensions/manager_service_grpc.pb.go @@ -27,8 +27,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: extensions/manager_service.proto package extensions @@ -42,8 +42,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( ExtensionManagerService_RegisterExtensions_FullMethodName = "/extensions.ExtensionManagerService/RegisterExtensions" @@ -55,6 +55,8 @@ const ( // ExtensionManagerServiceClient is the client API for ExtensionManagerService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// ExtensionManager - менеджер расширений. Должен реализовывать так же сервис Extension type ExtensionManagerServiceClient interface { // ## Регистрация расширений // @@ -85,8 +87,9 @@ func NewExtensionManagerServiceClient(cc grpc.ClientConnInterface) ExtensionMana } func (c *extensionManagerServiceClient) RegisterExtensions(ctx context.Context, in *RegisterExtensionsRequest, opts ...grpc.CallOption) (*RegisterExtensionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(RegisterExtensionsResponse) - err := c.cc.Invoke(ctx, ExtensionManagerService_RegisterExtensions_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionManagerService_RegisterExtensions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -94,8 +97,9 @@ func (c *extensionManagerServiceClient) RegisterExtensions(ctx context.Context, } func (c *extensionManagerServiceClient) UnregisterExtensions(ctx context.Context, in *UnregisterExtensionsRequest, opts ...grpc.CallOption) (*UnregisterExtensionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(UnregisterExtensionsResponse) - err := c.cc.Invoke(ctx, ExtensionManagerService_UnregisterExtensions_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionManagerService_UnregisterExtensions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -103,8 +107,9 @@ func (c *extensionManagerServiceClient) UnregisterExtensions(ctx context.Context } func (c *extensionManagerServiceClient) ListRegisteredExtensions(ctx context.Context, in *ListRegisteredExtensionsRequest, opts ...grpc.CallOption) (*ListRegisteredExtensionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListRegisteredExtensionsResponse) - err := c.cc.Invoke(ctx, ExtensionManagerService_ListRegisteredExtensions_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionManagerService_ListRegisteredExtensions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -112,8 +117,9 @@ func (c *extensionManagerServiceClient) ListRegisteredExtensions(ctx context.Con } func (c *extensionManagerServiceClient) ListExtensions(ctx context.Context, in *ListExtensionsRequest, opts ...grpc.CallOption) (*ListExtensionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListExtensionsResponse) - err := c.cc.Invoke(ctx, ExtensionManagerService_ListExtensions_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, ExtensionManagerService_ListExtensions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -122,7 +128,9 @@ func (c *extensionManagerServiceClient) ListExtensions(ctx context.Context, in * // ExtensionManagerServiceServer is the server API for ExtensionManagerService service. // All implementations must embed UnimplementedExtensionManagerServiceServer -// for forward compatibility +// for forward compatibility. +// +// ExtensionManager - менеджер расширений. Должен реализовывать так же сервис Extension type ExtensionManagerServiceServer interface { // ## Регистрация расширений // @@ -145,9 +153,12 @@ type ExtensionManagerServiceServer interface { mustEmbedUnimplementedExtensionManagerServiceServer() } -// UnimplementedExtensionManagerServiceServer must be embedded to have forward compatible implementations. -type UnimplementedExtensionManagerServiceServer struct { -} +// UnimplementedExtensionManagerServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedExtensionManagerServiceServer struct{} func (UnimplementedExtensionManagerServiceServer) RegisterExtensions(context.Context, *RegisterExtensionsRequest) (*RegisterExtensionsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterExtensions not implemented") @@ -163,6 +174,7 @@ func (UnimplementedExtensionManagerServiceServer) ListExtensions(context.Context } func (UnimplementedExtensionManagerServiceServer) mustEmbedUnimplementedExtensionManagerServiceServer() { } +func (UnimplementedExtensionManagerServiceServer) testEmbeddedByValue() {} // UnsafeExtensionManagerServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ExtensionManagerServiceServer will @@ -172,6 +184,13 @@ type UnsafeExtensionManagerServiceServer interface { } func RegisterExtensionManagerServiceServer(s grpc.ServiceRegistrar, srv ExtensionManagerServiceServer) { + // If the following call pancis, it indicates UnimplementedExtensionManagerServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&ExtensionManagerService_ServiceDesc, srv) } diff --git a/proto/files/files.pb.go b/proto/files/files.pb.go index 8f93164f9b2f1957fd62aca0fe29a7cdc62d4b29..655ebff92f49c17fddd05bb9cfa8a8cf988a2fa2 100644 --- a/proto/files/files.pb.go +++ b/proto/files/files.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: files/files.proto package files @@ -28,7 +28,7 @@ type File struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // Уникальный идентификатор файла в хранилище Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // Имя файла - Size int32 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` // Размер файла + Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` // Размер файла MimeType string `protobuf:"bytes,4,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"` // Mime-type файла Url string `protobuf:"bytes,5,opt,name=url,proto3" json:"url,omitempty"` // Адрес для загрузки файла } @@ -79,7 +79,7 @@ func (x *File) GetName() string { return "" } -func (x *File) GetSize() int32 { +func (x *File) GetSize() uint64 { if x != nil { return x.Size } @@ -107,7 +107,7 @@ type MultipartUpload struct { File *File `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` UploadId string `protobuf:"bytes,2,opt,name=upload_id,json=uploadId,proto3" json:"upload_id,omitempty"` // Идентификатор загрузки хранилища - PartSize int32 `protobuf:"varint,3,opt,name=part_size,json=partSize,proto3" json:"part_size,omitempty"` // Размер блока для загрузки + PartSize uint64 `protobuf:"varint,3,opt,name=part_size,json=partSize,proto3" json:"part_size,omitempty"` // Размер блока для загрузки PartUrls []string `protobuf:"bytes,4,rep,name=part_urls,json=partUrls,proto3" json:"part_urls,omitempty"` // Адреса для загрузки пол Parts []*CompletedPart `protobuf:"bytes,5,rep,name=parts,proto3" json:"parts,omitempty"` // Идентификаторы загруженных блоков (S3 ETAGs) } @@ -158,7 +158,7 @@ func (x *MultipartUpload) GetUploadId() string { return "" } -func (x *MultipartUpload) GetPartSize() int32 { +func (x *MultipartUpload) GetPartSize() uint64 { if x != nil { return x.PartSize } @@ -939,7 +939,7 @@ var file_files_files_proto_rawDesc = []byte{ 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, + 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xb5, 0x01, 0x0a, 0x0f, 0x4d, 0x75, 0x6c, 0x74, 0x69, @@ -948,7 +948,7 @@ var file_files_files_proto_rawDesc = []byte{ 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x74, - 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x72, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x70, 0x61, 0x72, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x72, 0x74, 0x55, 0x72, 0x6c, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, @@ -1060,7 +1060,7 @@ func file_files_files_proto_rawDescGZIP() []byte { } var file_files_files_proto_msgTypes = make([]protoimpl.MessageInfo, 18) -var file_files_files_proto_goTypes = []interface{}{ +var file_files_files_proto_goTypes = []any{ (*File)(nil), // 0: files.File (*MultipartUpload)(nil), // 1: files.MultipartUpload (*Upload)(nil), // 2: files.Upload @@ -1123,7 +1123,7 @@ func file_files_files_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_files_files_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*File); i { case 0: return &v.state @@ -1135,7 +1135,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*MultipartUpload); i { case 0: return &v.state @@ -1147,7 +1147,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Upload); i { case 0: return &v.state @@ -1159,7 +1159,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*CompletedPart); i { case 0: return &v.state @@ -1171,7 +1171,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*StartUploadRequest); i { case 0: return &v.state @@ -1183,7 +1183,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*StartUploadResponse); i { case 0: return &v.state @@ -1195,7 +1195,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*CompleteUploadRequest); i { case 0: return &v.state @@ -1207,7 +1207,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*CompleteUploadResponse); i { case 0: return &v.state @@ -1219,7 +1219,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*AbortUploadRequest); i { case 0: return &v.state @@ -1231,7 +1231,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*AbortUploadResponse); i { case 0: return &v.state @@ -1243,7 +1243,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*MoveUploadRequest); i { case 0: return &v.state @@ -1255,7 +1255,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*MoveUploadResponse); i { case 0: return &v.state @@ -1267,7 +1267,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*UploadRequest); i { case 0: return &v.state @@ -1279,7 +1279,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*UploadResponse); i { case 0: return &v.state @@ -1291,7 +1291,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*GetFileRequest); i { case 0: return &v.state @@ -1303,7 +1303,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*GetFileResponse); i { case 0: return &v.state @@ -1315,7 +1315,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*DeleteFileRequest); i { case 0: return &v.state @@ -1327,7 +1327,7 @@ func file_files_files_proto_init() { return nil } } - file_files_files_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_files_files_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*DeleteFileResponse); i { case 0: return &v.state diff --git a/proto/files/files_grpc.pb.go b/proto/files/files_grpc.pb.go index 234e28599a99f74e704121aeda9e82a9f37005b4..ae5d8c4766e129958ebe093cb636f90bc1756426 100644 --- a/proto/files/files_grpc.pb.go +++ b/proto/files/files_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: files/files.proto package files @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Files_StartUpload_FullMethodName = "/files.Files/StartUpload" @@ -71,8 +71,9 @@ func NewFilesClient(cc grpc.ClientConnInterface) FilesClient { } func (c *filesClient) StartUpload(ctx context.Context, in *StartUploadRequest, opts ...grpc.CallOption) (*StartUploadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StartUploadResponse) - err := c.cc.Invoke(ctx, Files_StartUpload_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_StartUpload_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -80,8 +81,9 @@ func (c *filesClient) StartUpload(ctx context.Context, in *StartUploadRequest, o } func (c *filesClient) CompleteUpload(ctx context.Context, in *CompleteUploadRequest, opts ...grpc.CallOption) (*CompleteUploadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CompleteUploadResponse) - err := c.cc.Invoke(ctx, Files_CompleteUpload_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_CompleteUpload_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -89,8 +91,9 @@ func (c *filesClient) CompleteUpload(ctx context.Context, in *CompleteUploadRequ } func (c *filesClient) AbortUpload(ctx context.Context, in *AbortUploadRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Files_AbortUpload_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_AbortUpload_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -98,8 +101,9 @@ func (c *filesClient) AbortUpload(ctx context.Context, in *AbortUploadRequest, o } func (c *filesClient) MoveUpload(ctx context.Context, in *MoveUploadRequest, opts ...grpc.CallOption) (*MoveUploadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MoveUploadResponse) - err := c.cc.Invoke(ctx, Files_MoveUpload_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_MoveUpload_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -107,8 +111,9 @@ func (c *filesClient) MoveUpload(ctx context.Context, in *MoveUploadRequest, opt } func (c *filesClient) Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(UploadResponse) - err := c.cc.Invoke(ctx, Files_Upload_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_Upload_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -116,8 +121,9 @@ func (c *filesClient) Upload(ctx context.Context, in *UploadRequest, opts ...grp } func (c *filesClient) GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (*GetFileResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetFileResponse) - err := c.cc.Invoke(ctx, Files_GetFile_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_GetFile_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -125,8 +131,9 @@ func (c *filesClient) GetFile(ctx context.Context, in *GetFileRequest, opts ...g } func (c *filesClient) DeleteFile(ctx context.Context, in *DeleteFileRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Files_DeleteFile_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Files_DeleteFile_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -135,7 +142,7 @@ func (c *filesClient) DeleteFile(ctx context.Context, in *DeleteFileRequest, opt // FilesServer is the server API for Files service. // All implementations must embed UnimplementedFilesServer -// for forward compatibility +// for forward compatibility. type FilesServer interface { // StartUpload - инициирует процедуру загрузки файла в файловое хранилище. // Используется клиентским приложением для начала загрузки файла @@ -167,9 +174,12 @@ type FilesServer interface { mustEmbedUnimplementedFilesServer() } -// UnimplementedFilesServer must be embedded to have forward compatible implementations. -type UnimplementedFilesServer struct { -} +// UnimplementedFilesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedFilesServer struct{} func (UnimplementedFilesServer) StartUpload(context.Context, *StartUploadRequest) (*StartUploadResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method StartUpload not implemented") @@ -193,6 +203,7 @@ func (UnimplementedFilesServer) DeleteFile(context.Context, *DeleteFileRequest) return nil, status.Errorf(codes.Unimplemented, "method DeleteFile not implemented") } func (UnimplementedFilesServer) mustEmbedUnimplementedFilesServer() {} +func (UnimplementedFilesServer) testEmbeddedByValue() {} // UnsafeFilesServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to FilesServer will @@ -202,6 +213,13 @@ type UnsafeFilesServer interface { } func RegisterFilesServer(s grpc.ServiceRegistrar, srv FilesServer) { + // If the following call pancis, it indicates UnimplementedFilesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Files_ServiceDesc, srv) } diff --git a/proto/images/images.pb.go b/proto/images/images.pb.go index 4f95cb6da087725f8af05fbca35955d9e02c7608..e84dae61c1ff2493731ccfbcaec30046b6c7b6fc 100644 --- a/proto/images/images.pb.go +++ b/proto/images/images.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: images/images.proto package images @@ -270,7 +270,7 @@ func file_images_images_proto_rawDescGZIP() []byte { } var file_images_images_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_images_images_proto_goTypes = []interface{}{ +var file_images_images_proto_goTypes = []any{ (*Param)(nil), // 0: images.Param (*GetRequest)(nil), // 1: images.GetRequest (*GetResponse)(nil), // 2: images.GetResponse @@ -297,7 +297,7 @@ func file_images_images_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_images_images_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_images_images_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Param); i { case 0: return &v.state @@ -309,7 +309,7 @@ func file_images_images_proto_init() { return nil } } - file_images_images_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_images_images_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -321,7 +321,7 @@ func file_images_images_proto_init() { return nil } } - file_images_images_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_images_images_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -333,7 +333,7 @@ func file_images_images_proto_init() { return nil } } - file_images_images_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_images_images_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*GetRequest_GetOptions); i { case 0: return &v.state diff --git a/proto/images/images_grpc.pb.go b/proto/images/images_grpc.pb.go index 272c6580743f491a78834708bdcacfef2a166f86..669dcc8e9a29cefefb38ade60d4d48900d268707 100644 --- a/proto/images/images_grpc.pb.go +++ b/proto/images/images_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: images/images.proto package images @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Images_Get_FullMethodName = "/images.Images/Get" @@ -25,6 +25,8 @@ const ( // ImagesClient is the client API for Images service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// ImageService - сервис для обработки изображений type ImagesClient interface { // Get - к файлу, идентификатор которого передан в запросе, применяются параметры. // Может быть передано несколько параметров, порядок учитывается при обработке @@ -47,8 +49,9 @@ func NewImagesClient(cc grpc.ClientConnInterface) ImagesClient { } func (c *imagesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Images_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Images_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -57,7 +60,9 @@ func (c *imagesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Cal // ImagesServer is the server API for Images service. // All implementations must embed UnimplementedImagesServer -// for forward compatibility +// for forward compatibility. +// +// ImageService - сервис для обработки изображений type ImagesServer interface { // Get - к файлу, идентификатор которого передан в запросе, применяются параметры. // Может быть передано несколько параметров, порядок учитывается при обработке @@ -72,14 +77,18 @@ type ImagesServer interface { mustEmbedUnimplementedImagesServer() } -// UnimplementedImagesServer must be embedded to have forward compatible implementations. -type UnimplementedImagesServer struct { -} +// UnimplementedImagesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedImagesServer struct{} func (UnimplementedImagesServer) Get(context.Context, *GetRequest) (*GetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") } func (UnimplementedImagesServer) mustEmbedUnimplementedImagesServer() {} +func (UnimplementedImagesServer) testEmbeddedByValue() {} // UnsafeImagesServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ImagesServer will @@ -89,6 +98,13 @@ type UnsafeImagesServer interface { } func RegisterImagesServer(s grpc.ServiceRegistrar, srv ImagesServer) { + // If the following call pancis, it indicates UnimplementedImagesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Images_ServiceDesc, srv) } diff --git a/proto/invitations/invitations.pb.go b/proto/invitations/invitations.pb.go index 1e9fd729c0ffba1903d60f70ba8f89041684b11d..5fd81d66ef5f3b27a7d8c4de428cca03e6d53de1 100644 --- a/proto/invitations/invitations.pb.go +++ b/proto/invitations/invitations.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: invitations/invitations.proto package invitations @@ -1021,7 +1021,7 @@ func file_invitations_invitations_proto_rawDescGZIP() []byte { } var file_invitations_invitations_proto_msgTypes = make([]protoimpl.MessageInfo, 15) -var file_invitations_invitations_proto_goTypes = []interface{}{ +var file_invitations_invitations_proto_goTypes = []any{ (*Invitation)(nil), // 0: content.invitations.Invitation (*Filter)(nil), // 1: content.invitations.Filter (*FindOptions)(nil), // 2: content.invitations.FindOptions @@ -1077,7 +1077,7 @@ func file_invitations_invitations_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_invitations_invitations_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Invitation); i { case 0: return &v.state @@ -1089,7 +1089,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Filter); i { case 0: return &v.state @@ -1101,7 +1101,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*FindOptions); i { case 0: return &v.state @@ -1113,7 +1113,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -1125,7 +1125,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -1137,7 +1137,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -1149,7 +1149,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -1161,7 +1161,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1173,7 +1173,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*UpdateInvitationResponse); i { case 0: return &v.state @@ -1185,7 +1185,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*AcceptRequest); i { case 0: return &v.state @@ -1197,7 +1197,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*AcceptInvitationResponse); i { case 0: return &v.state @@ -1209,7 +1209,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*FindRequest); i { case 0: return &v.state @@ -1221,7 +1221,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*FindResponse); i { case 0: return &v.state @@ -1233,7 +1233,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -1245,7 +1245,7 @@ func file_invitations_invitations_proto_init() { return nil } } - file_invitations_invitations_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_invitations_invitations_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*DeleteSpaceInvitationResponse); i { case 0: return &v.state diff --git a/proto/invitations/invitations_grpc.pb.go b/proto/invitations/invitations_grpc.pb.go index d5137fec4deee51fb509d7ee0ba9e0c235f57668..767261cba6341aea650345743e27fce8804d3d99 100644 --- a/proto/invitations/invitations_grpc.pb.go +++ b/proto/invitations/invitations_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: invitations/invitations.proto package invitations @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Invitations_Create_FullMethodName = "/content.invitations.Invitations/Create" @@ -51,8 +51,9 @@ func NewInvitationsClient(cc grpc.ClientConnInterface) InvitationsClient { } func (c *invitationsClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Invitations_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Invitations_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -60,8 +61,9 @@ func (c *invitationsClient) Create(ctx context.Context, in *CreateRequest, opts } func (c *invitationsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Invitations_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Invitations_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -69,8 +71,9 @@ func (c *invitationsClient) Get(ctx context.Context, in *GetRequest, opts ...grp } func (c *invitationsClient) Accept(ctx context.Context, in *AcceptRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Invitations_Accept_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Invitations_Accept_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -78,8 +81,9 @@ func (c *invitationsClient) Accept(ctx context.Context, in *AcceptRequest, opts } func (c *invitationsClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindResponse) - err := c.cc.Invoke(ctx, Invitations_Find_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Invitations_Find_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -87,8 +91,9 @@ func (c *invitationsClient) Find(ctx context.Context, in *FindRequest, opts ...g } func (c *invitationsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Invitations_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Invitations_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -97,7 +102,7 @@ func (c *invitationsClient) Delete(ctx context.Context, in *DeleteRequest, opts // InvitationsServer is the server API for Invitations service. // All implementations must embed UnimplementedInvitationsServer -// for forward compatibility +// for forward compatibility. type InvitationsServer interface { Create(context.Context, *CreateRequest) (*CreateResponse, error) // Получить данные о приглашении @@ -111,9 +116,12 @@ type InvitationsServer interface { mustEmbedUnimplementedInvitationsServer() } -// UnimplementedInvitationsServer must be embedded to have forward compatible implementations. -type UnimplementedInvitationsServer struct { -} +// UnimplementedInvitationsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedInvitationsServer struct{} func (UnimplementedInvitationsServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -131,6 +139,7 @@ func (UnimplementedInvitationsServer) Delete(context.Context, *DeleteRequest) (* return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func (UnimplementedInvitationsServer) mustEmbedUnimplementedInvitationsServer() {} +func (UnimplementedInvitationsServer) testEmbeddedByValue() {} // UnsafeInvitationsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to InvitationsServer will @@ -140,6 +149,13 @@ type UnsafeInvitationsServer interface { } func RegisterInvitationsServer(s grpc.ServiceRegistrar, srv InvitationsServer) { + // If the following call pancis, it indicates UnimplementedInvitationsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Invitations_ServiceDesc, srv) } diff --git a/proto/items/items.pb.go b/proto/items/items.pb.go index 7843fcdbb318fbf0540eb789b3fe50ed6e687a0c..a49876ec9c67d5a76a29330cff5dfea32c51c0aa 100644 --- a/proto/items/items.pb.go +++ b/proto/items/items.pb.go @@ -8,8 +8,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: items/items.proto package items @@ -366,25 +366,42 @@ type Item struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - SpaceId string `protobuf:"bytes,2,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` - EnvId string `protobuf:"bytes,3,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` - CollectionId string `protobuf:"bytes,4,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` - State Item_State `protobuf:"varint,5,opt,name=state,proto3,enum=content.items.Item_State" json:"state,omitempty"` - CreatedRevAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_rev_at,json=createdRevAt,proto3" json:"created_rev_at,omitempty"` // дата создания текущей ревизии - CreatedBy string `protobuf:"bytes,7,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` // id пользователя создавшего первую ревизию - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // дата создания первой ревизии - UpdatedBy string `protobuf:"bytes,9,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"` // id пользователя обновившего текущую ревизию - UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` // дата обновления текущей ревизии - Data *structpb.Struct `protobuf:"bytes,11,opt,name=data,proto3" json:"data,omitempty"` - Translations map[string]*structpb.Struct `protobuf:"bytes,12,rep,name=translations,proto3" json:"translations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - RevisionId string `protobuf:"bytes,13,opt,name=revision_id,json=revisionId,proto3" json:"revision_id,omitempty"` - RevisionDescription string `protobuf:"bytes,14,opt,name=revision_description,json=revisionDescription,proto3" json:"revision_description,omitempty"` - Locale string `protobuf:"bytes,18,opt,name=locale,proto3" json:"locale,omitempty"` - Deleted bool `protobuf:"varint,19,opt,name=deleted,proto3" json:"deleted,omitempty"` - Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` - Template bool `protobuf:"varint,21,opt,name=template,proto3" json:"template,omitempty"` - Permissions *Permissions `protobuf:"bytes,22,opt,name=permissions,proto3" json:"permissions,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + SpaceId string `protobuf:"bytes,2,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` + EnvId string `protobuf:"bytes,3,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` + CollectionId string `protobuf:"bytes,4,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` + State Item_State `protobuf:"varint,5,opt,name=state,proto3,enum=content.items.Item_State" json:"state,omitempty"` + CreatedRevAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_rev_at,json=createdRevAt,proto3" json:"created_rev_at,omitempty"` // дата создания текущей ревизии + CreatedBy string `protobuf:"bytes,7,opt,name=created_by,json=createdBy,proto3" json:"created_by,omitempty"` // id пользователя создавшего первую ревизию + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // дата создания первой ревизии + UpdatedBy string `protobuf:"bytes,9,opt,name=updated_by,json=updatedBy,proto3" json:"updated_by,omitempty"` // id пользователя обновившего текущую ревизию + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` // дата обновления текущей ревизии + Data *structpb.Struct `protobuf:"bytes,11,opt,name=data,proto3" json:"data,omitempty"` + RevisionId string `protobuf:"bytes,13,opt,name=revision_id,json=revisionId,proto3" json:"revision_id,omitempty"` + RevisionDescription string `protobuf:"bytes,14,opt,name=revision_description,json=revisionDescription,proto3" json:"revision_description,omitempty"` + Deleted bool `protobuf:"varint,19,opt,name=deleted,proto3" json:"deleted,omitempty"` + Hidden bool `protobuf:"varint,20,opt,name=hidden,proto3" json:"hidden,omitempty"` + Template bool `protobuf:"varint,21,opt,name=template,proto3" json:"template,omitempty"` + Permissions *Permissions `protobuf:"bytes,22,opt,name=permissions,proto3" json:"permissions,omitempty"` + SearchScore float64 `protobuf:"fixed64,23,opt,name=search_score,json=searchScore,proto3" json:"search_score,omitempty"` // релеватность элемента при полнотекстовом поиске + // Идентификатор локали полученной записи. + // При создании или обновлении идентификатор локали, в которой создается запись, опционально. + // Если указан, то создается перевод для указанного языка, поле translations игнорируется + LocaleId string `protobuf:"bytes,100,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` + // Позволяет одновременно установить/получить несколько переводов и производить манипуляции с переводами + // Ключами является идентификатор локали, значениями - данные переводы + // При обновлении не происходит валидация или модификация каждого из переводов в соответствие со схемой, + // поэтому обновление через поле `translations` стоит выполнять с аккуратностью + // Для удаления переводов реализована следующая логика: + // - {"lang":nil|{}} - сброс перевода для языка + // - {"lang":map{...}} - установка перевода для языка + // - {"lang":map{...}, "*":nil} - установка перевода для языка, сброс остальных переводов + // - {"*":nil} - сброс всех переводов + Translations map[string]*structpb.Struct `protobuf:"bytes,12,rep,name=translations,proto3" json:"translations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Список идентификаторов локалей, для которых есть переводы + // Соотвествует списку переводов в translations, при получении записи всегда возвращается + // полный список. Невозможно обновить вручную: формируется системой + TranslationsIds []string `protobuf:"bytes,101,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` } func (x *Item) Reset() { @@ -496,13 +513,6 @@ func (x *Item) GetData() *structpb.Struct { return nil } -func (x *Item) GetTranslations() map[string]*structpb.Struct { - if x != nil { - return x.Translations - } - return nil -} - func (x *Item) GetRevisionId() string { if x != nil { return x.RevisionId @@ -517,13 +527,6 @@ func (x *Item) GetRevisionDescription() string { return "" } -func (x *Item) GetLocale() string { - if x != nil { - return x.Locale - } - return "" -} - func (x *Item) GetDeleted() bool { if x != nil { return x.Deleted @@ -552,6 +555,34 @@ func (x *Item) GetPermissions() *Permissions { return nil } +func (x *Item) GetSearchScore() float64 { + if x != nil { + return x.SearchScore + } + return 0 +} + +func (x *Item) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *Item) GetTranslations() map[string]*structpb.Struct { + if x != nil { + return x.Translations + } + return nil +} + +func (x *Item) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + type EventCreate struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1027,6 +1058,10 @@ type FindOptions struct { Regular bool `protobuf:"varint,4,opt,name=regular,proto3" json:"regular,omitempty"` Hidden bool `protobuf:"varint,5,opt,name=hidden,proto3" json:"hidden,omitempty"` Templates bool `protobuf:"varint,6,opt,name=templates,proto3" json:"templates,omitempty"` + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + // Возможно указание '*' для получения всех переводов + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` } func (x *FindOptions) Reset() { @@ -1096,6 +1131,20 @@ func (x *FindOptions) GetTemplates() bool { return false } +func (x *FindOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *FindOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + type UpdateOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1148,7 +1197,10 @@ type GetPublishedOptions struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - LocaleId string `protobuf:"bytes,1,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + // Возможно указание '*' для получения всех переводов + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` } func (x *GetPublishedOptions) Reset() { @@ -1190,6 +1242,13 @@ func (x *GetPublishedOptions) GetLocaleId() string { return "" } +func (x *GetPublishedOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + type DeleteOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1391,11 +1450,15 @@ type FindPublishedOptions struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` - LocaleId string `protobuf:"bytes,3,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` - Regular bool `protobuf:"varint,4,opt,name=regular,proto3" json:"regular,omitempty"` - Hidden bool `protobuf:"varint,5,opt,name=hidden,proto3" json:"hidden,omitempty"` - Templates bool `protobuf:"varint,6,opt,name=templates,proto3" json:"templates,omitempty"` + Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + // string locale_id = 3; // язык для поиска переводов. Если не указан, то возвращаются данные для языка по умолчанию + Regular bool `protobuf:"varint,4,opt,name=regular,proto3" json:"regular,omitempty"` + Hidden bool `protobuf:"varint,5,opt,name=hidden,proto3" json:"hidden,omitempty"` + Templates bool `protobuf:"varint,6,opt,name=templates,proto3" json:"templates,omitempty"` + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + // Список идентификаторов переводов/локалей, которых должны быть включены в результат + // Возможно указание '*' для получения всех переводов + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` } func (x *FindPublishedOptions) Reset() { @@ -1437,13 +1500,6 @@ func (x *FindPublishedOptions) GetOptions() *common.FindOptions { return nil } -func (x *FindPublishedOptions) GetLocaleId() string { - if x != nil { - return x.LocaleId - } - return "" -} - func (x *FindPublishedOptions) GetRegular() bool { if x != nil { return x.Regular @@ -1465,12 +1521,28 @@ func (x *FindPublishedOptions) GetTemplates() bool { return false } +func (x *FindPublishedOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *FindPublishedOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + type FindArchivedOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` // Список идентификаторов переводов/локалей, которых должны быть включены в результат } func (x *FindArchivedOptions) Reset() { @@ -1512,12 +1584,28 @@ func (x *FindArchivedOptions) GetOptions() *common.FindOptions { return nil } +func (x *FindArchivedOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *FindArchivedOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + type ListRevisionsOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` // Список идентификаторов переводов/локалей, которых должны быть включены в результат } func (x *ListRevisionsOptions) Reset() { @@ -1559,6 +1647,75 @@ func (x *ListRevisionsOptions) GetOptions() *common.FindOptions { return nil } +func (x *ListRevisionsOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *ListRevisionsOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + +type GetRevisionOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` // Список идентификаторов переводов/локалей, которых должны быть включены в результат +} + +func (x *GetRevisionOptions) Reset() { + *x = GetRevisionOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_items_items_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRevisionOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRevisionOptions) ProtoMessage() {} + +func (x *GetRevisionOptions) ProtoReflect() protoreflect.Message { + mi := &file_items_items_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRevisionOptions.ProtoReflect.Descriptor instead. +func (*GetRevisionOptions) Descriptor() ([]byte, []int) { + return file_items_items_proto_rawDescGZIP(), []int{23} +} + +func (x *GetRevisionOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *GetRevisionOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + // Fields - поля которые должны быть возвращены или вычислены в результате. // Ключ (string) - имя поля под которым будет добавляться результат. // Значение (string) - является выражением, вычисление которого сформирует результат @@ -1581,7 +1738,7 @@ type AggregateOptions struct { func (x *AggregateOptions) Reset() { *x = AggregateOptions{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[23] + mi := &file_items_items_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1594,7 +1751,7 @@ func (x *AggregateOptions) String() string { func (*AggregateOptions) ProtoMessage() {} func (x *AggregateOptions) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[23] + mi := &file_items_items_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1607,7 +1764,7 @@ func (x *AggregateOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregateOptions.ProtoReflect.Descriptor instead. func (*AggregateOptions) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{23} + return file_items_items_proto_rawDescGZIP(), []int{24} } func (x *AggregateOptions) GetFields() map[string]string { @@ -1628,7 +1785,7 @@ type AggregatePublishedOptions struct { func (x *AggregatePublishedOptions) Reset() { *x = AggregatePublishedOptions{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[24] + mi := &file_items_items_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1641,7 +1798,7 @@ func (x *AggregatePublishedOptions) String() string { func (*AggregatePublishedOptions) ProtoMessage() {} func (x *AggregatePublishedOptions) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[24] + mi := &file_items_items_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1654,7 +1811,7 @@ func (x *AggregatePublishedOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregatePublishedOptions.ProtoReflect.Descriptor instead. func (*AggregatePublishedOptions) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{24} + return file_items_items_proto_rawDescGZIP(), []int{25} } func (x *AggregatePublishedOptions) GetFields() map[string]string { @@ -1676,7 +1833,7 @@ type CreateRequest struct { func (x *CreateRequest) Reset() { *x = CreateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[25] + mi := &file_items_items_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1689,7 +1846,7 @@ func (x *CreateRequest) String() string { func (*CreateRequest) ProtoMessage() {} func (x *CreateRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[25] + mi := &file_items_items_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1702,7 +1859,7 @@ func (x *CreateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateRequest.ProtoReflect.Descriptor instead. func (*CreateRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{25} + return file_items_items_proto_rawDescGZIP(), []int{26} } func (x *CreateRequest) GetItem() *Item { @@ -1730,7 +1887,7 @@ type CreateResponse struct { func (x *CreateResponse) Reset() { *x = CreateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[26] + mi := &file_items_items_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1743,7 +1900,7 @@ func (x *CreateResponse) String() string { func (*CreateResponse) ProtoMessage() {} func (x *CreateResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[26] + mi := &file_items_items_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1756,7 +1913,7 @@ func (x *CreateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateResponse.ProtoReflect.Descriptor instead. func (*CreateResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{26} + return file_items_items_proto_rawDescGZIP(), []int{27} } func (x *CreateResponse) GetCreated() *Item { @@ -1777,7 +1934,7 @@ type IntrospectRequest struct { func (x *IntrospectRequest) Reset() { *x = IntrospectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[27] + mi := &file_items_items_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1790,7 +1947,7 @@ func (x *IntrospectRequest) String() string { func (*IntrospectRequest) ProtoMessage() {} func (x *IntrospectRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[27] + mi := &file_items_items_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1803,7 +1960,7 @@ func (x *IntrospectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use IntrospectRequest.ProtoReflect.Descriptor instead. func (*IntrospectRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{27} + return file_items_items_proto_rawDescGZIP(), []int{28} } func (x *IntrospectRequest) GetItem() *Item { @@ -1826,7 +1983,7 @@ type IntrospectResponse struct { func (x *IntrospectResponse) Reset() { *x = IntrospectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[28] + mi := &file_items_items_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1839,7 +1996,7 @@ func (x *IntrospectResponse) String() string { func (*IntrospectResponse) ProtoMessage() {} func (x *IntrospectResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[28] + mi := &file_items_items_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1852,7 +2009,7 @@ func (x *IntrospectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use IntrospectResponse.ProtoReflect.Descriptor instead. func (*IntrospectResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{28} + return file_items_items_proto_rawDescGZIP(), []int{29} } func (x *IntrospectResponse) GetItem() *Item { @@ -1876,21 +2033,77 @@ func (x *IntrospectResponse) GetValidationErrors() []*common.Error_BadRequest_Fi return nil } +type GetOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LocaleId string `protobuf:"bytes,7,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + TranslationsIds []string `protobuf:"bytes,8,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` // Список идентификаторов переводов/локалей, которых должны быть включены в результат +} + +func (x *GetOptions) Reset() { + *x = GetOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_items_items_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetOptions) ProtoMessage() {} + +func (x *GetOptions) ProtoReflect() protoreflect.Message { + mi := &file_items_items_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetOptions.ProtoReflect.Descriptor instead. +func (*GetOptions) Descriptor() ([]byte, []int) { + return file_items_items_proto_rawDescGZIP(), []int{30} +} + +func (x *GetOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *GetOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + type GetRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` - EnvId string `protobuf:"bytes,2,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` - CollectionId string `protobuf:"bytes,3,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` - ItemId string `protobuf:"bytes,4,opt,name=item_id,json=itemId,proto3" json:"item_id,omitempty"` + SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` + EnvId string `protobuf:"bytes,2,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` + CollectionId string `protobuf:"bytes,3,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` + ItemId string `protobuf:"bytes,4,opt,name=item_id,json=itemId,proto3" json:"item_id,omitempty"` + Options *GetOptions `protobuf:"bytes,5,opt,name=options,proto3" json:"options,omitempty"` } func (x *GetRequest) Reset() { *x = GetRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[29] + mi := &file_items_items_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1903,7 +2116,7 @@ func (x *GetRequest) String() string { func (*GetRequest) ProtoMessage() {} func (x *GetRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[29] + mi := &file_items_items_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1916,7 +2129,7 @@ func (x *GetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRequest.ProtoReflect.Descriptor instead. func (*GetRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{29} + return file_items_items_proto_rawDescGZIP(), []int{31} } func (x *GetRequest) GetSpaceId() string { @@ -1947,6 +2160,13 @@ func (x *GetRequest) GetItemId() string { return "" } +func (x *GetRequest) GetOptions() *GetOptions { + if x != nil { + return x.Options + } + return nil +} + type GetResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1958,7 +2178,7 @@ type GetResponse struct { func (x *GetResponse) Reset() { *x = GetResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[30] + mi := &file_items_items_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1971,7 +2191,7 @@ func (x *GetResponse) String() string { func (*GetResponse) ProtoMessage() {} func (x *GetResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[30] + mi := &file_items_items_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1984,7 +2204,7 @@ func (x *GetResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetResponse.ProtoReflect.Descriptor instead. func (*GetResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{30} + return file_items_items_proto_rawDescGZIP(), []int{32} } func (x *GetResponse) GetItem() *Item { @@ -2009,7 +2229,7 @@ type FindRequest struct { func (x *FindRequest) Reset() { *x = FindRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[31] + mi := &file_items_items_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2022,7 +2242,7 @@ func (x *FindRequest) String() string { func (*FindRequest) ProtoMessage() {} func (x *FindRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[31] + mi := &file_items_items_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2035,7 +2255,7 @@ func (x *FindRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FindRequest.ProtoReflect.Descriptor instead. func (*FindRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{31} + return file_items_items_proto_rawDescGZIP(), []int{33} } func (x *FindRequest) GetSpaceId() string { @@ -2085,7 +2305,7 @@ type FindResponse struct { func (x *FindResponse) Reset() { *x = FindResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[32] + mi := &file_items_items_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2098,7 +2318,7 @@ func (x *FindResponse) String() string { func (*FindResponse) ProtoMessage() {} func (x *FindResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[32] + mi := &file_items_items_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2111,7 +2331,7 @@ func (x *FindResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FindResponse.ProtoReflect.Descriptor instead. func (*FindResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{32} + return file_items_items_proto_rawDescGZIP(), []int{34} } func (x *FindResponse) GetItems() []*Item { @@ -2140,7 +2360,7 @@ type UpdateRequest struct { func (x *UpdateRequest) Reset() { *x = UpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[33] + mi := &file_items_items_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2153,7 +2373,7 @@ func (x *UpdateRequest) String() string { func (*UpdateRequest) ProtoMessage() {} func (x *UpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[33] + mi := &file_items_items_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2166,7 +2386,7 @@ func (x *UpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateRequest.ProtoReflect.Descriptor instead. func (*UpdateRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{33} + return file_items_items_proto_rawDescGZIP(), []int{35} } func (x *UpdateRequest) GetItem() *Item { @@ -2195,7 +2415,7 @@ type DeleteRequest struct { func (x *DeleteRequest) Reset() { *x = DeleteRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[34] + mi := &file_items_items_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2208,7 +2428,7 @@ func (x *DeleteRequest) String() string { func (*DeleteRequest) ProtoMessage() {} func (x *DeleteRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[34] + mi := &file_items_items_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2221,7 +2441,7 @@ func (x *DeleteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. func (*DeleteRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{34} + return file_items_items_proto_rawDescGZIP(), []int{36} } func (x *DeleteRequest) GetItem() *Item { @@ -2250,7 +2470,7 @@ type UndeleteRequest struct { func (x *UndeleteRequest) Reset() { *x = UndeleteRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[35] + mi := &file_items_items_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2263,7 +2483,7 @@ func (x *UndeleteRequest) String() string { func (*UndeleteRequest) ProtoMessage() {} func (x *UndeleteRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[35] + mi := &file_items_items_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2276,7 +2496,7 @@ func (x *UndeleteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UndeleteRequest.ProtoReflect.Descriptor instead. func (*UndeleteRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{35} + return file_items_items_proto_rawDescGZIP(), []int{37} } func (x *UndeleteRequest) GetItem() *Item { @@ -2305,7 +2525,7 @@ type PublishRequest struct { func (x *PublishRequest) Reset() { *x = PublishRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[36] + mi := &file_items_items_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2318,7 +2538,7 @@ func (x *PublishRequest) String() string { func (*PublishRequest) ProtoMessage() {} func (x *PublishRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[36] + mi := &file_items_items_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2331,7 +2551,7 @@ func (x *PublishRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PublishRequest.ProtoReflect.Descriptor instead. func (*PublishRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{36} + return file_items_items_proto_rawDescGZIP(), []int{38} } func (x *PublishRequest) GetItem() *Item { @@ -2360,7 +2580,7 @@ type UnpublishRequest struct { func (x *UnpublishRequest) Reset() { *x = UnpublishRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[37] + mi := &file_items_items_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2373,7 +2593,7 @@ func (x *UnpublishRequest) String() string { func (*UnpublishRequest) ProtoMessage() {} func (x *UnpublishRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[37] + mi := &file_items_items_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2386,7 +2606,7 @@ func (x *UnpublishRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnpublishRequest.ProtoReflect.Descriptor instead. func (*UnpublishRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{37} + return file_items_items_proto_rawDescGZIP(), []int{39} } func (x *UnpublishRequest) GetItem() *Item { @@ -2418,7 +2638,7 @@ type GetPublishedRequest struct { func (x *GetPublishedRequest) Reset() { *x = GetPublishedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[38] + mi := &file_items_items_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2431,7 +2651,7 @@ func (x *GetPublishedRequest) String() string { func (*GetPublishedRequest) ProtoMessage() {} func (x *GetPublishedRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[38] + mi := &file_items_items_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2444,7 +2664,7 @@ func (x *GetPublishedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPublishedRequest.ProtoReflect.Descriptor instead. func (*GetPublishedRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{38} + return file_items_items_proto_rawDescGZIP(), []int{40} } func (x *GetPublishedRequest) GetSpaceId() string { @@ -2493,7 +2713,7 @@ type GetPublishedResponse struct { func (x *GetPublishedResponse) Reset() { *x = GetPublishedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[39] + mi := &file_items_items_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2506,7 +2726,7 @@ func (x *GetPublishedResponse) String() string { func (*GetPublishedResponse) ProtoMessage() {} func (x *GetPublishedResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[39] + mi := &file_items_items_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2519,7 +2739,7 @@ func (x *GetPublishedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPublishedResponse.ProtoReflect.Descriptor instead. func (*GetPublishedResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{39} + return file_items_items_proto_rawDescGZIP(), []int{41} } func (x *GetPublishedResponse) GetItem() *Item { @@ -2544,7 +2764,7 @@ type FindPublishedRequest struct { func (x *FindPublishedRequest) Reset() { *x = FindPublishedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[40] + mi := &file_items_items_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2557,7 +2777,7 @@ func (x *FindPublishedRequest) String() string { func (*FindPublishedRequest) ProtoMessage() {} func (x *FindPublishedRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[40] + mi := &file_items_items_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2570,7 +2790,7 @@ func (x *FindPublishedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FindPublishedRequest.ProtoReflect.Descriptor instead. func (*FindPublishedRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{40} + return file_items_items_proto_rawDescGZIP(), []int{42} } func (x *FindPublishedRequest) GetSpaceId() string { @@ -2620,7 +2840,7 @@ type FindPublishedResponse struct { func (x *FindPublishedResponse) Reset() { *x = FindPublishedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[41] + mi := &file_items_items_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2633,7 +2853,7 @@ func (x *FindPublishedResponse) String() string { func (*FindPublishedResponse) ProtoMessage() {} func (x *FindPublishedResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[41] + mi := &file_items_items_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2646,7 +2866,7 @@ func (x *FindPublishedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FindPublishedResponse.ProtoReflect.Descriptor instead. func (*FindPublishedResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{41} + return file_items_items_proto_rawDescGZIP(), []int{43} } func (x *FindPublishedResponse) GetItems() []*Item { @@ -2678,7 +2898,7 @@ type AggregateRequest struct { func (x *AggregateRequest) Reset() { *x = AggregateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[42] + mi := &file_items_items_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2691,7 +2911,7 @@ func (x *AggregateRequest) String() string { func (*AggregateRequest) ProtoMessage() {} func (x *AggregateRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[42] + mi := &file_items_items_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2704,7 +2924,7 @@ func (x *AggregateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregateRequest.ProtoReflect.Descriptor instead. func (*AggregateRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{42} + return file_items_items_proto_rawDescGZIP(), []int{44} } func (x *AggregateRequest) GetSpaceId() string { @@ -2755,7 +2975,7 @@ type AggregateResponse struct { func (x *AggregateResponse) Reset() { *x = AggregateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[43] + mi := &file_items_items_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2768,7 +2988,7 @@ func (x *AggregateResponse) String() string { func (*AggregateResponse) ProtoMessage() {} func (x *AggregateResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[43] + mi := &file_items_items_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2781,7 +3001,7 @@ func (x *AggregateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregateResponse.ProtoReflect.Descriptor instead. func (*AggregateResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{43} + return file_items_items_proto_rawDescGZIP(), []int{45} } func (x *AggregateResponse) GetResult() *structpb.Struct { @@ -2806,7 +3026,7 @@ type AggregatePublishedRequest struct { func (x *AggregatePublishedRequest) Reset() { *x = AggregatePublishedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[44] + mi := &file_items_items_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2819,7 +3039,7 @@ func (x *AggregatePublishedRequest) String() string { func (*AggregatePublishedRequest) ProtoMessage() {} func (x *AggregatePublishedRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[44] + mi := &file_items_items_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2832,7 +3052,7 @@ func (x *AggregatePublishedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregatePublishedRequest.ProtoReflect.Descriptor instead. func (*AggregatePublishedRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{44} + return file_items_items_proto_rawDescGZIP(), []int{46} } func (x *AggregatePublishedRequest) GetSpaceId() string { @@ -2881,7 +3101,7 @@ type AggregatePublishedResponse struct { func (x *AggregatePublishedResponse) Reset() { *x = AggregatePublishedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[45] + mi := &file_items_items_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2894,7 +3114,7 @@ func (x *AggregatePublishedResponse) String() string { func (*AggregatePublishedResponse) ProtoMessage() {} func (x *AggregatePublishedResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[45] + mi := &file_items_items_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2907,7 +3127,7 @@ func (x *AggregatePublishedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregatePublishedResponse.ProtoReflect.Descriptor instead. func (*AggregatePublishedResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{45} + return file_items_items_proto_rawDescGZIP(), []int{47} } func (x *AggregatePublishedResponse) GetResult() *structpb.Struct { @@ -2922,17 +3142,18 @@ type GetRevisionRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` - EnvId string `protobuf:"bytes,2,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` - CollectionId string `protobuf:"bytes,3,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` - ItemId string `protobuf:"bytes,4,opt,name=item_id,json=itemId,proto3" json:"item_id,omitempty"` - RevisionId string `protobuf:"bytes,5,opt,name=revision_id,json=revisionId,proto3" json:"revision_id,omitempty"` + SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` + EnvId string `protobuf:"bytes,2,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` + CollectionId string `protobuf:"bytes,3,opt,name=collection_id,json=collectionId,proto3" json:"collection_id,omitempty"` + ItemId string `protobuf:"bytes,4,opt,name=item_id,json=itemId,proto3" json:"item_id,omitempty"` + RevisionId string `protobuf:"bytes,5,opt,name=revision_id,json=revisionId,proto3" json:"revision_id,omitempty"` + Options *GetRevisionOptions `protobuf:"bytes,10,opt,name=options,proto3" json:"options,omitempty"` } func (x *GetRevisionRequest) Reset() { *x = GetRevisionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[46] + mi := &file_items_items_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2945,7 +3166,7 @@ func (x *GetRevisionRequest) String() string { func (*GetRevisionRequest) ProtoMessage() {} func (x *GetRevisionRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[46] + mi := &file_items_items_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2958,7 +3179,7 @@ func (x *GetRevisionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRevisionRequest.ProtoReflect.Descriptor instead. func (*GetRevisionRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{46} + return file_items_items_proto_rawDescGZIP(), []int{48} } func (x *GetRevisionRequest) GetSpaceId() string { @@ -2996,6 +3217,13 @@ func (x *GetRevisionRequest) GetRevisionId() string { return "" } +func (x *GetRevisionRequest) GetOptions() *GetRevisionOptions { + if x != nil { + return x.Options + } + return nil +} + type GetRevisionResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3007,7 +3235,7 @@ type GetRevisionResponse struct { func (x *GetRevisionResponse) Reset() { *x = GetRevisionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[47] + mi := &file_items_items_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3020,7 +3248,7 @@ func (x *GetRevisionResponse) String() string { func (*GetRevisionResponse) ProtoMessage() {} func (x *GetRevisionResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[47] + mi := &file_items_items_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3033,7 +3261,7 @@ func (x *GetRevisionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRevisionResponse.ProtoReflect.Descriptor instead. func (*GetRevisionResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{47} + return file_items_items_proto_rawDescGZIP(), []int{49} } func (x *GetRevisionResponse) GetItem() *Item { @@ -3058,7 +3286,7 @@ type ListRevisionsRequest struct { func (x *ListRevisionsRequest) Reset() { *x = ListRevisionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[48] + mi := &file_items_items_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3071,7 +3299,7 @@ func (x *ListRevisionsRequest) String() string { func (*ListRevisionsRequest) ProtoMessage() {} func (x *ListRevisionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[48] + mi := &file_items_items_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3084,7 +3312,7 @@ func (x *ListRevisionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRevisionsRequest.ProtoReflect.Descriptor instead. func (*ListRevisionsRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{48} + return file_items_items_proto_rawDescGZIP(), []int{50} } func (x *ListRevisionsRequest) GetSpaceId() string { @@ -3133,7 +3361,7 @@ type ListRevisionsResponse struct { func (x *ListRevisionsResponse) Reset() { *x = ListRevisionsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[49] + mi := &file_items_items_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3146,7 +3374,7 @@ func (x *ListRevisionsResponse) String() string { func (*ListRevisionsResponse) ProtoMessage() {} func (x *ListRevisionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[49] + mi := &file_items_items_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3159,7 +3387,7 @@ func (x *ListRevisionsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRevisionsResponse.ProtoReflect.Descriptor instead. func (*ListRevisionsResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{49} + return file_items_items_proto_rawDescGZIP(), []int{51} } func (x *ListRevisionsResponse) GetItems() []*Item { @@ -3182,7 +3410,7 @@ type ArchiveRequest struct { func (x *ArchiveRequest) Reset() { *x = ArchiveRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[50] + mi := &file_items_items_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3195,7 +3423,7 @@ func (x *ArchiveRequest) String() string { func (*ArchiveRequest) ProtoMessage() {} func (x *ArchiveRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[50] + mi := &file_items_items_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3208,7 +3436,7 @@ func (x *ArchiveRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ArchiveRequest.ProtoReflect.Descriptor instead. func (*ArchiveRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{50} + return file_items_items_proto_rawDescGZIP(), []int{52} } func (x *ArchiveRequest) GetItem() *Item { @@ -3229,7 +3457,7 @@ type UnarchiveRequest struct { func (x *UnarchiveRequest) Reset() { *x = UnarchiveRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[51] + mi := &file_items_items_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3242,7 +3470,7 @@ func (x *UnarchiveRequest) String() string { func (*UnarchiveRequest) ProtoMessage() {} func (x *UnarchiveRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[51] + mi := &file_items_items_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3255,7 +3483,7 @@ func (x *UnarchiveRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UnarchiveRequest.ProtoReflect.Descriptor instead. func (*UnarchiveRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{51} + return file_items_items_proto_rawDescGZIP(), []int{53} } func (x *UnarchiveRequest) GetItem() *Item { @@ -3280,7 +3508,7 @@ type FindArchivedRequest struct { func (x *FindArchivedRequest) Reset() { *x = FindArchivedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[52] + mi := &file_items_items_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3293,7 +3521,7 @@ func (x *FindArchivedRequest) String() string { func (*FindArchivedRequest) ProtoMessage() {} func (x *FindArchivedRequest) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[52] + mi := &file_items_items_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3306,7 +3534,7 @@ func (x *FindArchivedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FindArchivedRequest.ProtoReflect.Descriptor instead. func (*FindArchivedRequest) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{52} + return file_items_items_proto_rawDescGZIP(), []int{54} } func (x *FindArchivedRequest) GetSpaceId() string { @@ -3356,7 +3584,7 @@ type FindArchivedResponse struct { func (x *FindArchivedResponse) Reset() { *x = FindArchivedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_items_items_proto_msgTypes[53] + mi := &file_items_items_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3369,7 +3597,7 @@ func (x *FindArchivedResponse) String() string { func (*FindArchivedResponse) ProtoMessage() {} func (x *FindArchivedResponse) ProtoReflect() protoreflect.Message { - mi := &file_items_items_proto_msgTypes[53] + mi := &file_items_items_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3382,7 +3610,7 @@ func (x *FindArchivedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FindArchivedResponse.ProtoReflect.Descriptor instead. func (*FindArchivedResponse) Descriptor() ([]byte, []int) { - return file_items_items_proto_rawDescGZIP(), []int{53} + return file_items_items_proto_rawDescGZIP(), []int{55} } func (x *FindArchivedResponse) GetItems() []*Item { @@ -3437,7 +3665,7 @@ var file_items_items_proto_rawDesc = []byte{ 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x6f, 0x66, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0a, 0x68, 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x22, 0x9c, 0x07, 0x0a, 0x04, + 0x0a, 0x68, 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x22, 0xef, 0x07, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, @@ -3466,194 +3694,304 @@ var file_items_items_proto_rawDesc = []byte{ 0x41, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0d, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x31, 0x0a, 0x14, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, + 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x13, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, + 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x53, 0x63, 0x6f, + 0x72, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x49, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x72, - 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x65, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x12, 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x1a, 0x58, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3c, 0x0a, 0x05, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x52, 0x41, 0x46, 0x54, 0x10, 0x00, - 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, 0x12, - 0x0b, 0x0a, 0x07, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, - 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, 0x45, 0x44, 0x10, 0x03, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x7d, 0x0a, 0x0b, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x7e, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x80, 0x01, 0x0a, 0x0e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, + 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x65, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x49, 0x64, 0x73, 0x1a, 0x58, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x3c, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x52, 0x41, 0x46, + 0x54, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x0c, 0x0a, 0x08, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, 0x45, 0x44, 0x10, 0x03, 0x22, 0x7d, 0x0a, + 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x7d, 0x0a, 0x0b, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x7d, 0x0a, 0x0b, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x7e, 0x0a, 0x0c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, + 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x80, 0x01, 0x0a, 0x0e, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x19, + 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, + 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x7d, + 0x0a, 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, + 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x4a, 0x0a, + 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0c, 0x0a, 0x01, 0x71, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x01, 0x71, 0x22, 0x32, 0x0a, 0x0d, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0xee, 0x01, + 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, + 0x12, 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x22, 0x32, + 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, + 0x72, 0x73, 0x22, 0x5d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, + 0x73, 0x22, 0x48, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x74, 0x74, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x61, 0x73, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x65, 0x72, 0x61, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x0f, 0x55, + 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, + 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, + 0x73, 0x22, 0x33, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, + 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0x35, 0x0a, 0x10, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0xdd, 0x01, + 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x12, + 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x22, 0x8c, 0x01, + 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, + 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x22, 0x8d, 0x01, 0x0a, + 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, + 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x22, 0x5c, 0x0a, 0x12, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, 0x12, + 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x10, 0x41, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x43, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, + 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xa4, 0x01, 0x0a, 0x19, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, + 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x70, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3f, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x07, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, + 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3c, 0x0a, 0x11, 0x49, 0x6e, 0x74, + 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, + 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xab, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x72, + 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, + 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, + 0x54, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x54, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, + 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x0a, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x4a, 0x0a, 0x06, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0c, 0x0a, 0x01, 0x71, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x01, 0x71, 0x22, 0x32, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x0b, 0x46, - 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x12, 0x16, 0x0a, - 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, - 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x73, 0x22, 0x32, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, - 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0x32, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, - 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, 0x22, 0x48, 0x0a, 0x0d, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, - 0x65, 0x72, 0x61, 0x73, 0x65, 0x22, 0x34, 0x0a, 0x0f, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0x33, 0x0a, 0x0e, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, - 0x22, 0x35, 0x0a, 0x10, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x61, - 0x74, 0x74, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x73, 0x22, 0xb2, 0x01, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, - 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x09, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x22, 0x44, 0x0a, 0x13, - 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x45, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x10, 0x41, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x43, - 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa4, - 0x01, 0x0a, 0x19, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x06, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x70, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, + 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, + 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, + 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xc9, 0x01, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, + 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x34, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, + 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x4f, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x70, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x36, + 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x70, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x74, 0x0a, 0x0f, 0x55, 0x6e, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x12, 0x38, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x72, + 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, + 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x37, 0x0a, 0x07, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x76, 0x0a, 0x10, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, - 0x36, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3f, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x07, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, - 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3c, 0x0a, 0x11, 0x49, 0x6e, 0x74, 0x72, - 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, - 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xab, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x74, 0x72, 0x6f, - 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, - 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x54, - 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0x22, 0x7c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x39, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x2e, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xc3, 0x01, 0x0a, 0x13, 0x47, + 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, - 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, - 0x49, 0x64, 0x22, 0x36, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xc9, 0x01, 0x0a, 0x0b, 0x46, - 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, + 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, + 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x3f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x22, 0xdb, 0x01, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, @@ -3662,164 +4000,35 @@ var file_items_items_proto_rawDesc = []byte{ 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x12, 0x34, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x4f, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x70, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x70, 0x0a, 0x0d, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x74, 0x0a, 0x0f, 0x55, - 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, - 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, - 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x38, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0x72, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x37, 0x0a, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x76, 0x0a, 0x10, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, - 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xc3, 0x01, - 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, - 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, - 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0x3f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x22, 0xdb, 0x01, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, - 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, - 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x58, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, - 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xd3, 0x01, 0x0a, - 0x10, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, - 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, - 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, - 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x22, 0x44, 0x0a, 0x11, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xe5, 0x01, 0x0a, 0x19, 0x41, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, - 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x22, 0x4d, 0x0a, 0x1a, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, - 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0xa5, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, - 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, - 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x3e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, - 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, - 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xc5, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, - 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, - 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, - 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4f, + 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, - 0x42, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x58, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, - 0x65, 0x6d, 0x73, 0x22, 0x39, 0x0a, 0x0e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, - 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x3b, - 0x0a, 0x10, 0x55, 0x6e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xd9, 0x01, 0x0a, 0x13, - 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x6d, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0xd3, 0x01, 0x0a, 0x10, 0x41, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, + 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, + 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0x44, 0x0a, 0x11, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xe5, 0x01, 0x0a, 0x19, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, @@ -3828,109 +4037,171 @@ var file_items_items_proto_rawDesc = []byte{ 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, - 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x57, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x41, - 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, - 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x32, 0x93, 0x0b, 0x0a, 0x05, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x47, 0x0a, 0x06, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, - 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, - 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, - 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x04, 0x46, 0x69, 0x6e, 0x64, - 0x12, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x06, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a, - 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x07, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x4d, 0x0a, + 0x1a, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xe2, 0x01, 0x0a, + 0x12, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, + 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, + 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, + 0x6d, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x3e, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x22, 0xc5, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x69, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x42, 0x0a, 0x15, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x39, 0x0a, + 0x0e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x3b, 0x0a, 0x10, 0x55, 0x6e, 0x61, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xd9, 0x01, 0x0a, 0x13, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, + 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x57, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x32, 0x93, 0x0b, 0x0a, 0x05, 0x49, + 0x74, 0x65, 0x6d, 0x73, 0x12, 0x47, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x1c, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x53, 0x0a, + 0x0a, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x72, + 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x6e, + 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x41, 0x0a, 0x04, 0x46, 0x69, 0x6e, 0x64, 0x12, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x08, 0x55, 0x6e, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, - 0x44, 0x0a, 0x08, 0x55, 0x6e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x07, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x09, 0x55, 0x6e, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, - 0x00, 0x12, 0x59, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, - 0x64, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x0d, - 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x23, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, - 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x09, 0x41, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6b, 0x0a, 0x12, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x65, 0x64, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, + 0x42, 0x0a, 0x07, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x09, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x2e, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0c, 0x47, + 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x22, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, + 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x0d, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, + 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x09, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6b, 0x0a, 0x12, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x0b, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, - 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x5c, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x42, 0x0a, 0x07, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69, - 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, - 0x76, 0x65, 0x64, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, - 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, - 0x0a, 0x09, 0x55, 0x6e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x1f, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x72, - 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, - 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, - 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x3b, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x0d, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x07, 0x41, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x59, 0x0a, + 0x0c, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x12, 0x22, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x46, 0x69, + 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x09, 0x55, 0x6e, 0x61, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, + 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, + 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x3b, 0x69, 0x74, 0x65, + 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3946,8 +4217,8 @@ func file_items_items_proto_rawDescGZIP() []byte { } var file_items_items_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_items_items_proto_msgTypes = make([]protoimpl.MessageInfo, 57) -var file_items_items_proto_goTypes = []interface{}{ +var file_items_items_proto_msgTypes = make([]protoimpl.MessageInfo, 59) +var file_items_items_proto_goTypes = []any{ (Item_State)(0), // 0: content.items.Item.State (*Error)(nil), // 1: content.items.Error (*DecodeError)(nil), // 2: content.items.DecodeError @@ -3972,146 +4243,150 @@ var file_items_items_proto_goTypes = []interface{}{ (*FindPublishedOptions)(nil), // 21: content.items.FindPublishedOptions (*FindArchivedOptions)(nil), // 22: content.items.FindArchivedOptions (*ListRevisionsOptions)(nil), // 23: content.items.ListRevisionsOptions - (*AggregateOptions)(nil), // 24: content.items.AggregateOptions - (*AggregatePublishedOptions)(nil), // 25: content.items.AggregatePublishedOptions - (*CreateRequest)(nil), // 26: content.items.CreateRequest - (*CreateResponse)(nil), // 27: content.items.CreateResponse - (*IntrospectRequest)(nil), // 28: content.items.IntrospectRequest - (*IntrospectResponse)(nil), // 29: content.items.IntrospectResponse - (*GetRequest)(nil), // 30: content.items.GetRequest - (*GetResponse)(nil), // 31: content.items.GetResponse - (*FindRequest)(nil), // 32: content.items.FindRequest - (*FindResponse)(nil), // 33: content.items.FindResponse - (*UpdateRequest)(nil), // 34: content.items.UpdateRequest - (*DeleteRequest)(nil), // 35: content.items.DeleteRequest - (*UndeleteRequest)(nil), // 36: content.items.UndeleteRequest - (*PublishRequest)(nil), // 37: content.items.PublishRequest - (*UnpublishRequest)(nil), // 38: content.items.UnpublishRequest - (*GetPublishedRequest)(nil), // 39: content.items.GetPublishedRequest - (*GetPublishedResponse)(nil), // 40: content.items.GetPublishedResponse - (*FindPublishedRequest)(nil), // 41: content.items.FindPublishedRequest - (*FindPublishedResponse)(nil), // 42: content.items.FindPublishedResponse - (*AggregateRequest)(nil), // 43: content.items.AggregateRequest - (*AggregateResponse)(nil), // 44: content.items.AggregateResponse - (*AggregatePublishedRequest)(nil), // 45: content.items.AggregatePublishedRequest - (*AggregatePublishedResponse)(nil), // 46: content.items.AggregatePublishedResponse - (*GetRevisionRequest)(nil), // 47: content.items.GetRevisionRequest - (*GetRevisionResponse)(nil), // 48: content.items.GetRevisionResponse - (*ListRevisionsRequest)(nil), // 49: content.items.ListRevisionsRequest - (*ListRevisionsResponse)(nil), // 50: content.items.ListRevisionsResponse - (*ArchiveRequest)(nil), // 51: content.items.ArchiveRequest - (*UnarchiveRequest)(nil), // 52: content.items.UnarchiveRequest - (*FindArchivedRequest)(nil), // 53: content.items.FindArchivedRequest - (*FindArchivedResponse)(nil), // 54: content.items.FindArchivedResponse - nil, // 55: content.items.Item.TranslationsEntry - nil, // 56: content.items.AggregateOptions.FieldsEntry - nil, // 57: content.items.AggregatePublishedOptions.FieldsEntry - (*timestamppb.Timestamp)(nil), // 58: google.protobuf.Timestamp - (*structpb.Struct)(nil), // 59: google.protobuf.Struct - (*common.Filter)(nil), // 60: common.Filter - (*common.FindOptions)(nil), // 61: common.FindOptions - (*common.Error_BadRequest_FieldViolation)(nil), // 62: common.Error.BadRequest.FieldViolation - (*emptypb.Empty)(nil), // 63: google.protobuf.Empty + (*GetRevisionOptions)(nil), // 24: content.items.GetRevisionOptions + (*AggregateOptions)(nil), // 25: content.items.AggregateOptions + (*AggregatePublishedOptions)(nil), // 26: content.items.AggregatePublishedOptions + (*CreateRequest)(nil), // 27: content.items.CreateRequest + (*CreateResponse)(nil), // 28: content.items.CreateResponse + (*IntrospectRequest)(nil), // 29: content.items.IntrospectRequest + (*IntrospectResponse)(nil), // 30: content.items.IntrospectResponse + (*GetOptions)(nil), // 31: content.items.GetOptions + (*GetRequest)(nil), // 32: content.items.GetRequest + (*GetResponse)(nil), // 33: content.items.GetResponse + (*FindRequest)(nil), // 34: content.items.FindRequest + (*FindResponse)(nil), // 35: content.items.FindResponse + (*UpdateRequest)(nil), // 36: content.items.UpdateRequest + (*DeleteRequest)(nil), // 37: content.items.DeleteRequest + (*UndeleteRequest)(nil), // 38: content.items.UndeleteRequest + (*PublishRequest)(nil), // 39: content.items.PublishRequest + (*UnpublishRequest)(nil), // 40: content.items.UnpublishRequest + (*GetPublishedRequest)(nil), // 41: content.items.GetPublishedRequest + (*GetPublishedResponse)(nil), // 42: content.items.GetPublishedResponse + (*FindPublishedRequest)(nil), // 43: content.items.FindPublishedRequest + (*FindPublishedResponse)(nil), // 44: content.items.FindPublishedResponse + (*AggregateRequest)(nil), // 45: content.items.AggregateRequest + (*AggregateResponse)(nil), // 46: content.items.AggregateResponse + (*AggregatePublishedRequest)(nil), // 47: content.items.AggregatePublishedRequest + (*AggregatePublishedResponse)(nil), // 48: content.items.AggregatePublishedResponse + (*GetRevisionRequest)(nil), // 49: content.items.GetRevisionRequest + (*GetRevisionResponse)(nil), // 50: content.items.GetRevisionResponse + (*ListRevisionsRequest)(nil), // 51: content.items.ListRevisionsRequest + (*ListRevisionsResponse)(nil), // 52: content.items.ListRevisionsResponse + (*ArchiveRequest)(nil), // 53: content.items.ArchiveRequest + (*UnarchiveRequest)(nil), // 54: content.items.UnarchiveRequest + (*FindArchivedRequest)(nil), // 55: content.items.FindArchivedRequest + (*FindArchivedResponse)(nil), // 56: content.items.FindArchivedResponse + nil, // 57: content.items.Item.TranslationsEntry + nil, // 58: content.items.AggregateOptions.FieldsEntry + nil, // 59: content.items.AggregatePublishedOptions.FieldsEntry + (*timestamppb.Timestamp)(nil), // 60: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 61: google.protobuf.Struct + (*common.Filter)(nil), // 62: common.Filter + (*common.FindOptions)(nil), // 63: common.FindOptions + (*common.Error_BadRequest_FieldViolation)(nil), // 64: common.Error.BadRequest.FieldViolation + (*emptypb.Empty)(nil), // 65: google.protobuf.Empty } var file_items_items_proto_depIdxs = []int32{ 1, // 0: content.items.DecodeError.errors:type_name -> content.items.Error 1, // 1: content.items.ValidationError.errors:type_name -> content.items.Error 1, // 2: content.items.ModificationError.errors:type_name -> content.items.Error 0, // 3: content.items.Item.state:type_name -> content.items.Item.State - 58, // 4: content.items.Item.created_rev_at:type_name -> google.protobuf.Timestamp - 58, // 5: content.items.Item.created_at:type_name -> google.protobuf.Timestamp - 58, // 6: content.items.Item.updated_at:type_name -> google.protobuf.Timestamp - 59, // 7: content.items.Item.data:type_name -> google.protobuf.Struct - 55, // 8: content.items.Item.translations:type_name -> content.items.Item.TranslationsEntry - 5, // 9: content.items.Item.permissions:type_name -> content.items.Permissions - 60, // 10: content.items.Filter.data:type_name -> common.Filter - 61, // 11: content.items.FindOptions.options:type_name -> common.FindOptions - 61, // 12: content.items.FindPublishedOptions.options:type_name -> common.FindOptions - 61, // 13: content.items.FindArchivedOptions.options:type_name -> common.FindOptions - 61, // 14: content.items.ListRevisionsOptions.options:type_name -> common.FindOptions - 56, // 15: content.items.AggregateOptions.fields:type_name -> content.items.AggregateOptions.FieldsEntry - 57, // 16: content.items.AggregatePublishedOptions.fields:type_name -> content.items.AggregatePublishedOptions.FieldsEntry + 60, // 4: content.items.Item.created_rev_at:type_name -> google.protobuf.Timestamp + 60, // 5: content.items.Item.created_at:type_name -> google.protobuf.Timestamp + 60, // 6: content.items.Item.updated_at:type_name -> google.protobuf.Timestamp + 61, // 7: content.items.Item.data:type_name -> google.protobuf.Struct + 5, // 8: content.items.Item.permissions:type_name -> content.items.Permissions + 57, // 9: content.items.Item.translations:type_name -> content.items.Item.TranslationsEntry + 62, // 10: content.items.Filter.data:type_name -> common.Filter + 63, // 11: content.items.FindOptions.options:type_name -> common.FindOptions + 63, // 12: content.items.FindPublishedOptions.options:type_name -> common.FindOptions + 63, // 13: content.items.FindArchivedOptions.options:type_name -> common.FindOptions + 63, // 14: content.items.ListRevisionsOptions.options:type_name -> common.FindOptions + 58, // 15: content.items.AggregateOptions.fields:type_name -> content.items.AggregateOptions.FieldsEntry + 59, // 16: content.items.AggregatePublishedOptions.fields:type_name -> content.items.AggregatePublishedOptions.FieldsEntry 6, // 17: content.items.CreateRequest.item:type_name -> content.items.Item 13, // 18: content.items.CreateRequest.options:type_name -> content.items.CreateOptions 6, // 19: content.items.CreateResponse.created:type_name -> content.items.Item 6, // 20: content.items.IntrospectRequest.item:type_name -> content.items.Item 6, // 21: content.items.IntrospectResponse.item:type_name -> content.items.Item - 62, // 22: content.items.IntrospectResponse.validation_errors:type_name -> common.Error.BadRequest.FieldViolation - 6, // 23: content.items.GetResponse.item:type_name -> content.items.Item - 12, // 24: content.items.FindRequest.filter:type_name -> content.items.Filter - 14, // 25: content.items.FindRequest.options:type_name -> content.items.FindOptions - 6, // 26: content.items.FindResponse.items:type_name -> content.items.Item - 6, // 27: content.items.UpdateRequest.item:type_name -> content.items.Item - 15, // 28: content.items.UpdateRequest.options:type_name -> content.items.UpdateOptions - 6, // 29: content.items.DeleteRequest.item:type_name -> content.items.Item - 17, // 30: content.items.DeleteRequest.options:type_name -> content.items.DeleteOptions - 6, // 31: content.items.UndeleteRequest.item:type_name -> content.items.Item - 18, // 32: content.items.UndeleteRequest.options:type_name -> content.items.UndeleteOptions - 6, // 33: content.items.PublishRequest.item:type_name -> content.items.Item - 19, // 34: content.items.PublishRequest.options:type_name -> content.items.PublishOptions - 6, // 35: content.items.UnpublishRequest.item:type_name -> content.items.Item - 20, // 36: content.items.UnpublishRequest.options:type_name -> content.items.UnpublishOptions - 16, // 37: content.items.GetPublishedRequest.options:type_name -> content.items.GetPublishedOptions - 6, // 38: content.items.GetPublishedResponse.item:type_name -> content.items.Item - 12, // 39: content.items.FindPublishedRequest.filter:type_name -> content.items.Filter - 21, // 40: content.items.FindPublishedRequest.options:type_name -> content.items.FindPublishedOptions - 6, // 41: content.items.FindPublishedResponse.items:type_name -> content.items.Item - 12, // 42: content.items.AggregateRequest.filter:type_name -> content.items.Filter - 24, // 43: content.items.AggregateRequest.options:type_name -> content.items.AggregateOptions - 59, // 44: content.items.AggregateResponse.result:type_name -> google.protobuf.Struct - 12, // 45: content.items.AggregatePublishedRequest.filter:type_name -> content.items.Filter - 25, // 46: content.items.AggregatePublishedRequest.options:type_name -> content.items.AggregatePublishedOptions - 59, // 47: content.items.AggregatePublishedResponse.result:type_name -> google.protobuf.Struct - 6, // 48: content.items.GetRevisionResponse.item:type_name -> content.items.Item - 23, // 49: content.items.ListRevisionsRequest.options:type_name -> content.items.ListRevisionsOptions - 6, // 50: content.items.ListRevisionsResponse.items:type_name -> content.items.Item - 6, // 51: content.items.ArchiveRequest.item:type_name -> content.items.Item - 6, // 52: content.items.UnarchiveRequest.item:type_name -> content.items.Item - 12, // 53: content.items.FindArchivedRequest.filter:type_name -> content.items.Filter - 22, // 54: content.items.FindArchivedRequest.options:type_name -> content.items.FindArchivedOptions - 6, // 55: content.items.FindArchivedResponse.items:type_name -> content.items.Item - 59, // 56: content.items.Item.TranslationsEntry.value:type_name -> google.protobuf.Struct - 26, // 57: content.items.Items.Create:input_type -> content.items.CreateRequest - 28, // 58: content.items.Items.Introspect:input_type -> content.items.IntrospectRequest - 30, // 59: content.items.Items.Get:input_type -> content.items.GetRequest - 32, // 60: content.items.Items.Find:input_type -> content.items.FindRequest - 34, // 61: content.items.Items.Update:input_type -> content.items.UpdateRequest - 35, // 62: content.items.Items.Delete:input_type -> content.items.DeleteRequest - 36, // 63: content.items.Items.Undelete:input_type -> content.items.UndeleteRequest - 37, // 64: content.items.Items.Publish:input_type -> content.items.PublishRequest - 38, // 65: content.items.Items.Unpublish:input_type -> content.items.UnpublishRequest - 39, // 66: content.items.Items.GetPublished:input_type -> content.items.GetPublishedRequest - 41, // 67: content.items.Items.FindPublished:input_type -> content.items.FindPublishedRequest - 43, // 68: content.items.Items.Aggregate:input_type -> content.items.AggregateRequest - 45, // 69: content.items.Items.AggregatePublished:input_type -> content.items.AggregatePublishedRequest - 47, // 70: content.items.Items.GetRevision:input_type -> content.items.GetRevisionRequest - 49, // 71: content.items.Items.ListRevisions:input_type -> content.items.ListRevisionsRequest - 51, // 72: content.items.Items.Archive:input_type -> content.items.ArchiveRequest - 53, // 73: content.items.Items.FindArchived:input_type -> content.items.FindArchivedRequest - 52, // 74: content.items.Items.Unarchive:input_type -> content.items.UnarchiveRequest - 27, // 75: content.items.Items.Create:output_type -> content.items.CreateResponse - 29, // 76: content.items.Items.Introspect:output_type -> content.items.IntrospectResponse - 31, // 77: content.items.Items.Get:output_type -> content.items.GetResponse - 33, // 78: content.items.Items.Find:output_type -> content.items.FindResponse - 63, // 79: content.items.Items.Update:output_type -> google.protobuf.Empty - 63, // 80: content.items.Items.Delete:output_type -> google.protobuf.Empty - 63, // 81: content.items.Items.Undelete:output_type -> google.protobuf.Empty - 63, // 82: content.items.Items.Publish:output_type -> google.protobuf.Empty - 63, // 83: content.items.Items.Unpublish:output_type -> google.protobuf.Empty - 40, // 84: content.items.Items.GetPublished:output_type -> content.items.GetPublishedResponse - 42, // 85: content.items.Items.FindPublished:output_type -> content.items.FindPublishedResponse - 44, // 86: content.items.Items.Aggregate:output_type -> content.items.AggregateResponse - 46, // 87: content.items.Items.AggregatePublished:output_type -> content.items.AggregatePublishedResponse - 48, // 88: content.items.Items.GetRevision:output_type -> content.items.GetRevisionResponse - 50, // 89: content.items.Items.ListRevisions:output_type -> content.items.ListRevisionsResponse - 63, // 90: content.items.Items.Archive:output_type -> google.protobuf.Empty - 54, // 91: content.items.Items.FindArchived:output_type -> content.items.FindArchivedResponse - 63, // 92: content.items.Items.Unarchive:output_type -> google.protobuf.Empty - 75, // [75:93] is the sub-list for method output_type - 57, // [57:75] is the sub-list for method input_type - 57, // [57:57] is the sub-list for extension type_name - 57, // [57:57] is the sub-list for extension extendee - 0, // [0:57] is the sub-list for field type_name + 64, // 22: content.items.IntrospectResponse.validation_errors:type_name -> common.Error.BadRequest.FieldViolation + 31, // 23: content.items.GetRequest.options:type_name -> content.items.GetOptions + 6, // 24: content.items.GetResponse.item:type_name -> content.items.Item + 12, // 25: content.items.FindRequest.filter:type_name -> content.items.Filter + 14, // 26: content.items.FindRequest.options:type_name -> content.items.FindOptions + 6, // 27: content.items.FindResponse.items:type_name -> content.items.Item + 6, // 28: content.items.UpdateRequest.item:type_name -> content.items.Item + 15, // 29: content.items.UpdateRequest.options:type_name -> content.items.UpdateOptions + 6, // 30: content.items.DeleteRequest.item:type_name -> content.items.Item + 17, // 31: content.items.DeleteRequest.options:type_name -> content.items.DeleteOptions + 6, // 32: content.items.UndeleteRequest.item:type_name -> content.items.Item + 18, // 33: content.items.UndeleteRequest.options:type_name -> content.items.UndeleteOptions + 6, // 34: content.items.PublishRequest.item:type_name -> content.items.Item + 19, // 35: content.items.PublishRequest.options:type_name -> content.items.PublishOptions + 6, // 36: content.items.UnpublishRequest.item:type_name -> content.items.Item + 20, // 37: content.items.UnpublishRequest.options:type_name -> content.items.UnpublishOptions + 16, // 38: content.items.GetPublishedRequest.options:type_name -> content.items.GetPublishedOptions + 6, // 39: content.items.GetPublishedResponse.item:type_name -> content.items.Item + 12, // 40: content.items.FindPublishedRequest.filter:type_name -> content.items.Filter + 21, // 41: content.items.FindPublishedRequest.options:type_name -> content.items.FindPublishedOptions + 6, // 42: content.items.FindPublishedResponse.items:type_name -> content.items.Item + 12, // 43: content.items.AggregateRequest.filter:type_name -> content.items.Filter + 25, // 44: content.items.AggregateRequest.options:type_name -> content.items.AggregateOptions + 61, // 45: content.items.AggregateResponse.result:type_name -> google.protobuf.Struct + 12, // 46: content.items.AggregatePublishedRequest.filter:type_name -> content.items.Filter + 26, // 47: content.items.AggregatePublishedRequest.options:type_name -> content.items.AggregatePublishedOptions + 61, // 48: content.items.AggregatePublishedResponse.result:type_name -> google.protobuf.Struct + 24, // 49: content.items.GetRevisionRequest.options:type_name -> content.items.GetRevisionOptions + 6, // 50: content.items.GetRevisionResponse.item:type_name -> content.items.Item + 23, // 51: content.items.ListRevisionsRequest.options:type_name -> content.items.ListRevisionsOptions + 6, // 52: content.items.ListRevisionsResponse.items:type_name -> content.items.Item + 6, // 53: content.items.ArchiveRequest.item:type_name -> content.items.Item + 6, // 54: content.items.UnarchiveRequest.item:type_name -> content.items.Item + 12, // 55: content.items.FindArchivedRequest.filter:type_name -> content.items.Filter + 22, // 56: content.items.FindArchivedRequest.options:type_name -> content.items.FindArchivedOptions + 6, // 57: content.items.FindArchivedResponse.items:type_name -> content.items.Item + 61, // 58: content.items.Item.TranslationsEntry.value:type_name -> google.protobuf.Struct + 27, // 59: content.items.Items.Create:input_type -> content.items.CreateRequest + 29, // 60: content.items.Items.Introspect:input_type -> content.items.IntrospectRequest + 32, // 61: content.items.Items.Get:input_type -> content.items.GetRequest + 34, // 62: content.items.Items.Find:input_type -> content.items.FindRequest + 36, // 63: content.items.Items.Update:input_type -> content.items.UpdateRequest + 37, // 64: content.items.Items.Delete:input_type -> content.items.DeleteRequest + 38, // 65: content.items.Items.Undelete:input_type -> content.items.UndeleteRequest + 39, // 66: content.items.Items.Publish:input_type -> content.items.PublishRequest + 40, // 67: content.items.Items.Unpublish:input_type -> content.items.UnpublishRequest + 41, // 68: content.items.Items.GetPublished:input_type -> content.items.GetPublishedRequest + 43, // 69: content.items.Items.FindPublished:input_type -> content.items.FindPublishedRequest + 45, // 70: content.items.Items.Aggregate:input_type -> content.items.AggregateRequest + 47, // 71: content.items.Items.AggregatePublished:input_type -> content.items.AggregatePublishedRequest + 49, // 72: content.items.Items.GetRevision:input_type -> content.items.GetRevisionRequest + 51, // 73: content.items.Items.ListRevisions:input_type -> content.items.ListRevisionsRequest + 53, // 74: content.items.Items.Archive:input_type -> content.items.ArchiveRequest + 55, // 75: content.items.Items.FindArchived:input_type -> content.items.FindArchivedRequest + 54, // 76: content.items.Items.Unarchive:input_type -> content.items.UnarchiveRequest + 28, // 77: content.items.Items.Create:output_type -> content.items.CreateResponse + 30, // 78: content.items.Items.Introspect:output_type -> content.items.IntrospectResponse + 33, // 79: content.items.Items.Get:output_type -> content.items.GetResponse + 35, // 80: content.items.Items.Find:output_type -> content.items.FindResponse + 65, // 81: content.items.Items.Update:output_type -> google.protobuf.Empty + 65, // 82: content.items.Items.Delete:output_type -> google.protobuf.Empty + 65, // 83: content.items.Items.Undelete:output_type -> google.protobuf.Empty + 65, // 84: content.items.Items.Publish:output_type -> google.protobuf.Empty + 65, // 85: content.items.Items.Unpublish:output_type -> google.protobuf.Empty + 42, // 86: content.items.Items.GetPublished:output_type -> content.items.GetPublishedResponse + 44, // 87: content.items.Items.FindPublished:output_type -> content.items.FindPublishedResponse + 46, // 88: content.items.Items.Aggregate:output_type -> content.items.AggregateResponse + 48, // 89: content.items.Items.AggregatePublished:output_type -> content.items.AggregatePublishedResponse + 50, // 90: content.items.Items.GetRevision:output_type -> content.items.GetRevisionResponse + 52, // 91: content.items.Items.ListRevisions:output_type -> content.items.ListRevisionsResponse + 65, // 92: content.items.Items.Archive:output_type -> google.protobuf.Empty + 56, // 93: content.items.Items.FindArchived:output_type -> content.items.FindArchivedResponse + 65, // 94: content.items.Items.Unarchive:output_type -> google.protobuf.Empty + 77, // [77:95] is the sub-list for method output_type + 59, // [59:77] is the sub-list for method input_type + 59, // [59:59] is the sub-list for extension type_name + 59, // [59:59] is the sub-list for extension extendee + 0, // [0:59] is the sub-list for field type_name } func init() { file_items_items_proto_init() } @@ -4120,7 +4395,7 @@ func file_items_items_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_items_items_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Error); i { case 0: return &v.state @@ -4132,7 +4407,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*DecodeError); i { case 0: return &v.state @@ -4144,7 +4419,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*ValidationError); i { case 0: return &v.state @@ -4156,7 +4431,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ModificationError); i { case 0: return &v.state @@ -4168,7 +4443,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*Permissions); i { case 0: return &v.state @@ -4180,7 +4455,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*Item); i { case 0: return &v.state @@ -4192,7 +4467,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*EventCreate); i { case 0: return &v.state @@ -4204,7 +4479,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*EventUpdate); i { case 0: return &v.state @@ -4216,7 +4491,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*EventPublish); i { case 0: return &v.state @@ -4228,7 +4503,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*EventUnpublish); i { case 0: return &v.state @@ -4240,7 +4515,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*EventDelete); i { case 0: return &v.state @@ -4252,7 +4527,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*Filter); i { case 0: return &v.state @@ -4264,7 +4539,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*CreateOptions); i { case 0: return &v.state @@ -4276,7 +4551,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*FindOptions); i { case 0: return &v.state @@ -4288,7 +4563,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*UpdateOptions); i { case 0: return &v.state @@ -4300,7 +4575,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*GetPublishedOptions); i { case 0: return &v.state @@ -4312,7 +4587,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*DeleteOptions); i { case 0: return &v.state @@ -4324,7 +4599,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*UndeleteOptions); i { case 0: return &v.state @@ -4336,7 +4611,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[18].Exporter = func(v any, i int) any { switch v := v.(*PublishOptions); i { case 0: return &v.state @@ -4348,7 +4623,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[19].Exporter = func(v any, i int) any { switch v := v.(*UnpublishOptions); i { case 0: return &v.state @@ -4360,7 +4635,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[20].Exporter = func(v any, i int) any { switch v := v.(*FindPublishedOptions); i { case 0: return &v.state @@ -4372,7 +4647,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[21].Exporter = func(v any, i int) any { switch v := v.(*FindArchivedOptions); i { case 0: return &v.state @@ -4384,7 +4659,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[22].Exporter = func(v any, i int) any { switch v := v.(*ListRevisionsOptions); i { case 0: return &v.state @@ -4396,7 +4671,19 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[23].Exporter = func(v any, i int) any { + switch v := v.(*GetRevisionOptions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_items_items_proto_msgTypes[24].Exporter = func(v any, i int) any { switch v := v.(*AggregateOptions); i { case 0: return &v.state @@ -4408,7 +4695,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[25].Exporter = func(v any, i int) any { switch v := v.(*AggregatePublishedOptions); i { case 0: return &v.state @@ -4420,7 +4707,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[26].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -4432,7 +4719,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[27].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -4444,7 +4731,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[28].Exporter = func(v any, i int) any { switch v := v.(*IntrospectRequest); i { case 0: return &v.state @@ -4456,7 +4743,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[29].Exporter = func(v any, i int) any { switch v := v.(*IntrospectResponse); i { case 0: return &v.state @@ -4468,7 +4755,19 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[30].Exporter = func(v any, i int) any { + switch v := v.(*GetOptions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_items_items_proto_msgTypes[31].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -4480,7 +4779,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[32].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -4492,7 +4791,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[33].Exporter = func(v any, i int) any { switch v := v.(*FindRequest); i { case 0: return &v.state @@ -4504,7 +4803,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[34].Exporter = func(v any, i int) any { switch v := v.(*FindResponse); i { case 0: return &v.state @@ -4516,7 +4815,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[35].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -4528,7 +4827,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[36].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -4540,7 +4839,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[37].Exporter = func(v any, i int) any { switch v := v.(*UndeleteRequest); i { case 0: return &v.state @@ -4552,7 +4851,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[38].Exporter = func(v any, i int) any { switch v := v.(*PublishRequest); i { case 0: return &v.state @@ -4564,7 +4863,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[39].Exporter = func(v any, i int) any { switch v := v.(*UnpublishRequest); i { case 0: return &v.state @@ -4576,7 +4875,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[40].Exporter = func(v any, i int) any { switch v := v.(*GetPublishedRequest); i { case 0: return &v.state @@ -4588,7 +4887,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[41].Exporter = func(v any, i int) any { switch v := v.(*GetPublishedResponse); i { case 0: return &v.state @@ -4600,7 +4899,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[42].Exporter = func(v any, i int) any { switch v := v.(*FindPublishedRequest); i { case 0: return &v.state @@ -4612,7 +4911,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[43].Exporter = func(v any, i int) any { switch v := v.(*FindPublishedResponse); i { case 0: return &v.state @@ -4624,7 +4923,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[44].Exporter = func(v any, i int) any { switch v := v.(*AggregateRequest); i { case 0: return &v.state @@ -4636,7 +4935,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[45].Exporter = func(v any, i int) any { switch v := v.(*AggregateResponse); i { case 0: return &v.state @@ -4648,7 +4947,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[46].Exporter = func(v any, i int) any { switch v := v.(*AggregatePublishedRequest); i { case 0: return &v.state @@ -4660,7 +4959,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[47].Exporter = func(v any, i int) any { switch v := v.(*AggregatePublishedResponse); i { case 0: return &v.state @@ -4672,7 +4971,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[48].Exporter = func(v any, i int) any { switch v := v.(*GetRevisionRequest); i { case 0: return &v.state @@ -4684,7 +4983,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[49].Exporter = func(v any, i int) any { switch v := v.(*GetRevisionResponse); i { case 0: return &v.state @@ -4696,7 +4995,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[50].Exporter = func(v any, i int) any { switch v := v.(*ListRevisionsRequest); i { case 0: return &v.state @@ -4708,7 +5007,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[51].Exporter = func(v any, i int) any { switch v := v.(*ListRevisionsResponse); i { case 0: return &v.state @@ -4720,7 +5019,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[52].Exporter = func(v any, i int) any { switch v := v.(*ArchiveRequest); i { case 0: return &v.state @@ -4732,7 +5031,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[53].Exporter = func(v any, i int) any { switch v := v.(*UnarchiveRequest); i { case 0: return &v.state @@ -4744,7 +5043,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[54].Exporter = func(v any, i int) any { switch v := v.(*FindArchivedRequest); i { case 0: return &v.state @@ -4756,7 +5055,7 @@ func file_items_items_proto_init() { return nil } } - file_items_items_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + file_items_items_proto_msgTypes[55].Exporter = func(v any, i int) any { switch v := v.(*FindArchivedResponse); i { case 0: return &v.state @@ -4775,7 +5074,7 @@ func file_items_items_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_items_items_proto_rawDesc, NumEnums: 1, - NumMessages: 57, + NumMessages: 59, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/items/items_grpc.pb.go b/proto/items/items_grpc.pb.go index b246b7627a8bbbdaaba51165e9f7b7e936691a11..16b486427fef5d6d4ee0dfd75c80da606413273d 100644 --- a/proto/items/items_grpc.pb.go +++ b/proto/items/items_grpc.pb.go @@ -8,8 +8,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: items/items.proto package items @@ -24,8 +24,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Items_Create_FullMethodName = "/content.items.Items/Create" @@ -51,6 +51,9 @@ const ( // ItemsClient is the client API for Items service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// * +// Сервис API элементов type ItemsClient interface { // * // Создать запись @@ -93,8 +96,9 @@ func NewItemsClient(cc grpc.ClientConnInterface) ItemsClient { } func (c *itemsClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Items_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -102,8 +106,9 @@ func (c *itemsClient) Create(ctx context.Context, in *CreateRequest, opts ...grp } func (c *itemsClient) Introspect(ctx context.Context, in *IntrospectRequest, opts ...grpc.CallOption) (*IntrospectResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(IntrospectResponse) - err := c.cc.Invoke(ctx, Items_Introspect_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Introspect_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -111,8 +116,9 @@ func (c *itemsClient) Introspect(ctx context.Context, in *IntrospectRequest, opt } func (c *itemsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Items_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -120,8 +126,9 @@ func (c *itemsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Call } func (c *itemsClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindResponse) - err := c.cc.Invoke(ctx, Items_Find_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Find_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -129,8 +136,9 @@ func (c *itemsClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.Ca } func (c *itemsClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -138,8 +146,9 @@ func (c *itemsClient) Update(ctx context.Context, in *UpdateRequest, opts ...grp } func (c *itemsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -147,8 +156,9 @@ func (c *itemsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grp } func (c *itemsClient) Undelete(ctx context.Context, in *UndeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Undelete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Undelete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -156,8 +166,9 @@ func (c *itemsClient) Undelete(ctx context.Context, in *UndeleteRequest, opts .. } func (c *itemsClient) Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Publish_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Publish_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -165,8 +176,9 @@ func (c *itemsClient) Publish(ctx context.Context, in *PublishRequest, opts ...g } func (c *itemsClient) Unpublish(ctx context.Context, in *UnpublishRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Unpublish_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Unpublish_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -174,8 +186,9 @@ func (c *itemsClient) Unpublish(ctx context.Context, in *UnpublishRequest, opts } func (c *itemsClient) GetPublished(ctx context.Context, in *GetPublishedRequest, opts ...grpc.CallOption) (*GetPublishedResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetPublishedResponse) - err := c.cc.Invoke(ctx, Items_GetPublished_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_GetPublished_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -183,8 +196,9 @@ func (c *itemsClient) GetPublished(ctx context.Context, in *GetPublishedRequest, } func (c *itemsClient) FindPublished(ctx context.Context, in *FindPublishedRequest, opts ...grpc.CallOption) (*FindPublishedResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindPublishedResponse) - err := c.cc.Invoke(ctx, Items_FindPublished_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_FindPublished_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -192,8 +206,9 @@ func (c *itemsClient) FindPublished(ctx context.Context, in *FindPublishedReques } func (c *itemsClient) Aggregate(ctx context.Context, in *AggregateRequest, opts ...grpc.CallOption) (*AggregateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AggregateResponse) - err := c.cc.Invoke(ctx, Items_Aggregate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Aggregate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -201,8 +216,9 @@ func (c *itemsClient) Aggregate(ctx context.Context, in *AggregateRequest, opts } func (c *itemsClient) AggregatePublished(ctx context.Context, in *AggregatePublishedRequest, opts ...grpc.CallOption) (*AggregatePublishedResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(AggregatePublishedResponse) - err := c.cc.Invoke(ctx, Items_AggregatePublished_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_AggregatePublished_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -210,8 +226,9 @@ func (c *itemsClient) AggregatePublished(ctx context.Context, in *AggregatePubli } func (c *itemsClient) GetRevision(ctx context.Context, in *GetRevisionRequest, opts ...grpc.CallOption) (*GetRevisionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetRevisionResponse) - err := c.cc.Invoke(ctx, Items_GetRevision_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_GetRevision_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -219,8 +236,9 @@ func (c *itemsClient) GetRevision(ctx context.Context, in *GetRevisionRequest, o } func (c *itemsClient) ListRevisions(ctx context.Context, in *ListRevisionsRequest, opts ...grpc.CallOption) (*ListRevisionsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListRevisionsResponse) - err := c.cc.Invoke(ctx, Items_ListRevisions_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_ListRevisions_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -228,8 +246,9 @@ func (c *itemsClient) ListRevisions(ctx context.Context, in *ListRevisionsReques } func (c *itemsClient) Archive(ctx context.Context, in *ArchiveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Archive_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Archive_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -237,8 +256,9 @@ func (c *itemsClient) Archive(ctx context.Context, in *ArchiveRequest, opts ...g } func (c *itemsClient) FindArchived(ctx context.Context, in *FindArchivedRequest, opts ...grpc.CallOption) (*FindArchivedResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindArchivedResponse) - err := c.cc.Invoke(ctx, Items_FindArchived_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_FindArchived_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -246,8 +266,9 @@ func (c *itemsClient) FindArchived(ctx context.Context, in *FindArchivedRequest, } func (c *itemsClient) Unarchive(ctx context.Context, in *UnarchiveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Items_Unarchive_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Items_Unarchive_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -256,7 +277,10 @@ func (c *itemsClient) Unarchive(ctx context.Context, in *UnarchiveRequest, opts // ItemsServer is the server API for Items service. // All implementations must embed UnimplementedItemsServer -// for forward compatibility +// for forward compatibility. +// +// * +// Сервис API элементов type ItemsServer interface { // * // Создать запись @@ -291,9 +315,12 @@ type ItemsServer interface { mustEmbedUnimplementedItemsServer() } -// UnimplementedItemsServer must be embedded to have forward compatible implementations. -type UnimplementedItemsServer struct { -} +// UnimplementedItemsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedItemsServer struct{} func (UnimplementedItemsServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -350,6 +377,7 @@ func (UnimplementedItemsServer) Unarchive(context.Context, *UnarchiveRequest) (* return nil, status.Errorf(codes.Unimplemented, "method Unarchive not implemented") } func (UnimplementedItemsServer) mustEmbedUnimplementedItemsServer() {} +func (UnimplementedItemsServer) testEmbeddedByValue() {} // UnsafeItemsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ItemsServer will @@ -359,6 +387,13 @@ type UnsafeItemsServer interface { } func RegisterItemsServer(s grpc.ServiceRegistrar, srv ItemsServer) { + // If the following call pancis, it indicates UnimplementedItemsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Items_ServiceDesc, srv) } diff --git a/proto/locales/locales.pb.go b/proto/locales/locales.pb.go index 6ed197b9a1d42660f0211daaaba01f7334ff93df..a1a301ae6e8acc273ac186745f14df700e2478c4 100644 --- a/proto/locales/locales.pb.go +++ b/proto/locales/locales.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: locales/locales.proto package locales @@ -26,9 +26,16 @@ type Locale struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - SpaceId string `protobuf:"bytes,2,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // Идентификатор локали, генерируется автоматически. Для локали по умолчанию устанавливается как "default". + SpaceId string `protobuf:"bytes,2,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` // Идентификатор пространства. + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` // Название локали. Опционально, заполняется автоматически (Пример: russian, english) + NativeName string `protobuf:"bytes,4,opt,name=native_name,json=nativeName,proto3" json:"native_name,omitempty"` // Название локали на языке локали. Опционально, заполняется автоматически (Пример: Русский, English) + Code string `protobuf:"bytes,5,opt,name=code,proto3" json:"code,omitempty"` // Код локали https://en.wikipedia.org/wiki/IETF_language_tag + Fallback string `protobuf:"bytes,6,opt,name=fallback,proto3" json:"fallback,omitempty"` // Идентификатор локали, который будет использоваться при отсутствии перевода + Direction string `protobuf:"bytes,7,opt,name=direction,proto3" json:"direction,omitempty"` // Направление письма - слева направо (ltr) или справа налево (rtl). По умолчанию устанавливается ltr. + Weight int64 `protobuf:"varint,8,opt,name=weight,proto3" json:"weight,omitempty"` // Вес локали. + NoPublish bool `protobuf:"varint,100,opt,name=no_publish,json=noPublish,proto3" json:"no_publish,omitempty"` // Не публиковать контент данной локали. Не будет доступен контент через Delivery API. (кроме default) + Disabled bool `protobuf:"varint,101,opt,name=disabled,proto3" json:"disabled,omitempty"` // Запретить использование локали. Нельзя создавать и редактировать контент для данной локали (кроме default) } func (x *Locale) Reset() { @@ -84,6 +91,55 @@ func (x *Locale) GetName() string { return "" } +func (x *Locale) GetNativeName() string { + if x != nil { + return x.NativeName + } + return "" +} + +func (x *Locale) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *Locale) GetFallback() string { + if x != nil { + return x.Fallback + } + return "" +} + +func (x *Locale) GetDirection() string { + if x != nil { + return x.Direction + } + return "" +} + +func (x *Locale) GetWeight() int64 { + if x != nil { + return x.Weight + } + return 0 +} + +func (x *Locale) GetNoPublish() bool { + if x != nil { + return x.NoPublish + } + return false +} + +func (x *Locale) GetDisabled() bool { + if x != nil { + return x.Disabled + } + return false +} + type CreateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -178,6 +234,53 @@ func (x *CreateResponse) GetLocale() *Locale { return nil } +type UpdateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Locale *Locale `protobuf:"bytes,1,opt,name=locale,proto3" json:"locale,omitempty"` +} + +func (x *UpdateRequest) Reset() { + *x = UpdateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_locales_locales_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRequest) ProtoMessage() {} + +func (x *UpdateRequest) ProtoReflect() protoreflect.Message { + mi := &file_locales_locales_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateRequest.ProtoReflect.Descriptor instead. +func (*UpdateRequest) Descriptor() ([]byte, []int) { + return file_locales_locales_proto_rawDescGZIP(), []int{3} +} + +func (x *UpdateRequest) GetLocale() *Locale { + if x != nil { + return x.Locale + } + return nil +} + type ListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -189,7 +292,7 @@ type ListRequest struct { func (x *ListRequest) Reset() { *x = ListRequest{} if protoimpl.UnsafeEnabled { - mi := &file_locales_locales_proto_msgTypes[3] + mi := &file_locales_locales_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -202,7 +305,7 @@ func (x *ListRequest) String() string { func (*ListRequest) ProtoMessage() {} func (x *ListRequest) ProtoReflect() protoreflect.Message { - mi := &file_locales_locales_proto_msgTypes[3] + mi := &file_locales_locales_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -215,7 +318,7 @@ func (x *ListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. func (*ListRequest) Descriptor() ([]byte, []int) { - return file_locales_locales_proto_rawDescGZIP(), []int{3} + return file_locales_locales_proto_rawDescGZIP(), []int{4} } func (x *ListRequest) GetSpaceId() string { @@ -236,7 +339,7 @@ type ListResponse struct { func (x *ListResponse) Reset() { *x = ListResponse{} if protoimpl.UnsafeEnabled { - mi := &file_locales_locales_proto_msgTypes[4] + mi := &file_locales_locales_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -249,7 +352,7 @@ func (x *ListResponse) String() string { func (*ListResponse) ProtoMessage() {} func (x *ListResponse) ProtoReflect() protoreflect.Message { - mi := &file_locales_locales_proto_msgTypes[4] + mi := &file_locales_locales_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -262,7 +365,7 @@ func (x *ListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListResponse.ProtoReflect.Descriptor instead. func (*ListResponse) Descriptor() ([]byte, []int) { - return file_locales_locales_proto_rawDescGZIP(), []int{4} + return file_locales_locales_proto_rawDescGZIP(), []int{5} } func (x *ListResponse) GetLocales() []*Locale { @@ -277,14 +380,14 @@ type DeleteRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` - LocaleId string `protobuf:"bytes,2,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + SpaceId string `protobuf:"bytes,2,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` } func (x *DeleteRequest) Reset() { *x = DeleteRequest{} if protoimpl.UnsafeEnabled { - mi := &file_locales_locales_proto_msgTypes[5] + mi := &file_locales_locales_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -297,7 +400,7 @@ func (x *DeleteRequest) String() string { func (*DeleteRequest) ProtoMessage() {} func (x *DeleteRequest) ProtoReflect() protoreflect.Message { - mi := &file_locales_locales_proto_msgTypes[5] + mi := &file_locales_locales_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -310,19 +413,19 @@ func (x *DeleteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. func (*DeleteRequest) Descriptor() ([]byte, []int) { - return file_locales_locales_proto_rawDescGZIP(), []int{5} + return file_locales_locales_proto_rawDescGZIP(), []int{6} } -func (x *DeleteRequest) GetSpaceId() string { +func (x *DeleteRequest) GetId() string { if x != nil { - return x.SpaceId + return x.Id } return "" } -func (x *DeleteRequest) GetLocaleId() string { +func (x *DeleteRequest) GetSpaceId() string { if x != nil { - return x.LocaleId + return x.SpaceId } return "" } @@ -334,49 +437,69 @@ var file_locales_locales_proto_rawDesc = []byte{ 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x47, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x40, - 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x2f, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, - 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, - 0x22, 0x41, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x89, 0x02, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x5f, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x18, 0x64, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6e, 0x6f, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x18, 0x65, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x22, 0x40, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, 0x06, 0x6c, 0x6f, 0x63, - 0x61, 0x6c, 0x65, 0x22, 0x28, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x41, 0x0a, - 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, - 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, - 0x22, 0x47, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, 0x64, 0x32, 0xe1, 0x01, 0x0a, 0x07, 0x4c, 0x6f, - 0x63, 0x61, 0x6c, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, + 0x61, 0x6c, 0x65, 0x22, 0x41, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, 0x06, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x40, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x28, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x49, 0x64, 0x22, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, 0x07, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x73, 0x22, 0x3a, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, + 0x64, 0x32, 0xa5, 0x02, 0x0a, 0x07, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x12, 0x4b, 0x0a, + 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x06, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x45, + 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, - 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, - 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x45, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x06, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x6c, 0x6f, - 0x63, 0x61, 0x6c, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, - 0x32, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, - 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x3b, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, + 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, + 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x3b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -391,31 +514,35 @@ func file_locales_locales_proto_rawDescGZIP() []byte { return file_locales_locales_proto_rawDescData } -var file_locales_locales_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_locales_locales_proto_goTypes = []interface{}{ +var file_locales_locales_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_locales_locales_proto_goTypes = []any{ (*Locale)(nil), // 0: content.locales.Locale (*CreateRequest)(nil), // 1: content.locales.CreateRequest (*CreateResponse)(nil), // 2: content.locales.CreateResponse - (*ListRequest)(nil), // 3: content.locales.ListRequest - (*ListResponse)(nil), // 4: content.locales.ListResponse - (*DeleteRequest)(nil), // 5: content.locales.DeleteRequest - (*emptypb.Empty)(nil), // 6: google.protobuf.Empty + (*UpdateRequest)(nil), // 3: content.locales.UpdateRequest + (*ListRequest)(nil), // 4: content.locales.ListRequest + (*ListResponse)(nil), // 5: content.locales.ListResponse + (*DeleteRequest)(nil), // 6: content.locales.DeleteRequest + (*emptypb.Empty)(nil), // 7: google.protobuf.Empty } var file_locales_locales_proto_depIdxs = []int32{ 0, // 0: content.locales.CreateRequest.locale:type_name -> content.locales.Locale 0, // 1: content.locales.CreateResponse.locale:type_name -> content.locales.Locale - 0, // 2: content.locales.ListResponse.locales:type_name -> content.locales.Locale - 1, // 3: content.locales.Locales.Create:input_type -> content.locales.CreateRequest - 3, // 4: content.locales.Locales.List:input_type -> content.locales.ListRequest - 5, // 5: content.locales.Locales.Delete:input_type -> content.locales.DeleteRequest - 2, // 6: content.locales.Locales.Create:output_type -> content.locales.CreateResponse - 4, // 7: content.locales.Locales.List:output_type -> content.locales.ListResponse - 6, // 8: content.locales.Locales.Delete:output_type -> google.protobuf.Empty - 6, // [6:9] is the sub-list for method output_type - 3, // [3:6] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 0, // 2: content.locales.UpdateRequest.locale:type_name -> content.locales.Locale + 0, // 3: content.locales.ListResponse.locales:type_name -> content.locales.Locale + 1, // 4: content.locales.Locales.Create:input_type -> content.locales.CreateRequest + 3, // 5: content.locales.Locales.Update:input_type -> content.locales.UpdateRequest + 4, // 6: content.locales.Locales.List:input_type -> content.locales.ListRequest + 6, // 7: content.locales.Locales.Delete:input_type -> content.locales.DeleteRequest + 2, // 8: content.locales.Locales.Create:output_type -> content.locales.CreateResponse + 7, // 9: content.locales.Locales.Update:output_type -> google.protobuf.Empty + 5, // 10: content.locales.Locales.List:output_type -> content.locales.ListResponse + 7, // 11: content.locales.Locales.Delete:output_type -> google.protobuf.Empty + 8, // [8:12] is the sub-list for method output_type + 4, // [4:8] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_locales_locales_proto_init() } @@ -424,7 +551,7 @@ func file_locales_locales_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_locales_locales_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_locales_locales_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Locale); i { case 0: return &v.state @@ -436,7 +563,7 @@ func file_locales_locales_proto_init() { return nil } } - file_locales_locales_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_locales_locales_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -448,7 +575,7 @@ func file_locales_locales_proto_init() { return nil } } - file_locales_locales_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_locales_locales_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -460,7 +587,19 @@ func file_locales_locales_proto_init() { return nil } } - file_locales_locales_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_locales_locales_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*UpdateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_locales_locales_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*ListRequest); i { case 0: return &v.state @@ -472,7 +611,7 @@ func file_locales_locales_proto_init() { return nil } } - file_locales_locales_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_locales_locales_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ListResponse); i { case 0: return &v.state @@ -484,7 +623,7 @@ func file_locales_locales_proto_init() { return nil } } - file_locales_locales_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_locales_locales_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -503,7 +642,7 @@ func file_locales_locales_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_locales_locales_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/locales/locales_grpc.pb.go b/proto/locales/locales_grpc.pb.go index d8f5e712b8b06e5646d56020c1e0cb06ae24545f..1e6d289f8fa50a8c1ec8a2013ac7cf5b8183d7f0 100644 --- a/proto/locales/locales_grpc.pb.go +++ b/proto/locales/locales_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: locales/locales.proto package locales @@ -16,11 +16,12 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Locales_Create_FullMethodName = "/content.locales.Locales/Create" + Locales_Update_FullMethodName = "/content.locales.Locales/Update" Locales_List_FullMethodName = "/content.locales.Locales/List" Locales_Delete_FullMethodName = "/content.locales.Locales/Delete" ) @@ -29,8 +30,13 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type LocalesClient interface { + // Создать локаль Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) + // Обновить локаль + Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // Получить список локалей List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) + // Удалить локаль Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) } @@ -43,8 +49,19 @@ func NewLocalesClient(cc grpc.ClientConnInterface) LocalesClient { } func (c *localesClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Locales_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Locales_Create_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *localesClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, Locales_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -52,8 +69,9 @@ func (c *localesClient) Create(ctx context.Context, in *CreateRequest, opts ...g } func (c *localesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListResponse) - err := c.cc.Invoke(ctx, Locales_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Locales_List_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -61,8 +79,9 @@ func (c *localesClient) List(ctx context.Context, in *ListRequest, opts ...grpc. } func (c *localesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Locales_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Locales_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -71,21 +90,32 @@ func (c *localesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...g // LocalesServer is the server API for Locales service. // All implementations must embed UnimplementedLocalesServer -// for forward compatibility +// for forward compatibility. type LocalesServer interface { + // Создать локаль Create(context.Context, *CreateRequest) (*CreateResponse, error) + // Обновить локаль + Update(context.Context, *UpdateRequest) (*emptypb.Empty, error) + // Получить список локалей List(context.Context, *ListRequest) (*ListResponse, error) + // Удалить локаль Delete(context.Context, *DeleteRequest) (*emptypb.Empty, error) mustEmbedUnimplementedLocalesServer() } -// UnimplementedLocalesServer must be embedded to have forward compatible implementations. -type UnimplementedLocalesServer struct { -} +// UnimplementedLocalesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedLocalesServer struct{} func (UnimplementedLocalesServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") } +func (UnimplementedLocalesServer) Update(context.Context, *UpdateRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} func (UnimplementedLocalesServer) List(context.Context, *ListRequest) (*ListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method List not implemented") } @@ -93,6 +123,7 @@ func (UnimplementedLocalesServer) Delete(context.Context, *DeleteRequest) (*empt return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func (UnimplementedLocalesServer) mustEmbedUnimplementedLocalesServer() {} +func (UnimplementedLocalesServer) testEmbeddedByValue() {} // UnsafeLocalesServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to LocalesServer will @@ -102,6 +133,13 @@ type UnsafeLocalesServer interface { } func RegisterLocalesServer(s grpc.ServiceRegistrar, srv LocalesServer) { + // If the following call pancis, it indicates UnimplementedLocalesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Locales_ServiceDesc, srv) } @@ -123,6 +161,24 @@ func _Locales_Create_Handler(srv interface{}, ctx context.Context, dec func(inte return interceptor(ctx, in, info, handler) } +func _Locales_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LocalesServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Locales_Update_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LocalesServer).Update(ctx, req.(*UpdateRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Locales_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListRequest) if err := dec(in); err != nil { @@ -170,6 +226,10 @@ var Locales_ServiceDesc = grpc.ServiceDesc{ MethodName: "Create", Handler: _Locales_Create_Handler, }, + { + MethodName: "Update", + Handler: _Locales_Update_Handler, + }, { MethodName: "List", Handler: _Locales_List_Handler, diff --git a/proto/logs/log.pb.go b/proto/logs/log.pb.go index 8beabf96d64b409bc99ebf0b6e6ecb64b1ae4aa6..deb2d4fc477c54e2bb1c091b29feb4b209e5b670 100644 --- a/proto/logs/log.pb.go +++ b/proto/logs/log.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: logs/log.proto package logs @@ -146,6 +146,8 @@ type LogEntry struct { Attr *anypb.Any `protobuf:"bytes,10,opt,name=attr,proto3" json:"attr,omitempty"` // tags содержит теги связанные с событием, на усмотрение сервиса Tags []string `protobuf:"bytes,11,rep,name=tags,proto3" json:"tags,omitempty"` + // релевантность элемента при полнотекстовом поиске + SearchScore float64 `protobuf:"fixed64,12,opt,name=search_score,json=searchScore,proto3" json:"search_score,omitempty"` } func (x *LogEntry) Reset() { @@ -257,6 +259,13 @@ func (x *LogEntry) GetTags() []string { return nil } +func (x *LogEntry) GetSearchScore() float64 { + if x != nil { + return x.SearchScore + } + return 0 +} + var File_logs_log_proto protoreflect.FileDescriptor var file_logs_log_proto_rawDesc = []byte{ @@ -266,7 +275,7 @@ var file_logs_log_proto_rawDesc = []byte{ 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdc, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xff, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, @@ -288,15 +297,17 @@ var file_logs_log_proto_rawDesc = []byte{ 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x04, 0x61, 0x74, 0x74, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x61, 0x67, 0x73, 0x2a, 0x45, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, - 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, - 0x03, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x04, 0x42, 0x2e, 0x5a, 0x2c, - 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, - 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2f, 0x6c, 0x6f, 0x67, 0x73, 0x3b, 0x6c, 0x6f, 0x67, 0x73, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, + 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x2a, 0x45, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, + 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, 0x12, 0x0b, + 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, + 0x41, 0x4c, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x04, 0x42, + 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, + 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x6f, 0x67, 0x73, 0x3b, 0x6c, 0x6f, 0x67, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -313,7 +324,7 @@ func file_logs_log_proto_rawDescGZIP() []byte { var file_logs_log_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_logs_log_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_logs_log_proto_goTypes = []interface{}{ +var file_logs_log_proto_goTypes = []any{ (LogLevel)(0), // 0: logs.LogLevel (*LogEntry)(nil), // 1: logs.LogEntry (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp @@ -336,7 +347,7 @@ func file_logs_log_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_logs_log_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*LogEntry); i { case 0: return &v.state diff --git a/proto/logs/log_service.pb.go b/proto/logs/log_service.pb.go index 7036778591e3e51156c67eccffb05976fea10d38..114d5229d30504b202cd9475741b65b4d28831a3 100644 --- a/proto/logs/log_service.pb.go +++ b/proto/logs/log_service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: logs/log_service.proto package logs @@ -568,7 +568,7 @@ func file_logs_log_service_proto_rawDescGZIP() []byte { } var file_logs_log_service_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_logs_log_service_proto_goTypes = []interface{}{ +var file_logs_log_service_proto_goTypes = []any{ (*LogRequest)(nil), // 0: logs.LogRequest (*LogResponse)(nil), // 1: logs.LogResponse (*Filter)(nil), // 2: logs.Filter @@ -613,7 +613,7 @@ func file_logs_log_service_proto_init() { } file_logs_log_proto_init() if !protoimpl.UnsafeEnabled { - file_logs_log_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*LogRequest); i { case 0: return &v.state @@ -625,7 +625,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*LogResponse); i { case 0: return &v.state @@ -637,7 +637,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Filter); i { case 0: return &v.state @@ -649,7 +649,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*FindRequest); i { case 0: return &v.state @@ -661,7 +661,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*FindResult); i { case 0: return &v.state @@ -673,7 +673,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*FindResponse); i { case 0: return &v.state @@ -685,7 +685,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -697,7 +697,7 @@ func file_logs_log_service_proto_init() { return nil } } - file_logs_log_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_logs_log_service_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*DeleteResponse); i { case 0: return &v.state @@ -710,7 +710,7 @@ func file_logs_log_service_proto_init() { } } } - file_logs_log_service_proto_msgTypes[5].OneofWrappers = []interface{}{ + file_logs_log_service_proto_msgTypes[5].OneofWrappers = []any{ (*FindResponse_Result)(nil), (*FindResponse_Error)(nil), } diff --git a/proto/logs/log_service_grpc.pb.go b/proto/logs/log_service_grpc.pb.go index ad55cee20f51d0135ab737a566f405696fe693fa..c8fd4bc4dbc5c0c044d6791f3ce62018d645a7d4 100644 --- a/proto/logs/log_service_grpc.pb.go +++ b/proto/logs/log_service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: logs/log_service.proto package logs @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( LogsService_Log_FullMethodName = "/logs.LogsService/Log" @@ -27,6 +27,9 @@ const ( // LogsServiceClient is the client API for LogsService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Сервис для записи активности в системе +// Позволяет всем компонентам системы записывать логи в единое хранилище и получать их оттуда type LogsServiceClient interface { // Метод для записи логов Log(ctx context.Context, in *LogRequest, opts ...grpc.CallOption) (*LogResponse, error) @@ -45,8 +48,9 @@ func NewLogsServiceClient(cc grpc.ClientConnInterface) LogsServiceClient { } func (c *logsServiceClient) Log(ctx context.Context, in *LogRequest, opts ...grpc.CallOption) (*LogResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(LogResponse) - err := c.cc.Invoke(ctx, LogsService_Log_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, LogsService_Log_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -54,8 +58,9 @@ func (c *logsServiceClient) Log(ctx context.Context, in *LogRequest, opts ...grp } func (c *logsServiceClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindResponse) - err := c.cc.Invoke(ctx, LogsService_Find_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, LogsService_Find_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -63,8 +68,9 @@ func (c *logsServiceClient) Find(ctx context.Context, in *FindRequest, opts ...g } func (c *logsServiceClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(DeleteResponse) - err := c.cc.Invoke(ctx, LogsService_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, LogsService_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -73,7 +79,10 @@ func (c *logsServiceClient) Delete(ctx context.Context, in *DeleteRequest, opts // LogsServiceServer is the server API for LogsService service. // All implementations must embed UnimplementedLogsServiceServer -// for forward compatibility +// for forward compatibility. +// +// Сервис для записи активности в системе +// Позволяет всем компонентам системы записывать логи в единое хранилище и получать их оттуда type LogsServiceServer interface { // Метод для записи логов Log(context.Context, *LogRequest) (*LogResponse, error) @@ -84,9 +93,12 @@ type LogsServiceServer interface { mustEmbedUnimplementedLogsServiceServer() } -// UnimplementedLogsServiceServer must be embedded to have forward compatible implementations. -type UnimplementedLogsServiceServer struct { -} +// UnimplementedLogsServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedLogsServiceServer struct{} func (UnimplementedLogsServiceServer) Log(context.Context, *LogRequest) (*LogResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Log not implemented") @@ -98,6 +110,7 @@ func (UnimplementedLogsServiceServer) Delete(context.Context, *DeleteRequest) (* return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func (UnimplementedLogsServiceServer) mustEmbedUnimplementedLogsServiceServer() {} +func (UnimplementedLogsServiceServer) testEmbeddedByValue() {} // UnsafeLogsServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to LogsServiceServer will @@ -107,6 +120,13 @@ type UnsafeLogsServiceServer interface { } func RegisterLogsServiceServer(s grpc.ServiceRegistrar, srv LogsServiceServer) { + // If the following call pancis, it indicates UnimplementedLogsServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&LogsService_ServiceDesc, srv) } diff --git a/proto/members/members.pb.go b/proto/members/members.pb.go index a939a3f8189f6f100b61a4ad070a3c4fb30fb023..deb1ac559b3f59243f01b8ab142b57e3c98ad675 100644 --- a/proto/members/members.pb.go +++ b/proto/members/members.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: members/members.proto package members @@ -759,7 +759,7 @@ func file_members_members_proto_rawDescGZIP() []byte { var file_members_members_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_members_members_proto_msgTypes = make([]protoimpl.MessageInfo, 11) -var file_members_members_proto_goTypes = []interface{}{ +var file_members_members_proto_goTypes = []any{ (Role)(0), // 0: account.members.Role (*Member)(nil), // 1: account.members.Member (*SetRequest)(nil), // 2: account.members.SetRequest @@ -807,7 +807,7 @@ func file_members_members_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_members_members_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Member); i { case 0: return &v.state @@ -819,7 +819,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*SetRequest); i { case 0: return &v.state @@ -831,7 +831,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -843,7 +843,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -855,7 +855,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*RemoveRequest); i { case 0: return &v.state @@ -867,7 +867,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ListMembersRequest); i { case 0: return &v.state @@ -879,7 +879,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ListMembersResponse); i { case 0: return &v.state @@ -891,7 +891,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ListOrganizationsRequest); i { case 0: return &v.state @@ -903,7 +903,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ListOrganizationsResponse); i { case 0: return &v.state @@ -915,7 +915,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*OnCollaboratorSetRequest); i { case 0: return &v.state @@ -927,7 +927,7 @@ func file_members_members_proto_init() { return nil } } - file_members_members_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_members_members_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*OnCollaboratorSetResponse); i { case 0: return &v.state diff --git a/proto/members/members_grpc.pb.go b/proto/members/members_grpc.pb.go index c0216bfe1d7c10c12a4d02d32b5ba6774cfcd59c..8b6677f46851145550d3f509ba230997c9848e4d 100644 --- a/proto/members/members_grpc.pb.go +++ b/proto/members/members_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: members/members.proto package members @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Members_Set_FullMethodName = "/account.members.Members/Set" @@ -47,8 +47,9 @@ func NewMembersClient(cc grpc.ClientConnInterface) MembersClient { } func (c *membersClient) Set(ctx context.Context, in *SetRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Members_Set_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Members_Set_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -56,8 +57,9 @@ func (c *membersClient) Set(ctx context.Context, in *SetRequest, opts ...grpc.Ca } func (c *membersClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Members_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Members_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -65,8 +67,9 @@ func (c *membersClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Ca } func (c *membersClient) Remove(ctx context.Context, in *RemoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Members_Remove_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Members_Remove_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -74,8 +77,9 @@ func (c *membersClient) Remove(ctx context.Context, in *RemoveRequest, opts ...g } func (c *membersClient) ListMembers(ctx context.Context, in *ListMembersRequest, opts ...grpc.CallOption) (*ListMembersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListMembersResponse) - err := c.cc.Invoke(ctx, Members_ListMembers_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Members_ListMembers_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -83,8 +87,9 @@ func (c *membersClient) ListMembers(ctx context.Context, in *ListMembersRequest, } func (c *membersClient) ListOrganizations(ctx context.Context, in *ListOrganizationsRequest, opts ...grpc.CallOption) (*ListOrganizationsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListOrganizationsResponse) - err := c.cc.Invoke(ctx, Members_ListOrganizations_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Members_ListOrganizations_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -93,7 +98,7 @@ func (c *membersClient) ListOrganizations(ctx context.Context, in *ListOrganizat // MembersServer is the server API for Members service. // All implementations must embed UnimplementedMembersServer -// for forward compatibility +// for forward compatibility. type MembersServer interface { Set(context.Context, *SetRequest) (*emptypb.Empty, error) Get(context.Context, *GetRequest) (*GetResponse, error) @@ -103,9 +108,12 @@ type MembersServer interface { mustEmbedUnimplementedMembersServer() } -// UnimplementedMembersServer must be embedded to have forward compatible implementations. -type UnimplementedMembersServer struct { -} +// UnimplementedMembersServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedMembersServer struct{} func (UnimplementedMembersServer) Set(context.Context, *SetRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Set not implemented") @@ -123,6 +131,7 @@ func (UnimplementedMembersServer) ListOrganizations(context.Context, *ListOrgani return nil, status.Errorf(codes.Unimplemented, "method ListOrganizations not implemented") } func (UnimplementedMembersServer) mustEmbedUnimplementedMembersServer() {} +func (UnimplementedMembersServer) testEmbeddedByValue() {} // UnsafeMembersServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to MembersServer will @@ -132,6 +141,13 @@ type UnsafeMembersServer interface { } func RegisterMembersServer(s grpc.ServiceRegistrar, srv MembersServer) { + // If the following call pancis, it indicates UnimplementedMembersServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Members_ServiceDesc, srv) } @@ -277,8 +293,9 @@ func NewObserverClient(cc grpc.ClientConnInterface) ObserverClient { } func (c *observerClient) OnCollaboratorSet(ctx context.Context, in *OnCollaboratorSetRequest, opts ...grpc.CallOption) (*OnCollaboratorSetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(OnCollaboratorSetResponse) - err := c.cc.Invoke(ctx, Observer_OnCollaboratorSet_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Observer_OnCollaboratorSet_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -287,20 +304,24 @@ func (c *observerClient) OnCollaboratorSet(ctx context.Context, in *OnCollaborat // ObserverServer is the server API for Observer service. // All implementations must embed UnimplementedObserverServer -// for forward compatibility +// for forward compatibility. type ObserverServer interface { OnCollaboratorSet(context.Context, *OnCollaboratorSetRequest) (*OnCollaboratorSetResponse, error) mustEmbedUnimplementedObserverServer() } -// UnimplementedObserverServer must be embedded to have forward compatible implementations. -type UnimplementedObserverServer struct { -} +// UnimplementedObserverServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedObserverServer struct{} func (UnimplementedObserverServer) OnCollaboratorSet(context.Context, *OnCollaboratorSetRequest) (*OnCollaboratorSetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method OnCollaboratorSet not implemented") } func (UnimplementedObserverServer) mustEmbedUnimplementedObserverServer() {} +func (UnimplementedObserverServer) testEmbeddedByValue() {} // UnsafeObserverServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ObserverServer will @@ -310,6 +331,13 @@ type UnsafeObserverServer interface { } func RegisterObserverServer(s grpc.ServiceRegistrar, srv ObserverServer) { + // If the following call pancis, it indicates UnimplementedObserverServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Observer_ServiceDesc, srv) } diff --git a/proto/organizations/organizations.pb.go b/proto/organizations/organizations.pb.go index b744640573280053557944e9cbd93a43b0be7b46..d2a220a15017de2caa99f33957d2acd000589ebd 100644 --- a/proto/organizations/organizations.pb.go +++ b/proto/organizations/organizations.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: organizations/organizations.proto package organizations @@ -654,7 +654,7 @@ func file_organizations_organizations_proto_rawDescGZIP() []byte { } var file_organizations_organizations_proto_msgTypes = make([]protoimpl.MessageInfo, 10) -var file_organizations_organizations_proto_goTypes = []interface{}{ +var file_organizations_organizations_proto_goTypes = []any{ (*Organization)(nil), // 0: account.organizations.Organization (*CreateRequest)(nil), // 1: account.organizations.CreateRequest (*CreateResponse)(nil), // 2: account.organizations.CreateResponse @@ -699,7 +699,7 @@ func file_organizations_organizations_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_organizations_organizations_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Organization); i { case 0: return &v.state @@ -711,7 +711,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -723,7 +723,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -735,7 +735,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -747,7 +747,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -759,7 +759,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -771,7 +771,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -783,7 +783,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*Filter); i { case 0: return &v.state @@ -795,7 +795,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*FindRequest); i { case 0: return &v.state @@ -807,7 +807,7 @@ func file_organizations_organizations_proto_init() { return nil } } - file_organizations_organizations_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_organizations_organizations_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*FindResponse); i { case 0: return &v.state @@ -820,7 +820,7 @@ func file_organizations_organizations_proto_init() { } } } - file_organizations_organizations_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_organizations_organizations_proto_msgTypes[0].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/proto/organizations/organizations_grpc.pb.go b/proto/organizations/organizations_grpc.pb.go index dc737ac9a2eb95cb6c977f537216942dfd4164d7..09aa7525515d4688ae40eed6aa7d0107feb5ad62 100644 --- a/proto/organizations/organizations_grpc.pb.go +++ b/proto/organizations/organizations_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: organizations/organizations.proto package organizations @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Organizations_Create_FullMethodName = "/account.organizations.Organizations/Create" @@ -47,8 +47,9 @@ func NewOrganizationsClient(cc grpc.ClientConnInterface) OrganizationsClient { } func (c *organizationsClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Organizations_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Organizations_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -56,8 +57,9 @@ func (c *organizationsClient) Create(ctx context.Context, in *CreateRequest, opt } func (c *organizationsClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Organizations_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Organizations_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -65,8 +67,9 @@ func (c *organizationsClient) Get(ctx context.Context, in *GetRequest, opts ...g } func (c *organizationsClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Organizations_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Organizations_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -74,8 +77,9 @@ func (c *organizationsClient) Delete(ctx context.Context, in *DeleteRequest, opt } func (c *organizationsClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindResponse) - err := c.cc.Invoke(ctx, Organizations_Find_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Organizations_Find_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -83,8 +87,9 @@ func (c *organizationsClient) Find(ctx context.Context, in *FindRequest, opts .. } func (c *organizationsClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Organizations_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Organizations_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -93,7 +98,7 @@ func (c *organizationsClient) Update(ctx context.Context, in *UpdateRequest, opt // OrganizationsServer is the server API for Organizations service. // All implementations must embed UnimplementedOrganizationsServer -// for forward compatibility +// for forward compatibility. type OrganizationsServer interface { Create(context.Context, *CreateRequest) (*CreateResponse, error) Get(context.Context, *GetRequest) (*GetResponse, error) @@ -103,9 +108,12 @@ type OrganizationsServer interface { mustEmbedUnimplementedOrganizationsServer() } -// UnimplementedOrganizationsServer must be embedded to have forward compatible implementations. -type UnimplementedOrganizationsServer struct { -} +// UnimplementedOrganizationsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedOrganizationsServer struct{} func (UnimplementedOrganizationsServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -123,6 +131,7 @@ func (UnimplementedOrganizationsServer) Update(context.Context, *UpdateRequest) return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") } func (UnimplementedOrganizationsServer) mustEmbedUnimplementedOrganizationsServer() {} +func (UnimplementedOrganizationsServer) testEmbeddedByValue() {} // UnsafeOrganizationsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to OrganizationsServer will @@ -132,6 +141,13 @@ type UnsafeOrganizationsServer interface { } func RegisterOrganizationsServer(s grpc.ServiceRegistrar, srv OrganizationsServer) { + // If the following call pancis, it indicates UnimplementedOrganizationsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Organizations_ServiceDesc, srv) } diff --git a/proto/references/references.pb.go b/proto/references/references.pb.go index 64895f9fa4b2e475dbc9444ee9998fc3d4204699..235312d912171d073957187c4087c563c010a58c 100644 --- a/proto/references/references.pb.go +++ b/proto/references/references.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: references/references.proto package references @@ -92,6 +92,7 @@ type GetRequest struct { SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` EnvId string `protobuf:"bytes,2,opt,name=env_id,json=envId,proto3" json:"env_id,omitempty"` References []*Reference `protobuf:"bytes,3,rep,name=references,proto3" json:"references,omitempty"` + Options *GetOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"` // Дополнительные параметры поиска } func (x *GetRequest) Reset() { @@ -147,6 +148,13 @@ func (x *GetRequest) GetReferences() []*Reference { return nil } +func (x *GetRequest) GetOptions() *GetOptions { + if x != nil { + return x.Options + } + return nil +} + type GetResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -346,6 +354,61 @@ func (x *PublishResponse) GetUnpublished() []*Reference { return nil } +type GetOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LocaleId string `protobuf:"bytes,1,opt,name=locale_id,json=localeId,proto3" json:"locale_id,omitempty"` // Язык перевода который будет использоваться. Если не указан, то возвращаются данные для языка по умолчанию + TranslationsIds []string `protobuf:"bytes,2,rep,name=translations_ids,json=translationsIds,proto3" json:"translations_ids,omitempty"` // Список идентификаторов переводов/локалей, которых должны быть включены в результат +} + +func (x *GetOptions) Reset() { + *x = GetOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_references_references_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetOptions) ProtoMessage() {} + +func (x *GetOptions) ProtoReflect() protoreflect.Message { + mi := &file_references_references_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetOptions.ProtoReflect.Descriptor instead. +func (*GetOptions) Descriptor() ([]byte, []int) { + return file_references_references_proto_rawDescGZIP(), []int{5} +} + +func (x *GetOptions) GetLocaleId() string { + if x != nil { + return x.LocaleId + } + return "" +} + +func (x *GetOptions) GetTranslationsIds() []string { + if x != nil { + return x.TranslationsIds + } + return nil +} + var File_references_references_proto protoreflect.FileDescriptor var file_references_references_proto_rawDesc = []byte{ @@ -359,61 +422,70 @@ var file_references_references_proto_rawDesc = []byte{ 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x22, 0x7d, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, - 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, - 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x73, 0x22, 0x73, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x29, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6e, - 0x6f, 0x74, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x6e, 0x6f, - 0x74, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0xb5, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, - 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, - 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0xca, - 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, - 0x39, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3f, 0x0a, 0x0b, 0x75, 0x6e, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0b, - 0x75, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x32, 0xac, 0x01, 0x0a, 0x0a, - 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x03, 0x47, 0x65, - 0x74, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x07, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, - 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, - 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, - 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x3b, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, + 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, + 0x76, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x12, 0x38, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x73, 0x0a, 0x0b, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, + 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x66, 0x6f, 0x75, + 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x66, 0x6f, 0x75, 0x6e, + 0x64, 0x22, 0xb5, 0x01, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x15, 0x0a, 0x06, 0x65, 0x6e, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x65, 0x6e, 0x76, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, + 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, + 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, + 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0xca, 0x01, 0x0a, 0x0f, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, + 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, + 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x08, 0x6e, 0x6f, + 0x74, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x73, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x6e, 0x6f, 0x74, + 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3f, 0x0a, 0x0b, 0x75, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, + 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0b, 0x75, 0x6e, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x22, 0x54, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x49, + 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x49, 0x64, 0x73, 0x32, 0xac, 0x01, 0x0a, + 0x0a, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x03, 0x47, + 0x65, 0x74, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x07, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3a, 0x5a, 0x38, 0x67, + 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, + 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x3b, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -428,32 +500,34 @@ func file_references_references_proto_rawDescGZIP() []byte { return file_references_references_proto_rawDescData } -var file_references_references_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_references_references_proto_goTypes = []interface{}{ +var file_references_references_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_references_references_proto_goTypes = []any{ (*Reference)(nil), // 0: content.references.Reference (*GetRequest)(nil), // 1: content.references.GetRequest (*GetResponse)(nil), // 2: content.references.GetResponse (*PublishRequest)(nil), // 3: content.references.PublishRequest (*PublishResponse)(nil), // 4: content.references.PublishResponse - (*items.Item)(nil), // 5: content.items.Item + (*GetOptions)(nil), // 5: content.references.GetOptions + (*items.Item)(nil), // 6: content.items.Item } var file_references_references_proto_depIdxs = []int32{ - 0, // 0: content.references.GetRequest.references:type_name -> content.references.Reference - 5, // 1: content.references.GetResponse.items:type_name -> content.items.Item - 0, // 2: content.references.GetResponse.notfound:type_name -> content.references.Reference - 0, // 3: content.references.PublishRequest.references:type_name -> content.references.Reference - 0, // 4: content.references.PublishResponse.published:type_name -> content.references.Reference - 0, // 5: content.references.PublishResponse.notfound:type_name -> content.references.Reference - 0, // 6: content.references.PublishResponse.unpublished:type_name -> content.references.Reference - 1, // 7: content.references.References.Get:input_type -> content.references.GetRequest - 3, // 8: content.references.References.Publish:input_type -> content.references.PublishRequest - 2, // 9: content.references.References.Get:output_type -> content.references.GetResponse - 4, // 10: content.references.References.Publish:output_type -> content.references.PublishResponse - 9, // [9:11] is the sub-list for method output_type - 7, // [7:9] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 0, // 0: content.references.GetRequest.references:type_name -> content.references.Reference + 5, // 1: content.references.GetRequest.options:type_name -> content.references.GetOptions + 6, // 2: content.references.GetResponse.items:type_name -> content.items.Item + 0, // 3: content.references.GetResponse.notfound:type_name -> content.references.Reference + 0, // 4: content.references.PublishRequest.references:type_name -> content.references.Reference + 0, // 5: content.references.PublishResponse.published:type_name -> content.references.Reference + 0, // 6: content.references.PublishResponse.notfound:type_name -> content.references.Reference + 0, // 7: content.references.PublishResponse.unpublished:type_name -> content.references.Reference + 1, // 8: content.references.References.Get:input_type -> content.references.GetRequest + 3, // 9: content.references.References.Publish:input_type -> content.references.PublishRequest + 2, // 10: content.references.References.Get:output_type -> content.references.GetResponse + 4, // 11: content.references.References.Publish:output_type -> content.references.PublishResponse + 10, // [10:12] is the sub-list for method output_type + 8, // [8:10] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_references_references_proto_init() } @@ -462,7 +536,7 @@ func file_references_references_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_references_references_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_references_references_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Reference); i { case 0: return &v.state @@ -474,7 +548,7 @@ func file_references_references_proto_init() { return nil } } - file_references_references_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_references_references_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -486,7 +560,7 @@ func file_references_references_proto_init() { return nil } } - file_references_references_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_references_references_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -498,7 +572,7 @@ func file_references_references_proto_init() { return nil } } - file_references_references_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_references_references_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*PublishRequest); i { case 0: return &v.state @@ -510,7 +584,7 @@ func file_references_references_proto_init() { return nil } } - file_references_references_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_references_references_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*PublishResponse); i { case 0: return &v.state @@ -522,6 +596,18 @@ func file_references_references_proto_init() { return nil } } + file_references_references_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*GetOptions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -529,7 +615,7 @@ func file_references_references_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_references_references_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/references/references_grpc.pb.go b/proto/references/references_grpc.pb.go index 750571cede9b697ed3392cd96941b2db54934fcb..f6b37c167ea54f950198a969a7c2f3420346d5c8 100644 --- a/proto/references/references_grpc.pb.go +++ b/proto/references/references_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: references/references.proto package references @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( References_Get_FullMethodName = "/content.references.References/Get" @@ -26,6 +26,8 @@ const ( // ReferencesClient is the client API for References service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// References сервис предназначен для работы со ссылками на записи type ReferencesClient interface { // Get возвращает список записей по ссылкам Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) @@ -51,8 +53,9 @@ func NewReferencesClient(cc grpc.ClientConnInterface) ReferencesClient { } func (c *referencesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, References_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, References_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -60,8 +63,9 @@ func (c *referencesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc } func (c *referencesClient) Publish(ctx context.Context, in *PublishRequest, opts ...grpc.CallOption) (*PublishResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(PublishResponse) - err := c.cc.Invoke(ctx, References_Publish_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, References_Publish_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -70,7 +74,9 @@ func (c *referencesClient) Publish(ctx context.Context, in *PublishRequest, opts // ReferencesServer is the server API for References service. // All implementations must embed UnimplementedReferencesServer -// for forward compatibility +// for forward compatibility. +// +// References сервис предназначен для работы со ссылками на записи type ReferencesServer interface { // Get возвращает список записей по ссылкам Get(context.Context, *GetRequest) (*GetResponse, error) @@ -88,9 +94,12 @@ type ReferencesServer interface { mustEmbedUnimplementedReferencesServer() } -// UnimplementedReferencesServer must be embedded to have forward compatible implementations. -type UnimplementedReferencesServer struct { -} +// UnimplementedReferencesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedReferencesServer struct{} func (UnimplementedReferencesServer) Get(context.Context, *GetRequest) (*GetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") @@ -99,6 +108,7 @@ func (UnimplementedReferencesServer) Publish(context.Context, *PublishRequest) ( return nil, status.Errorf(codes.Unimplemented, "method Publish not implemented") } func (UnimplementedReferencesServer) mustEmbedUnimplementedReferencesServer() {} +func (UnimplementedReferencesServer) testEmbeddedByValue() {} // UnsafeReferencesServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to ReferencesServer will @@ -108,6 +118,13 @@ type UnsafeReferencesServer interface { } func RegisterReferencesServer(s grpc.ServiceRegistrar, srv ReferencesServer) { + // If the following call pancis, it indicates UnimplementedReferencesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&References_ServiceDesc, srv) } diff --git a/proto/roles/roles.pb.go b/proto/roles/roles.pb.go index 0d70814977a6b765b8377739bd3f43704b98ec02..380ce70fad2a498d1349c019238cb26086131c1f 100644 --- a/proto/roles/roles.pb.go +++ b/proto/roles/roles.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: roles/roles.proto package roles @@ -605,7 +605,7 @@ func file_roles_roles_proto_rawDescGZIP() []byte { } var file_roles_roles_proto_msgTypes = make([]protoimpl.MessageInfo, 9) -var file_roles_roles_proto_goTypes = []interface{}{ +var file_roles_roles_proto_goTypes = []any{ (*Role)(nil), // 0: content.roles.Role (*CreateRequest)(nil), // 1: content.roles.CreateRequest (*CreateResponse)(nil), // 2: content.roles.CreateResponse @@ -648,7 +648,7 @@ func file_roles_roles_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_roles_roles_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Role); i { case 0: return &v.state @@ -660,7 +660,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -672,7 +672,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -684,7 +684,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -696,7 +696,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -708,7 +708,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -720,7 +720,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ListRequest); i { case 0: return &v.state @@ -732,7 +732,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ListResponse); i { case 0: return &v.state @@ -744,7 +744,7 @@ func file_roles_roles_proto_init() { return nil } } - file_roles_roles_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_roles_roles_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state diff --git a/proto/roles/roles_grpc.pb.go b/proto/roles/roles_grpc.pb.go index 13000eb2e08429aa6fcc93d5e133d4e3012c05ff..e82284338b495f0fc5ab7c67f419a0ca22e3484b 100644 --- a/proto/roles/roles_grpc.pb.go +++ b/proto/roles/roles_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: roles/roles.proto package roles @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Roles_Create_FullMethodName = "/content.roles.Roles/Create" @@ -52,8 +52,9 @@ func NewRolesClient(cc grpc.ClientConnInterface) RolesClient { } func (c *rolesClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Roles_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Roles_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -61,8 +62,9 @@ func (c *rolesClient) Create(ctx context.Context, in *CreateRequest, opts ...grp } func (c *rolesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Roles_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Roles_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -70,8 +72,9 @@ func (c *rolesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Call } func (c *rolesClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Roles_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Roles_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -79,8 +82,9 @@ func (c *rolesClient) Update(ctx context.Context, in *UpdateRequest, opts ...grp } func (c *rolesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListResponse) - err := c.cc.Invoke(ctx, Roles_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Roles_List_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -88,8 +92,9 @@ func (c *rolesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.Ca } func (c *rolesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Roles_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Roles_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -98,7 +103,7 @@ func (c *rolesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grp // RolesServer is the server API for Roles service. // All implementations must embed UnimplementedRolesServer -// for forward compatibility +// for forward compatibility. type RolesServer interface { // Create - создает роль в рамках пространства Create(context.Context, *CreateRequest) (*CreateResponse, error) @@ -113,9 +118,12 @@ type RolesServer interface { mustEmbedUnimplementedRolesServer() } -// UnimplementedRolesServer must be embedded to have forward compatible implementations. -type UnimplementedRolesServer struct { -} +// UnimplementedRolesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedRolesServer struct{} func (UnimplementedRolesServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -133,6 +141,7 @@ func (UnimplementedRolesServer) Delete(context.Context, *DeleteRequest) (*emptyp return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented") } func (UnimplementedRolesServer) mustEmbedUnimplementedRolesServer() {} +func (UnimplementedRolesServer) testEmbeddedByValue() {} // UnsafeRolesServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to RolesServer will @@ -142,6 +151,13 @@ type UnsafeRolesServer interface { } func RegisterRolesServer(s grpc.ServiceRegistrar, srv RolesServer) { + // If the following call pancis, it indicates UnimplementedRolesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Roles_ServiceDesc, srv) } diff --git a/proto/spaces/spaces.pb.go b/proto/spaces/spaces.pb.go index aedef2c39158d62f2fb08844c27c9c7f0fac6cb1..32a78ef8be7bf42af39daa7b3199311efe483c55 100644 --- a/proto/spaces/spaces.pb.go +++ b/proto/spaces/spaces.pb.go @@ -1,12 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: spaces/spaces.proto package spaces import ( + common "git.perx.ru/perxis/perxis-go/proto/common" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" @@ -991,6 +992,197 @@ func (x *MoveRequest) GetOrgId() string { return "" } +type Filter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id []string `protobuf:"bytes,1,rep,name=id,proto3" json:"id,omitempty"` // Список ID пространств + OrgId []string `protobuf:"bytes,2,rep,name=org_id,json=orgId,proto3" json:"org_id,omitempty"` // Список организаций + Name []string `protobuf:"bytes,3,rep,name=name,proto3" json:"name,omitempty"` // Список названий + State []State `protobuf:"varint,4,rep,packed,name=state,proto3,enum=content.spaces.State" json:"state,omitempty"` // Список состояний + TransferToOrg []string `protobuf:"bytes,5,rep,name=transfer_to_org,json=transferToOrg,proto3" json:"transfer_to_org,omitempty"` // Список организаций, в которые запрошен перенос пространства +} + +func (x *Filter) Reset() { + *x = Filter{} + if protoimpl.UnsafeEnabled { + mi := &file_spaces_spaces_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Filter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Filter) ProtoMessage() {} + +func (x *Filter) ProtoReflect() protoreflect.Message { + mi := &file_spaces_spaces_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Filter.ProtoReflect.Descriptor instead. +func (*Filter) Descriptor() ([]byte, []int) { + return file_spaces_spaces_proto_rawDescGZIP(), []int{17} +} + +func (x *Filter) GetId() []string { + if x != nil { + return x.Id + } + return nil +} + +func (x *Filter) GetOrgId() []string { + if x != nil { + return x.OrgId + } + return nil +} + +func (x *Filter) GetName() []string { + if x != nil { + return x.Name + } + return nil +} + +func (x *Filter) GetState() []State { + if x != nil { + return x.State + } + return nil +} + +func (x *Filter) GetTransferToOrg() []string { + if x != nil { + return x.TransferToOrg + } + return nil +} + +type FindRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Фильтры для поиска + Filter *Filter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + // Опции поиска + Options *common.FindOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *FindRequest) Reset() { + *x = FindRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_spaces_spaces_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindRequest) ProtoMessage() {} + +func (x *FindRequest) ProtoReflect() protoreflect.Message { + mi := &file_spaces_spaces_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindRequest.ProtoReflect.Descriptor instead. +func (*FindRequest) Descriptor() ([]byte, []int) { + return file_spaces_spaces_proto_rawDescGZIP(), []int{18} +} + +func (x *FindRequest) GetFilter() *Filter { + if x != nil { + return x.Filter + } + return nil +} + +func (x *FindRequest) GetOptions() *common.FindOptions { + if x != nil { + return x.Options + } + return nil +} + +type FindResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Spaces []*Space `protobuf:"bytes,1,rep,name=spaces,proto3" json:"spaces,omitempty"` + Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` +} + +func (x *FindResponse) Reset() { + *x = FindResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_spaces_spaces_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FindResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FindResponse) ProtoMessage() {} + +func (x *FindResponse) ProtoReflect() protoreflect.Message { + mi := &file_spaces_spaces_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FindResponse.ProtoReflect.Descriptor instead. +func (*FindResponse) Descriptor() ([]byte, []int) { + return file_spaces_spaces_proto_rawDescGZIP(), []int{19} +} + +func (x *FindResponse) GetSpaces() []*Space { + if x != nil { + return x.Spaces + } + return nil +} + +func (x *FindResponse) GetTotal() int32 { + if x != nil { + return x.Total + } + return 0 +} + var File_spaces_spaces_proto protoreflect.FileDescriptor var file_spaces_spaces_proto_rawDesc = []byte{ @@ -1000,148 +1192,176 @@ var file_spaces_spaces_proto_rawDesc = []byte{ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0xa3, 0x02, 0x0a, 0x05, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, - 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, - 0x72, 0x67, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x66, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x6f, 0x4f, 0x72, 0x67, 0x12, - 0x2e, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x38, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x9b, 0x01, 0x0a, 0x09, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x62, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x62, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x24, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x3c, 0x0a, - 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, + 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa3, 0x02, 0x0a, 0x05, 0x53, 0x70, 0x61, + 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x2b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x6f, 0x72, 0x67, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, + 0x6f, 0x4f, 0x72, 0x67, 0x12, 0x2e, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x9b, + 0x01, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, + 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, + 0x0a, 0x64, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x64, 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x04, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x24, 0x0a, 0x06, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x22, 0x41, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x22, 0x27, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x3a, 0x0a, 0x0b, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x24, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x22, 0x3d, + 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, + 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x22, 0x3c, 0x0a, + 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, - 0x70, 0x61, 0x63, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x41, 0x0a, 0x0e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, - 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x27, - 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, + 0x70, 0x61, 0x63, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x13, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, + 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2a, 0x0a, + 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, + 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x54, 0x0a, 0x0f, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x3a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x05, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x22, 0x24, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x22, 0x3d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, - 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, - 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x60, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, - 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2a, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x49, 0x64, 0x22, 0x54, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x6f, 0x4f, 0x72, 0x67, 0x22, + 0x31, 0x0a, 0x14, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x74, - 0x6f, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x6f, 0x4f, 0x72, 0x67, 0x22, 0x31, 0x0a, 0x14, 0x41, 0x62, - 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x22, 0x2d, 0x0a, - 0x14, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x22, 0x46, 0x0a, 0x15, - 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x0b, 0x4d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x15, - 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6f, 0x72, 0x67, 0x49, 0x64, 0x2a, 0x70, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, - 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4e, - 0x45, 0x57, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x12, - 0x0d, 0x0a, 0x09, 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0f, - 0x0a, 0x0b, 0x4d, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x04, 0x12, - 0x0d, 0x0a, 0x09, 0x4d, 0x49, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x0c, - 0x0a, 0x08, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x07, 0x32, 0xe6, 0x05, 0x0a, 0x06, 0x53, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x12, 0x49, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, - 0x03, 0x47, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x43, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1d, + 0x49, 0x64, 0x22, 0x2d, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, + 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, + 0x64, 0x22, 0x46, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x0b, 0x4d, 0x6f, 0x76, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x22, 0x98, 0x01, 0x0a, 0x06, 0x46, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, + 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x6f, 0x72, 0x67, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x54, 0x6f, 0x4f, 0x72, 0x67, 0x22, 0x6c, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, + 0x69, 0x6e, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x53, 0x0a, 0x0c, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x2a, 0x70, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, + 0x0a, 0x03, 0x4e, 0x45, 0x57, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, 0x59, + 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x49, 0x4e, 0x47, 0x10, + 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, + 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x49, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, + 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, + 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x07, 0x32, 0xab, 0x06, 0x0a, 0x06, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, + 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x08, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, - 0x12, 0x4f, 0x0a, 0x0d, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, - 0x72, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x2e, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x40, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x43, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x04, 0x46, 0x69, 0x6e, 0x64, 0x12, + 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x46, 0x69, + 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x06, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, + 0x4d, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x41, + 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, - 0x00, 0x12, 0x5e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, - 0x72, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x3d, 0x0a, 0x04, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, - 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, - 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x00, 0x12, 0x45, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x1f, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0d, 0x41, 0x62, 0x6f, 0x72, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x41, 0x62, 0x6f, 0x72, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x04, 0x4d, 0x6f, 0x76, + 0x65, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x2e, + 0x70, 0x65, 0x72, 0x78, 0x2e, 0x72, 0x75, 0x2f, 0x70, 0x65, 0x72, 0x78, 0x69, 0x73, 0x2f, 0x70, + 0x65, 0x72, 0x78, 0x69, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1157,8 +1377,8 @@ func file_spaces_spaces_proto_rawDescGZIP() []byte { } var file_spaces_spaces_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_spaces_spaces_proto_msgTypes = make([]protoimpl.MessageInfo, 17) -var file_spaces_spaces_proto_goTypes = []interface{}{ +var file_spaces_spaces_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_spaces_spaces_proto_goTypes = []any{ (State)(0), // 0: content.spaces.State (*Space)(nil), // 1: content.spaces.Space (*StateInfo)(nil), // 2: content.spaces.StateInfo @@ -1177,15 +1397,19 @@ var file_spaces_spaces_proto_goTypes = []interface{}{ (*ListTransfersRequest)(nil), // 15: content.spaces.ListTransfersRequest (*ListTransfersResponse)(nil), // 16: content.spaces.ListTransfersResponse (*MoveRequest)(nil), // 17: content.spaces.MoveRequest - (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 19: google.protobuf.Empty + (*Filter)(nil), // 18: content.spaces.Filter + (*FindRequest)(nil), // 19: content.spaces.FindRequest + (*FindResponse)(nil), // 20: content.spaces.FindResponse + (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp + (*common.FindOptions)(nil), // 22: common.FindOptions + (*emptypb.Empty)(nil), // 23: google.protobuf.Empty } var file_spaces_spaces_proto_depIdxs = []int32{ 0, // 0: content.spaces.Space.state:type_name -> content.spaces.State 3, // 1: content.spaces.Space.config:type_name -> content.spaces.Config 2, // 2: content.spaces.Space.state_info:type_name -> content.spaces.StateInfo 0, // 3: content.spaces.StateInfo.state:type_name -> content.spaces.State - 18, // 4: content.spaces.StateInfo.time:type_name -> google.protobuf.Timestamp + 21, // 4: content.spaces.StateInfo.time:type_name -> google.protobuf.Timestamp 1, // 5: content.spaces.CreateRequest.space:type_name -> content.spaces.Space 1, // 6: content.spaces.CreateResponse.created:type_name -> content.spaces.Space 1, // 7: content.spaces.GetResponse.space:type_name -> content.spaces.Space @@ -1193,31 +1417,37 @@ var file_spaces_spaces_proto_depIdxs = []int32{ 1, // 9: content.spaces.UpdateRequest.space:type_name -> content.spaces.Space 3, // 10: content.spaces.UpdateConfigRequest.config:type_name -> content.spaces.Config 1, // 11: content.spaces.ListTransfersResponse.spaces:type_name -> content.spaces.Space - 4, // 12: content.spaces.Spaces.Create:input_type -> content.spaces.CreateRequest - 6, // 13: content.spaces.Spaces.Get:input_type -> content.spaces.GetRequest - 8, // 14: content.spaces.Spaces.List:input_type -> content.spaces.ListRequest - 10, // 15: content.spaces.Spaces.Update:input_type -> content.spaces.UpdateRequest - 11, // 16: content.spaces.Spaces.UpdateConfig:input_type -> content.spaces.UpdateConfigRequest - 12, // 17: content.spaces.Spaces.Delete:input_type -> content.spaces.DeleteRequest - 13, // 18: content.spaces.Spaces.Transfer:input_type -> content.spaces.TransferRequest - 14, // 19: content.spaces.Spaces.AbortTransfer:input_type -> content.spaces.AbortTransferRequest - 15, // 20: content.spaces.Spaces.ListTransfers:input_type -> content.spaces.ListTransfersRequest - 17, // 21: content.spaces.Spaces.Move:input_type -> content.spaces.MoveRequest - 5, // 22: content.spaces.Spaces.Create:output_type -> content.spaces.CreateResponse - 7, // 23: content.spaces.Spaces.Get:output_type -> content.spaces.GetResponse - 9, // 24: content.spaces.Spaces.List:output_type -> content.spaces.ListResponse - 19, // 25: content.spaces.Spaces.Update:output_type -> google.protobuf.Empty - 19, // 26: content.spaces.Spaces.UpdateConfig:output_type -> google.protobuf.Empty - 19, // 27: content.spaces.Spaces.Delete:output_type -> google.protobuf.Empty - 19, // 28: content.spaces.Spaces.Transfer:output_type -> google.protobuf.Empty - 19, // 29: content.spaces.Spaces.AbortTransfer:output_type -> google.protobuf.Empty - 16, // 30: content.spaces.Spaces.ListTransfers:output_type -> content.spaces.ListTransfersResponse - 19, // 31: content.spaces.Spaces.Move:output_type -> google.protobuf.Empty - 22, // [22:32] is the sub-list for method output_type - 12, // [12:22] is the sub-list for method input_type - 12, // [12:12] is the sub-list for extension type_name - 12, // [12:12] is the sub-list for extension extendee - 0, // [0:12] is the sub-list for field type_name + 0, // 12: content.spaces.Filter.state:type_name -> content.spaces.State + 18, // 13: content.spaces.FindRequest.filter:type_name -> content.spaces.Filter + 22, // 14: content.spaces.FindRequest.options:type_name -> common.FindOptions + 1, // 15: content.spaces.FindResponse.spaces:type_name -> content.spaces.Space + 4, // 16: content.spaces.Spaces.Create:input_type -> content.spaces.CreateRequest + 6, // 17: content.spaces.Spaces.Get:input_type -> content.spaces.GetRequest + 8, // 18: content.spaces.Spaces.List:input_type -> content.spaces.ListRequest + 19, // 19: content.spaces.Spaces.Find:input_type -> content.spaces.FindRequest + 10, // 20: content.spaces.Spaces.Update:input_type -> content.spaces.UpdateRequest + 11, // 21: content.spaces.Spaces.UpdateConfig:input_type -> content.spaces.UpdateConfigRequest + 12, // 22: content.spaces.Spaces.Delete:input_type -> content.spaces.DeleteRequest + 13, // 23: content.spaces.Spaces.Transfer:input_type -> content.spaces.TransferRequest + 14, // 24: content.spaces.Spaces.AbortTransfer:input_type -> content.spaces.AbortTransferRequest + 15, // 25: content.spaces.Spaces.ListTransfers:input_type -> content.spaces.ListTransfersRequest + 17, // 26: content.spaces.Spaces.Move:input_type -> content.spaces.MoveRequest + 5, // 27: content.spaces.Spaces.Create:output_type -> content.spaces.CreateResponse + 7, // 28: content.spaces.Spaces.Get:output_type -> content.spaces.GetResponse + 9, // 29: content.spaces.Spaces.List:output_type -> content.spaces.ListResponse + 20, // 30: content.spaces.Spaces.Find:output_type -> content.spaces.FindResponse + 23, // 31: content.spaces.Spaces.Update:output_type -> google.protobuf.Empty + 23, // 32: content.spaces.Spaces.UpdateConfig:output_type -> google.protobuf.Empty + 23, // 33: content.spaces.Spaces.Delete:output_type -> google.protobuf.Empty + 23, // 34: content.spaces.Spaces.Transfer:output_type -> google.protobuf.Empty + 23, // 35: content.spaces.Spaces.AbortTransfer:output_type -> google.protobuf.Empty + 16, // 36: content.spaces.Spaces.ListTransfers:output_type -> content.spaces.ListTransfersResponse + 23, // 37: content.spaces.Spaces.Move:output_type -> google.protobuf.Empty + 27, // [27:38] is the sub-list for method output_type + 16, // [16:27] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name } func init() { file_spaces_spaces_proto_init() } @@ -1226,7 +1456,7 @@ func file_spaces_spaces_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_spaces_spaces_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Space); i { case 0: return &v.state @@ -1238,7 +1468,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*StateInfo); i { case 0: return &v.state @@ -1250,7 +1480,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Config); i { case 0: return &v.state @@ -1262,7 +1492,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -1274,7 +1504,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -1286,7 +1516,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -1298,7 +1528,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -1310,7 +1540,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*ListRequest); i { case 0: return &v.state @@ -1322,7 +1552,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*ListResponse); i { case 0: return &v.state @@ -1334,7 +1564,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1346,7 +1576,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*UpdateConfigRequest); i { case 0: return &v.state @@ -1358,7 +1588,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -1370,7 +1600,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*TransferRequest); i { case 0: return &v.state @@ -1382,7 +1612,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*AbortTransferRequest); i { case 0: return &v.state @@ -1394,7 +1624,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*ListTransfersRequest); i { case 0: return &v.state @@ -1406,7 +1636,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*ListTransfersResponse); i { case 0: return &v.state @@ -1418,7 +1648,7 @@ func file_spaces_spaces_proto_init() { return nil } } - file_spaces_spaces_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_spaces_spaces_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*MoveRequest); i { case 0: return &v.state @@ -1430,6 +1660,42 @@ func file_spaces_spaces_proto_init() { return nil } } + file_spaces_spaces_proto_msgTypes[17].Exporter = func(v any, i int) any { + switch v := v.(*Filter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_spaces_spaces_proto_msgTypes[18].Exporter = func(v any, i int) any { + switch v := v.(*FindRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_spaces_spaces_proto_msgTypes[19].Exporter = func(v any, i int) any { + switch v := v.(*FindResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1437,7 +1703,7 @@ func file_spaces_spaces_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_spaces_spaces_proto_rawDesc, NumEnums: 1, - NumMessages: 17, + NumMessages: 20, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/spaces/spaces_grpc.pb.go b/proto/spaces/spaces_grpc.pb.go index f080fe31ba0c4d97ff3fa5fecbf608eaf2ccdd6d..a7d50aee15acb36577d0cf7ef56d29e3eceaaaaa 100644 --- a/proto/spaces/spaces_grpc.pb.go +++ b/proto/spaces/spaces_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: spaces/spaces.proto package spaces @@ -16,13 +16,14 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Spaces_Create_FullMethodName = "/content.spaces.Spaces/Create" Spaces_Get_FullMethodName = "/content.spaces.Spaces/Get" Spaces_List_FullMethodName = "/content.spaces.Spaces/List" + Spaces_Find_FullMethodName = "/content.spaces.Spaces/Find" Spaces_Update_FullMethodName = "/content.spaces.Spaces/Update" Spaces_UpdateConfig_FullMethodName = "/content.spaces.Spaces/UpdateConfig" Spaces_Delete_FullMethodName = "/content.spaces.Spaces/Delete" @@ -39,6 +40,7 @@ type SpacesClient interface { Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) + Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) UpdateConfig(ctx context.Context, in *UpdateConfigRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) @@ -70,8 +72,9 @@ func NewSpacesClient(cc grpc.ClientConnInterface) SpacesClient { } func (c *spacesClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Spaces_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -79,8 +82,9 @@ func (c *spacesClient) Create(ctx context.Context, in *CreateRequest, opts ...gr } func (c *spacesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Spaces_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -88,8 +92,19 @@ func (c *spacesClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Cal } func (c *spacesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListResponse) - err := c.cc.Invoke(ctx, Spaces_List_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_List_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *spacesClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(FindResponse) + err := c.cc.Invoke(ctx, Spaces_Find_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -97,8 +112,9 @@ func (c *spacesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.C } func (c *spacesClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Spaces_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -106,8 +122,9 @@ func (c *spacesClient) Update(ctx context.Context, in *UpdateRequest, opts ...gr } func (c *spacesClient) UpdateConfig(ctx context.Context, in *UpdateConfigRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Spaces_UpdateConfig_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_UpdateConfig_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -115,8 +132,9 @@ func (c *spacesClient) UpdateConfig(ctx context.Context, in *UpdateConfigRequest } func (c *spacesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Spaces_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -124,8 +142,9 @@ func (c *spacesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...gr } func (c *spacesClient) Transfer(ctx context.Context, in *TransferRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Spaces_Transfer_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_Transfer_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -133,8 +152,9 @@ func (c *spacesClient) Transfer(ctx context.Context, in *TransferRequest, opts . } func (c *spacesClient) AbortTransfer(ctx context.Context, in *AbortTransferRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Spaces_AbortTransfer_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_AbortTransfer_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -142,8 +162,9 @@ func (c *spacesClient) AbortTransfer(ctx context.Context, in *AbortTransferReque } func (c *spacesClient) ListTransfers(ctx context.Context, in *ListTransfersRequest, opts ...grpc.CallOption) (*ListTransfersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListTransfersResponse) - err := c.cc.Invoke(ctx, Spaces_ListTransfers_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_ListTransfers_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -151,8 +172,9 @@ func (c *spacesClient) ListTransfers(ctx context.Context, in *ListTransfersReque } func (c *spacesClient) Move(ctx context.Context, in *MoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Spaces_Move_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Spaces_Move_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -161,11 +183,12 @@ func (c *spacesClient) Move(ctx context.Context, in *MoveRequest, opts ...grpc.C // SpacesServer is the server API for Spaces service. // All implementations must embed UnimplementedSpacesServer -// for forward compatibility +// for forward compatibility. type SpacesServer interface { Create(context.Context, *CreateRequest) (*CreateResponse, error) Get(context.Context, *GetRequest) (*GetResponse, error) List(context.Context, *ListRequest) (*ListResponse, error) + Find(context.Context, *FindRequest) (*FindResponse, error) Update(context.Context, *UpdateRequest) (*emptypb.Empty, error) UpdateConfig(context.Context, *UpdateConfigRequest) (*emptypb.Empty, error) Delete(context.Context, *DeleteRequest) (*emptypb.Empty, error) @@ -189,9 +212,12 @@ type SpacesServer interface { mustEmbedUnimplementedSpacesServer() } -// UnimplementedSpacesServer must be embedded to have forward compatible implementations. -type UnimplementedSpacesServer struct { -} +// UnimplementedSpacesServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedSpacesServer struct{} func (UnimplementedSpacesServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -202,6 +228,9 @@ func (UnimplementedSpacesServer) Get(context.Context, *GetRequest) (*GetResponse func (UnimplementedSpacesServer) List(context.Context, *ListRequest) (*ListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method List not implemented") } +func (UnimplementedSpacesServer) Find(context.Context, *FindRequest) (*FindResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Find not implemented") +} func (UnimplementedSpacesServer) Update(context.Context, *UpdateRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") } @@ -224,6 +253,7 @@ func (UnimplementedSpacesServer) Move(context.Context, *MoveRequest) (*emptypb.E return nil, status.Errorf(codes.Unimplemented, "method Move not implemented") } func (UnimplementedSpacesServer) mustEmbedUnimplementedSpacesServer() {} +func (UnimplementedSpacesServer) testEmbeddedByValue() {} // UnsafeSpacesServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to SpacesServer will @@ -233,6 +263,13 @@ type UnsafeSpacesServer interface { } func RegisterSpacesServer(s grpc.ServiceRegistrar, srv SpacesServer) { + // If the following call pancis, it indicates UnimplementedSpacesServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Spaces_ServiceDesc, srv) } @@ -290,6 +327,24 @@ func _Spaces_List_Handler(srv interface{}, ctx context.Context, dec func(interfa return interceptor(ctx, in, info, handler) } +func _Spaces_Find_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FindRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SpacesServer).Find(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Spaces_Find_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SpacesServer).Find(ctx, req.(*FindRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Spaces_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(UpdateRequest) if err := dec(in); err != nil { @@ -435,6 +490,10 @@ var Spaces_ServiceDesc = grpc.ServiceDesc{ MethodName: "List", Handler: _Spaces_List_Handler, }, + { + MethodName: "Find", + Handler: _Spaces_Find_Handler, + }, { MethodName: "Update", Handler: _Spaces_Update_Handler, diff --git a/proto/users/users.pb.go b/proto/users/users.pb.go index 18f49f1a3c2e75c911a5f783e9f008da8d9c4c79..23f9b300f1331883728dfb7a5355adba53e49306 100644 --- a/proto/users/users.pb.go +++ b/proto/users/users.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: users/users.proto package users @@ -839,7 +839,7 @@ func file_users_users_proto_rawDescGZIP() []byte { } var file_users_users_proto_msgTypes = make([]protoimpl.MessageInfo, 12) -var file_users_users_proto_goTypes = []interface{}{ +var file_users_users_proto_goTypes = []any{ (*User)(nil), // 0: account.users.User (*Filter)(nil), // 1: account.users.Filter (*CreateRequest)(nil), // 2: account.users.CreateRequest @@ -894,7 +894,7 @@ func file_users_users_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_users_users_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*User); i { case 0: return &v.state @@ -906,7 +906,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Filter); i { case 0: return &v.state @@ -918,7 +918,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -930,7 +930,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -942,7 +942,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*GetRequest); i { case 0: return &v.state @@ -954,7 +954,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state @@ -966,7 +966,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*FindRequest); i { case 0: return &v.state @@ -978,7 +978,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*FindResponse); i { case 0: return &v.state @@ -990,7 +990,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1002,7 +1002,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*DeleteRequest); i { case 0: return &v.state @@ -1014,7 +1014,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*GetByIdentityRequest); i { case 0: return &v.state @@ -1026,7 +1026,7 @@ func file_users_users_proto_init() { return nil } } - file_users_users_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_users_users_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*GetByIdentityResponse); i { case 0: return &v.state diff --git a/proto/users/users_grpc.pb.go b/proto/users/users_grpc.pb.go index 30a2b84431e53679e4b92f0f3db43ffc8d0e190c..20bc9b68454a328d389f4a45d77b4d2a8bb4cade 100644 --- a/proto/users/users_grpc.pb.go +++ b/proto/users/users_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: users/users.proto package users @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Users_Create_FullMethodName = "/account.users.Users/Create" @@ -59,8 +59,9 @@ func NewUsersClient(cc grpc.ClientConnInterface) UsersClient { } func (c *usersClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(CreateResponse) - err := c.cc.Invoke(ctx, Users_Create_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Users_Create_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -68,8 +69,9 @@ func (c *usersClient) Create(ctx context.Context, in *CreateRequest, opts ...grp } func (c *usersClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Users_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Users_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -77,8 +79,9 @@ func (c *usersClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.Call } func (c *usersClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.CallOption) (*FindResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(FindResponse) - err := c.cc.Invoke(ctx, Users_Find_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Users_Find_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -86,8 +89,9 @@ func (c *usersClient) Find(ctx context.Context, in *FindRequest, opts ...grpc.Ca } func (c *usersClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Users_Update_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Users_Update_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -95,8 +99,9 @@ func (c *usersClient) Update(ctx context.Context, in *UpdateRequest, opts ...grp } func (c *usersClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Users_Delete_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Users_Delete_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -104,8 +109,9 @@ func (c *usersClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grp } func (c *usersClient) GetByIdentity(ctx context.Context, in *GetByIdentityRequest, opts ...grpc.CallOption) (*GetByIdentityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetByIdentityResponse) - err := c.cc.Invoke(ctx, Users_GetByIdentity_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Users_GetByIdentity_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -114,7 +120,7 @@ func (c *usersClient) GetByIdentity(ctx context.Context, in *GetByIdentityReques // UsersServer is the server API for Users service. // All implementations must embed UnimplementedUsersServer -// for forward compatibility +// for forward compatibility. type UsersServer interface { // Создание пользователя или регистрация текущего пользователя в системе, если create.id == `current` Create(context.Context, *CreateRequest) (*CreateResponse, error) @@ -135,9 +141,12 @@ type UsersServer interface { mustEmbedUnimplementedUsersServer() } -// UnimplementedUsersServer must be embedded to have forward compatible implementations. -type UnimplementedUsersServer struct { -} +// UnimplementedUsersServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedUsersServer struct{} func (UnimplementedUsersServer) Create(context.Context, *CreateRequest) (*CreateResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Create not implemented") @@ -158,6 +167,7 @@ func (UnimplementedUsersServer) GetByIdentity(context.Context, *GetByIdentityReq return nil, status.Errorf(codes.Unimplemented, "method GetByIdentity not implemented") } func (UnimplementedUsersServer) mustEmbedUnimplementedUsersServer() {} +func (UnimplementedUsersServer) testEmbeddedByValue() {} // UnsafeUsersServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to UsersServer will @@ -167,6 +177,13 @@ type UnsafeUsersServer interface { } func RegisterUsersServer(s grpc.ServiceRegistrar, srv UsersServer) { + // If the following call pancis, it indicates UnimplementedUsersServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Users_ServiceDesc, srv) } diff --git a/proto/versions/account/versions.pb.go b/proto/versions/account/versions.pb.go index 9db5b3d2864ba0de22a950db158d66c3f488a36c..b1c95aba8a1f6a6d62ea2e0ac1102fe145f95178 100644 --- a/proto/versions/account/versions.pb.go +++ b/proto/versions/account/versions.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: versions/account/versions.proto package account @@ -105,7 +105,7 @@ func file_versions_account_versions_proto_rawDescGZIP() []byte { } var file_versions_account_versions_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_versions_account_versions_proto_goTypes = []interface{}{ +var file_versions_account_versions_proto_goTypes = []any{ (*GetResponse)(nil), // 0: account.GetResponse (*common.Version)(nil), // 1: common.Version (*emptypb.Empty)(nil), // 2: google.protobuf.Empty @@ -127,7 +127,7 @@ func file_versions_account_versions_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_versions_account_versions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_versions_account_versions_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state diff --git a/proto/versions/account/versions_grpc.pb.go b/proto/versions/account/versions_grpc.pb.go index 6d3fd60aff0ad0692c3a2ec698607ee4c59b9f97..06fb791413646cdc56dc021103c511d73689d7c8 100644 --- a/proto/versions/account/versions_grpc.pb.go +++ b/proto/versions/account/versions_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: versions/account/versions.proto package account @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Versions_Get_FullMethodName = "/account.Versions/Get" @@ -39,8 +39,9 @@ func NewVersionsClient(cc grpc.ClientConnInterface) VersionsClient { } func (c *versionsClient) Get(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Versions_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Versions_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -49,20 +50,24 @@ func (c *versionsClient) Get(ctx context.Context, in *emptypb.Empty, opts ...grp // VersionsServer is the server API for Versions service. // All implementations must embed UnimplementedVersionsServer -// for forward compatibility +// for forward compatibility. type VersionsServer interface { Get(context.Context, *emptypb.Empty) (*GetResponse, error) mustEmbedUnimplementedVersionsServer() } -// UnimplementedVersionsServer must be embedded to have forward compatible implementations. -type UnimplementedVersionsServer struct { -} +// UnimplementedVersionsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedVersionsServer struct{} func (UnimplementedVersionsServer) Get(context.Context, *emptypb.Empty) (*GetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") } func (UnimplementedVersionsServer) mustEmbedUnimplementedVersionsServer() {} +func (UnimplementedVersionsServer) testEmbeddedByValue() {} // UnsafeVersionsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to VersionsServer will @@ -72,6 +77,13 @@ type UnsafeVersionsServer interface { } func RegisterVersionsServer(s grpc.ServiceRegistrar, srv VersionsServer) { + // If the following call pancis, it indicates UnimplementedVersionsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Versions_ServiceDesc, srv) } diff --git a/proto/versions/content/versions.pb.go b/proto/versions/content/versions.pb.go index c399b1a29d2e793d7918eaa456670d4b2a6d02ce..fd3d05b80b73f7f3195f93753457b20202d74b3b 100644 --- a/proto/versions/content/versions.pb.go +++ b/proto/versions/content/versions.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: versions/content/versions.proto package content @@ -105,7 +105,7 @@ func file_versions_content_versions_proto_rawDescGZIP() []byte { } var file_versions_content_versions_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_versions_content_versions_proto_goTypes = []interface{}{ +var file_versions_content_versions_proto_goTypes = []any{ (*GetResponse)(nil), // 0: content.GetResponse (*common.Version)(nil), // 1: common.Version (*emptypb.Empty)(nil), // 2: google.protobuf.Empty @@ -127,7 +127,7 @@ func file_versions_content_versions_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_versions_content_versions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_versions_content_versions_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*GetResponse); i { case 0: return &v.state diff --git a/proto/versions/content/versions_grpc.pb.go b/proto/versions/content/versions_grpc.pb.go index 25198d3383a04d58c15a85d83673445386e347b2..d2afb289fa36d77a4ec2e95abbe6c10ab7cd41f5 100644 --- a/proto/versions/content/versions_grpc.pb.go +++ b/proto/versions/content/versions_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.24.3 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: versions/content/versions.proto package content @@ -16,8 +16,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( Versions_Get_FullMethodName = "/content.Versions/Get" @@ -39,8 +39,9 @@ func NewVersionsClient(cc grpc.ClientConnInterface) VersionsClient { } func (c *versionsClient) Get(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetResponse) - err := c.cc.Invoke(ctx, Versions_Get_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, Versions_Get_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -49,20 +50,24 @@ func (c *versionsClient) Get(ctx context.Context, in *emptypb.Empty, opts ...grp // VersionsServer is the server API for Versions service. // All implementations must embed UnimplementedVersionsServer -// for forward compatibility +// for forward compatibility. type VersionsServer interface { Get(context.Context, *emptypb.Empty) (*GetResponse, error) mustEmbedUnimplementedVersionsServer() } -// UnimplementedVersionsServer must be embedded to have forward compatible implementations. -type UnimplementedVersionsServer struct { -} +// UnimplementedVersionsServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedVersionsServer struct{} func (UnimplementedVersionsServer) Get(context.Context, *emptypb.Empty) (*GetResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") } func (UnimplementedVersionsServer) mustEmbedUnimplementedVersionsServer() {} +func (UnimplementedVersionsServer) testEmbeddedByValue() {} // UnsafeVersionsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to VersionsServer will @@ -72,6 +77,13 @@ type UnsafeVersionsServer interface { } func RegisterVersionsServer(s grpc.ServiceRegistrar, srv VersionsServer) { + // If the following call pancis, it indicates UnimplementedVersionsServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&Versions_ServiceDesc, srv) } diff --git a/zap/field.go b/zap/field.go index 4e5ec75e7f5fffbd6f1af83fd44c6a434d3190c3..d687bacc49c8e9599611e88590093c5756771896 100644 --- a/zap/field.go +++ b/zap/field.go @@ -2,7 +2,6 @@ package zap import ( "context" - "git.perx.ru/perxis/perxis-go/id" _ "git.perx.ru/perxis/perxis-go/id/system" // регистрируем обработчики для системных объектов "git.perx.ru/perxis/perxis-go/pkg/auth" @@ -47,22 +46,42 @@ func Object(v any) zap.Field { return zap.Reflect("object", oid) } -// Caller возвращает поле и устанавливает передаваемый аргумент в качестве "вызывающего" в формате ObjectId. -// Поддерживает типы в формате ObjectId: id.Descriptor, string, map[string]any, системные объекты. -func Caller(v any) zap.Field { - oid, _ := id.NewObjectId(v) - return zap.Reflect("caller", oid) +type callerConfig struct { + object any + spaceID string } -// CallerFromContext извлекает auth.Principal из контекста и устанавливает его в качестве "вызывающего" в формате Object. -// Вторым параметром передается идентификатор пространства, который требуется, если вызывающий является auth.SpaceAccessor. -// Если вызывающий не связан с пространством, следует передать пустую строку. -func CallerFromContext(ctx context.Context, spaceID string) zap.Field { - principal := auth.GetPrincipal(ctx) - if accessor, ok := principal.(auth.SpaceAccessor); ok && spaceID != "" { - principal = accessor.Space(spaceID) +type CallerOption func(c *callerConfig) + +func WithObject(object any) CallerOption { + return func(c *callerConfig) { + c.object = object } - return Caller(principal) +} + +func WithSpace(spaceID string) CallerOption { + return func(c *callerConfig) { + c.spaceID = spaceID + } +} + +// Caller возвращает поле и устанавливает в зависимости от переданных опций "вызывающего" в формате ObjectId. +func Caller(ctx context.Context, options ...CallerOption) zap.Field { + c := new(callerConfig) + for _, o := range options { + o(c) + } + var oid *id.ObjectId + if c.object != nil { + oid, _ = id.NewObjectId(c.object) + } else if ctx != nil { + principal := auth.GetPrincipal(ctx) + if accessor, ok := principal.(auth.SpaceAccessor); ok && c.spaceID != "" { + principal = accessor.Space(c.spaceID) + } + oid, _ = id.NewObjectId(principal) + } + return zap.Reflect("caller", oid) } func Attr(attr any) zap.Field { diff --git a/zap/field_test.go b/zap/field_test.go index 1e050bdcdc95a031cc00980309b650eac98c283b..46c4ee50722934e7d9ddd5ea759d01f3836706f8 100644 --- a/zap/field_test.go +++ b/zap/field_test.go @@ -132,43 +132,19 @@ func TestCaller(t *testing.T) { oid := id.MustObjectId(user) userId := id.NewUserId(user.ID) - - tests := []struct { - name string - field zap.Field - want zap.Field - }{ - {name: "system object", field: Caller(user), want: zap.Reflect("caller", oid)}, - {name: "object id", field: Caller(userId), want: zap.Reflect("caller", oid)}, - {name: "string", field: Caller(oid.String()), want: zap.Reflect("caller", oid)}, - {name: "invalid", field: Caller(nil), want: zap.Reflect("caller", (*id.ObjectId)(nil))}, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - wantObjectId, ok1 := tc.want.Interface.(*id.ObjectId) - fieldObjectId, ok2 := tc.field.Interface.(*id.ObjectId) - - if ok1 && ok2 && wantObjectId != nil && fieldObjectId != nil { - assert.Equal(t, wantObjectId.String(), fieldObjectId.String()) - } else { - assert.Equal(t, tc.want.Interface, tc.field.Interface) - } - }) - } -} - -func TestCallerFromContext(t *testing.T) { ctx := auth.WithSystem(context.Background()) - oid := id.MustObjectId(auth.GetPrincipal(ctx)) tests := []struct { name string field zap.Field want zap.Field }{ - {name: "ok", field: CallerFromContext(ctx, ""), want: zap.Reflect("caller", oid)}, - {name: "invalid", field: CallerFromContext(context.TODO(), ""), want: zap.Reflect("caller", (*id.ObjectId)(nil))}, + {name: "system object", field: Caller(context.TODO(), WithObject(user)), want: zap.Reflect("caller", oid)}, + {name: "object id", field: Caller(context.TODO(), WithObject(userId)), want: zap.Reflect("caller", oid)}, + {name: "string", field: Caller(context.TODO(), WithObject(oid.String())), want: zap.Reflect("caller", oid)}, + {name: "invalid", field: Caller(context.TODO()), want: zap.Reflect("caller", (*id.ObjectId)(nil))}, + {name: "context", field: Caller(ctx), want: zap.Reflect("caller", id.MustObjectId(auth.GetPrincipal(ctx)))}, + {name: "invalid context", field: Caller(context.TODO()), want: zap.Reflect("caller", (*id.ObjectId)(nil))}, } for _, tc := range tests {