From 147815cb706bffc2337a1f31bbed5492c130a05a Mon Sep 17 00:00:00 2001
From: Pavel Antonov <antonov@perx.ru>
Date: Mon, 18 Sep 2023 16:04:14 +0400
Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?=
 =?UTF-8?q?=D0=BD=D1=8B=20longtime=20operation.=20=D0=94=D0=BE=D0=B1=D0=B0?=
 =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0?=
 =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=B0?=
 =?UTF-8?q?=20OperationService=20=D0=B8=20ExtensionService?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 proto/common/operation.proto             |  42 ++++++
 proto/common/operation_service.proto     |  24 ++++
 proto/common/validation.proto            |  28 ++++
 proto/extensions/extension.proto         | 174 +++++------------------
 proto/extensions/extension_service.proto | 118 +++++++++++++++
 5 files changed, 245 insertions(+), 141 deletions(-)
 create mode 100644 proto/common/operation.proto
 create mode 100644 proto/common/operation_service.proto
 create mode 100644 proto/common/validation.proto
 create mode 100644 proto/extensions/extension_service.proto

diff --git a/proto/common/operation.proto b/proto/common/operation.proto
new file mode 100644
index 0000000..d77171a
--- /dev/null
+++ b/proto/common/operation.proto
@@ -0,0 +1,42 @@
+syntax = "proto3";
+
+package common;
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/any.proto";
+
+option go_package = "git.perx.ru/perxis/perxis-go/proto/common;common";
+
+
+// Операция
+message Operation {
+  // ID операции
+  string id = 1;
+
+  // Описание операции
+  string description = 2;
+
+  // Время создания операции
+  google.protobuf.Timestamp created_at = 3;
+
+  // Создатель операции
+  string created_by = 4;
+
+  // Время последнего изменения операции
+  google.protobuf.Timestamp modified_at = 6;
+
+  // Операция завершена
+  bool done = 7;
+
+  // Метаданные операции
+  google.protobuf.Any metadata = 8;
+
+  // Результат выполнения операции
+  oneof result {
+    // Результат выполнения операции в случае успеха
+    google.protobuf.Any response = 9;
+
+    // Результат выполнения операции в случае ошибки
+    string error = 10;
+  }
+}
diff --git a/proto/common/operation_service.proto b/proto/common/operation_service.proto
new file mode 100644
index 0000000..ca53cd8
--- /dev/null
+++ b/proto/common/operation_service.proto
@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+option go_package = "git.perx.ru/perxis/perxis-go/proto/common;common";
+
+package common;
+
+import "common/operation.proto";
+import "common/validation.proto";
+
+service OperationService {
+  // Возвращает статус операции и ее результат если она завершена
+  rpc Get (GetOperationRequest) returns (Operation) {}
+
+  // Отменяет выполнение операции если это поддерживается сервисом
+  rpc Cancel (CancelOperationRequest) returns (Operation) {}
+}
+
+message GetOperationRequest {
+  string operation_id = 1 [(required) = true];
+}
+
+message CancelOperationRequest {
+  string operation_id = 1 [(required) = true];
+}
\ No newline at end of file
diff --git a/proto/common/validation.proto b/proto/common/validation.proto
new file mode 100644
index 0000000..f4f5c97
--- /dev/null
+++ b/proto/common/validation.proto
@@ -0,0 +1,28 @@
+syntax = "proto3";
+
+package common;
+
+option go_package = "git.perx.ru/perxis/perxis-go/proto/common;common";
+
+import "google/protobuf/descriptor.proto";
+
+extend google.protobuf.OneofOptions {
+  bool exactly_one = 101400;
+}
+
+extend google.protobuf.FieldOptions {
+  bool required = 101501;
+  string pattern = 101502;
+  string value = 101503;
+  string size = 101504;
+  string length = 101505;
+  bool unique = 101506;
+  MapKeySpec map_key = 101510;
+  string bytes = 101511;
+}
+
+message MapKeySpec {
+  string value = 1;
+  string pattern = 2;
+  string length = 3;
+}
\ No newline at end of file
diff --git a/proto/extensions/extension.proto b/proto/extensions/extension.proto
index 59a4325..98840b4 100644
--- a/proto/extensions/extension.proto
+++ b/proto/extensions/extension.proto
@@ -16,60 +16,12 @@ package extensions;
 
 import "references/references.proto";
 
-// Extension - API расширения
-service Extension {
-
-  // Для установки расширения выполняется запрос к сервису с указанием расширений которые должны быть установлены. Если
-  // расширение уже установлено процесс возвращает ошибку.
-  rpc Install(InstallRequest) returns (InstallResponse) {}
-
-  // Можно запросить проверку статуса установки для расширения. При этом расширение проверяет наличие необходимых данных в
-  // пространстве или наличие новой версии расширения и сообщает об этом. Никаких действий с данными пространства не
-  // производится.
-  rpc Check(CheckRequest) returns (CheckResponse) {}
-
-  // Сервис выполняет необходимые действия с данными и миграции для соответствия нужной версии расширения.
-  // Если расширение не установлено процесс обновления возвращает ошибку.
-  rpc Update(UpdateRequest) returns (UpdateResponse) {}
-
-  // Удаление расширения из пространства.
-  rpc Uninstall(UninstallRequest) returns (UninstallResponse) {} // Удаление расширений
-
-
-  // Пользовательские Действия (Actions)
-  //
-  // Пользовательские действия позволяют расширить функционал пользовательского интерфейса путем
-  // добавления в интерфейс элементов взаимодействуя с которыми пользователь может вызывать реакцию на
-  // сервере или переход в интерфейсе.
-  //
-  // Пользовательские действия добавляются при установке расширений в системную коллекции `System/Actions`.
-  // Коллекция создается автоматически менеджером расширений. При установке так же отображается меню `Действия`
-  // доступное для всех пользователей.
-  //
-  // Примеры пользовательских действий:
-  // - "Собрать сайт" - добавляется Perxis.Web для сборки сайта, доступна пользователю через меню,
-  //   параметры space_id, env_id. При вызове выполняется запрос на сервер ProcessAction.
-  // - "Посмотреть задачи" - добавляется Tasks для перехода на коллекцию задач. Отображается в меню,
-  //   параметры space_id, env_id.
-  //
-  // Приложения так же могут использовать действия для вызова обработки в других приложениях при
-  // необходимости.
-  rpc Action(ActionRequest) returns(ActionResponse) {} // Выполнить указанное действие
-}
-
-message InstallRequest {
-  repeated string extensions = 10000; // Список расширений для установки
-  string space_id = 10010; // Пространство для установки расширений
-  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
-  bool force = 10100; // Игнорировать и автоматически исправлять ошибки установки
-}
-
-message ExtensionRequestResult {
+message Extension {
   enum State {
-    OK = 0; // Запрос завершен
-    ERROR = 1; // Возникла ошибка
-    PENDING = 2; // Запрос ожидает выполнения
-    IN_PROGRESS = 3; // Запрос выполняется
+    OK = 0; // Текущее состояние расширения без ошибок
+    ERROR = 1; // Возникла ошибка при выполнении запроса
+    PENDING = 2; // Ожидает обработки (в очереди)
+    IN_PROGRESS = 3; // Запрос уже выполняется
     PARAMETERS_REQUIRED= 4; // Требуются дополнительные данные для выполнения запроса
   }
 
@@ -77,69 +29,12 @@ message ExtensionRequestResult {
   string extension = 10100; // Имя расширения
   string msg = 10200; // Сообщение
   string error = 10300; // Ошибка (state == ERROR)
-  bool update_available = 10400; // Доступно обновление
-}
-
-message InstallResponse {
-  repeated ExtensionRequestResult results = 10000; // Список состояний расширений после установки
-}
-
-message UninstallRequest {
-  repeated string extensions = 10000; // Список расширений для удаления
-  string space_id = 10010; // Пространство для удаления расширений
-  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
-  bool remove = 10100; // Удалить все коллекции и данные
-  bool force = 10200; // Удалять расширения вне зависимости от возможных ошибок, без учета зависимостей
-}
-
-message UninstallResponse {
-  repeated ExtensionRequestResult results = 10000; // Список состояний расширений после удаления
-}
-
-message UpdateRequest {
-  repeated string extensions = 10000; // Список расширений для удаления
-  string space_id = 10010; // Пространство для удаления расширений
-  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
-  bool force = 10100; // Выполнять обновление и автоматически исправлять ошибки
-}
-
-message UpdateResponse {
-  repeated ExtensionRequestResult results = 10000; // Список состояний расширений после удаления
+  bool installed = 10400; // Расширение установлено
+  bool update_available = 10500; // Доступно обновление
+  string installed_version = 10510; // Установленная версия расширения
+  string available_version = 10520; // Доступная версия расширения
 }
 
-message CheckRequest {
-  repeated string extensions = 10000; // Список расширений для удаления
-  string space_id = 10010; // Пространство для удаления расширений
-  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
-}
-
-message CheckResponse {
-  repeated ExtensionRequestResult results = 10000; // Список состояний расширений
-}
-
-// ActionRequest - запрос на выполнение действия к расширению (или менеджеру расширений)
-message ActionRequest {
-  string extension = 1000;
-  string action = 10100;
-  string space_id = 10500;
-  string env_id = 10510;
-  string collection_id = 10520;
-  string item_id = 10530;
-  repeated string item_ids = 10540;
-
-  // Поля к которым применимо действие. В случае если действие выполняется из списка записей, содержит перечень
-  // полей которые пользователь выбрал для отображения в интерфейсе.
-  repeated string fields = 10550;
-
-  map<string,string> metadata = 11000;
-
-  // Ссылки на записи используемые для выполнения действия (назначение ссылок зависит от действия и расширения)
-  repeated content.references.Reference refs = 11010;
-
-  // Ссылка на документ с параметрами выполнения Action.
-  // Чтобы при выполнении действия открывалась форма параметров, необходимо указать `Action.params_collection`
-  content.references.Reference params = 11020;
-}
 
 // Target - определяет как открывать результат выполнения действия в пользовательском интерфейсе
 enum Target {
@@ -153,33 +48,6 @@ enum Target {
   NONE = 100; // Не отображать результат
 }
 
-message ActionResponse {
-  enum State {
-    DONE = 0; // Запрос завершен
-    ERROR = 1; // Возникла ошибка
-    PENDING = 2; // Запрос ожидает выполнения
-    IN_PROGRESS = 3; // Запрос выполняется
-    PARAMETERS_REQUIRED = 4; // Требуются дополнительные данные для выполнения запроса
-  }
-
-  enum Format {
-    PLAIN = 0;
-    HTML = 1;
-    MARKDOWN = 2;
-  }
-
-  State state = 10000;  // Состояние расширение
-  Target target = 10010; // Как открывать результат выполнения действия в пользовательском интерфейсе (переопределяет значение в Action)
-	Format format = 10050; // Формат полей msg  и error
-  string msg = 10100; // Сообщение о выполнении действия
-  string title = 10110; // Текст для отображения в интерфейсе
-  string image = 10140; // Изображение для отображения в интерфейсе (шапке окна)
-  string error = 10200; // Сообщение в случае ошибки (дополнительно к msg)
-  repeated Action next = 10300; // Следующие возможные действия. Интерфейс отображает как варианты дальнейших действий пользователя
-  map<string,string>metadata = 10400; // Метаданные запроса
-  repeated content.references.Reference refs = 10320; // Ссылки на записи (назначение ссылок зависит от действия и расширения)
-}
-
 
 /**
 Action описывает как коллекцию в системе с предуставновленными действиями, так и возможные дальнейшие действия после
@@ -287,4 +155,28 @@ message Action {
   // Параметр указывающий что действие требует подтверждения пользователя
   // Перед выполнением действия пользователю отображается информация о действии и кнопки подтверждения/отмены
   bool confirm = 10530;
+}
+
+// ActionRequest - запрос на выполнение действия к расширению (или менеджеру расширений)
+message ActionRequest {
+  string extension = 1000;
+  string action = 10100;
+  string space_id = 10500;
+  string env_id = 10510;
+  string collection_id = 10520;
+  string item_id = 10530;
+  repeated string item_ids = 10540;
+
+  // Поля к которым применимо действие. В случае если действие выполняется из списка записей, содержит перечень
+  // полей которые пользователь выбрал для отображения в интерфейсе.
+  repeated string fields = 10550;
+
+  map<string,string> metadata = 11000;
+
+  // Ссылки на записи используемые для выполнения действия (назначение ссылок зависит от действия и расширения)
+  repeated content.references.Reference refs = 11010;
+
+  // Ссылка на документ с параметрами выполнения Action.
+  // Чтобы при выполнении действия открывалась форма параметров, необходимо указать `Action.params_collection`
+  content.references.Reference params = 11020;
 }
\ No newline at end of file
diff --git a/proto/extensions/extension_service.proto b/proto/extensions/extension_service.proto
new file mode 100644
index 0000000..9d2893f
--- /dev/null
+++ b/proto/extensions/extension_service.proto
@@ -0,0 +1,118 @@
+/**
+# Расширения (Extensions)
+
+Расширения представляют собой отдельные сервисы предоставляющие дополнительные возможности для пользователей. Сервис
+может предоставлять несколько расширений одновременно.
+
+Для координации взаимодействия используется сервис менеджер расширений (Extension Manager). Для предоставления своих функций в систему сервис должен
+зарегистрироваться на контроллере.
+
+*/
+syntax = "proto3";
+
+option go_package = "git.perx.ru/perxis/perxis-go/proto/extensions;extensions";
+
+package extensions;
+
+import "references/references.proto";
+import "common/operation.proto";
+import "extensions/extension.proto";
+
+// ExtensionService - API расширения
+// Сервис должен реализовывать методы `common.OperationService` для работы операциями.
+service ExtensionService {
+
+  // Install выполняет установку указанных расширений. Если
+  // расширение уже установлены выполняет процесс переустановки. Возвращает longtime операцию
+  rpc Install(InstallRequest) returns (common.Operation) {}
+
+  // Uninstall выполняет удаление указанных расширений.
+  rpc Uninstall(UninstallRequest) returns (common.Operation) {} // Удаление расширений
+
+  // Check выполняет проверку установки для расширения. При этом расширение проверяет наличие необходимых данных в
+  // пространстве или наличие новой версии расширения и сообщает об этом. Никаких действий с данными пространства не
+  // производится.
+  rpc Check(CheckRequest) returns (common.Operation) {}
+
+
+  // Пользовательские Действия (Actions)
+  //
+  // Пользовательские действия позволяют расширить функционал пользовательского интерфейса путем
+  // добавления в интерфейс элементов взаимодействуя с которыми пользователь может вызывать реакцию на
+  // сервере или переход в интерфейсе.
+  //
+  // Пользовательские действия добавляются при установке расширений в системную коллекции `System/Actions`.
+  // Коллекция создается автоматически менеджером расширений. При установке так же отображается меню `Действия`
+  // доступное для всех пользователей.
+  //
+  // Примеры пользовательских действий:
+  // - "Собрать сайт" - добавляется Perxis.Web для сборки сайта, доступна пользователю через меню,
+  //   параметры space_id, env_id. При вызове выполняется запрос на сервер ProcessAction.
+  // - "Посмотреть задачи" - добавляется Tasks для перехода на коллекцию задач. Отображается в меню,
+  //   параметры space_id, env_id.
+  //
+  // Приложения так же могут использовать действия для вызова обработки в других приложениях при
+  // необходимости.
+  rpc Action(ActionRequest) returns(ActionResponse) {} // Выполнить указанное действие
+}
+
+
+// InstallRequest - запрос на установку расширений
+message InstallRequest {
+  repeated string extensions = 10000; // Список расширений для установки
+  string space_id = 10010; // Пространство для установки расширений
+  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
+  bool force = 10100; // Устанавливать расширения вне зависимости от возможных ошибок
+  bool update = 10200; // Установить обновления расширений
+}
+
+// ExtensionList - возвращает список состояний расширений в результате выполнения операции `common.Operation`
+// (СЃРј. `common.OperationService`)
+// В методах Install, Uninstall, Check возвращается список состояний расширений в результате выполнения операции
+message ExtensionList {
+  repeated Extension results = 10000; // Список состояний расширений
+}
+
+// UninstallRequest - запрос на удаление расширений
+message UninstallRequest {
+  repeated string extensions = 10000; // Список расширений для удаления
+  string space_id = 10010; // Пространство для удаления расширений
+  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
+  bool remove = 10100; // Удалить изменения сделанные расширением в пространстве, если возможно
+  bool force = 10200; // Удалять расширения вне зависимости от возможных ошибок, без учета зависимостей
+}
+
+
+// CheckRequest - запрос на проверку статуса установки расширений
+message CheckRequest {
+  repeated string extensions = 10000; // Список расширений для удаления
+  string space_id = 10010; // Пространство для удаления расширений
+  string env_id = 10020; // Идентификатор окружения для установки (по умолчанию master)
+}
+
+message ActionResponse {
+  enum State {
+    DONE = 0; // Запрос завершен
+    ERROR = 1; // Возникла ошибка
+    PENDING = 2; // Запрос ожидает выполнения
+    IN_PROGRESS = 3; // Запрос выполняется
+    PARAMETERS_REQUIRED = 4; // Требуются дополнительные данные для выполнения запроса
+  }
+
+  enum Format {
+    PLAIN = 0;
+    HTML = 1;
+    MARKDOWN = 2;
+  }
+
+  State state = 10000;  // Состояние расширение
+  Target target = 10010; // Как открывать результат выполнения действия в пользовательском интерфейсе (переопределяет значение в Action)
+  Format format = 10050; // Формат полей msg  и error
+  string msg = 10100; // Сообщение о выполнении действия
+  string title = 10110; // Текст для отображения в интерфейсе
+  string image = 10140; // Изображение для отображения в интерфейсе (шапке окна)
+  string error = 10200; // Сообщение в случае ошибки (дополнительно к msg)
+  repeated Action next = 10300; // Следующие возможные действия. Интерфейс отображает как варианты дальнейших действий пользователя
+  map<string,string>metadata = 10400; // Метаданные запроса
+  repeated content.references.Reference refs = 10320; // Ссылки на записи (назначение ссылок зависит от действия и расширения)
+}
-- 
GitLab