Przeglądaj źródła

Merge branch 'iapt-platform:agile' into agile

visuddhinanda 3 lat temu
rodzic
commit
aef06f8bde

+ 11 - 8
dashboard/package.json

@@ -4,16 +4,17 @@
   "private": true,
   "dependencies": {
     "@ant-design/charts": "^1.4.2",
-    "@ant-design/pro-components": "^2.3.29",
+    "@ant-design/pro-components": "^2.3.32",
     "@fortawesome/fontawesome-free": "^6.2.0",
     "@reduxjs/toolkit": "^1.9.0",
     "@testing-library/jest-dom": "^5.14.1",
     "@testing-library/react": "^13.0.0",
     "@testing-library/user-event": "^13.2.1",
+    "@types/diff": "^5.0.2",
     "@types/google-protobuf": "^3.15.6",
     "@types/jest": "^27.0.1",
     "@types/js-cookie": "^3.0.2",
-    "@types/lodash": "^4.14.188",
+    "@types/lodash": "^4.14.189",
     "@types/marked": "^4.0.7",
     "@types/node": "^16.7.13",
     "@types/react": "^18.0.0",
@@ -22,11 +23,12 @@
     "@types/react-copy-to-clipboard": "^5.0.4",
     "@types/react-dom": "^18.0.0",
     "@types/react-pdf": "^5.7.4",
-    "@uiw/react-md-editor": "^3.19.5",
-    "antd": "^4.24.1",
+    "@uiw/react-md-editor": "^3.19.7",
+    "antd": "^4.24.2",
     "dayjs": "^1.11.6",
+    "diff": "^5.1.0",
     "dinero.js": "^2.0.0-alpha.9",
-    "emoji-mart": "^5.2.2",
+    "emoji-mart": "^5.3.2",
     "famfamfam-flags": "^1.0.0",
     "famfamfam-mini": "^1.0.0",
     "famfamfam-silk": "^1.0.0",
@@ -38,22 +40,23 @@
     "jwt-decode": "^3.1.2",
     "lodash": "^4.17.21",
     "marked": "^4.2.2",
+    "mermaid": "^9.2.2",
     "qrcode.react": "^3.1.0",
     "react": "^18.2.0",
-    "react-big-calendar": "^1.5.0",
+    "react-big-calendar": "^1.5.2",
     "react-color": "^2.19.3",
     "react-copy-to-clipboard": "^5.1.0",
     "react-dom": "^18.2.0",
     "react-draggable": "^4.4.5",
     "react-dropzone": "^14.2.3",
     "react-highlight-words": "^0.18.0",
-    "react-hook-form": "^7.39.1",
+    "react-hook-form": "^7.39.4",
     "react-image-crop": "^10.0.8",
     "react-intl": "^6.2.1",
     "react-json-view": "^1.21.3",
     "react-markdown": "^8.0.3",
     "react-number-format": "^5.1.1",
-    "react-pdf": "^5.7.2",
+    "react-pdf": "^6.0.3",
     "react-player": "^2.11.0",
     "react-quill": "^2.0.0",
     "react-redux": "^8.0.5",

+ 2 - 0
dashboard/src/App.tsx

@@ -3,6 +3,7 @@ import { ConfigProvider } from "antd";
 import { IntlProvider } from "react-intl";
 import { Provider } from "react-redux";
 import { pdfjs } from "react-pdf";
+import mermaid from "mermaid";
 
 import Router from "./Router";
 import store from "./store";
@@ -16,6 +17,7 @@ import onLoad from "./load";
 import "./App.css";
 
 pdfjs.GlobalWorkerOptions.workerSrc = `${API_HOST}/assets/pdf.worker.min.js`;
+mermaid.initialize({ startOnLoad: true });
 
 onLoad();
 const lang = getLocale();

+ 46 - 18
dashboard/src/pages/nut/index.tsx

@@ -14,11 +14,25 @@ interface IRandomPanel {
   v2: string;
 }
 
+interface IMermaidProps {
+  value: string;
+}
+
+const Mermaid = ({ value }: IMermaidProps) => {
+  return <pre className="mermaid">{value}</pre>;
+};
+
 const Widget = () => {
   const [rdp, setRdp] = useState<IRandomPanel>({
     v1: "",
     v2: "",
   });
+  var aaa: any = {};
+  aaa["bbb"] = "hi";
+  aaa[123] = 321;
+  aaa.hi = "hello";
+  console.log(aaa);
+
   return (
     <div>
       <HeadBar />
@@ -30,25 +44,39 @@ const Widget = () => {
       <div>Home Page</div>
       <InnerDrawer />
       <div>
+        <h1>Mermaid</h1>
+        <div>
+          <Mermaid
+            value={`graph TD 
+        A[Client] --> B[Load Balancer] 
+        B --> C[Server01] 
+        B --> D[Server02]`}
+          />
+        </div>
         <h1>random</h1>
-        <Space style={{ color: "red" }}>{rdp.v1}</Space>
-        &nbsp;
-        <Space style={{ color: "green" }}>{rdp.v2}</Space>
-        &nbsp;
-        <Button
-          onClick={() => {
-            setRdp({
-              v1: Array.from(Array(20), () =>
-                Math.floor(Math.random() * 36).toString(36)
-              ).join(""),
-              v2: lodash
-                .times(20, () => lodash.random(35).toString(36))
-                .join(""),
-            });
-          }}
-        >
-          Generate
-        </Button>
+        <div>
+          &nbsp;
+          <Space style={{ color: "blue" }}>{lodash.uniqueId("hi-")}</Space>
+          &nbsp;
+          <Space style={{ color: "red" }}>{rdp.v1}</Space>
+          &nbsp;
+          <Space style={{ color: "green" }}>{rdp.v2}</Space>
+          &nbsp;
+          <Button
+            onClick={() => {
+              setRdp({
+                v1: Array.from(Array(20), () =>
+                  Math.floor(Math.random() * 36).toString(36)
+                ).join(""),
+                v2: lodash
+                  .times(20, () => lodash.random(35).toString(36))
+                  .join(""),
+              });
+            }}
+          >
+            Generate
+          </Button>
+        </div>
       </div>
       <br />
       <div>

+ 14 - 2
docker/jammy/Dockerfile

@@ -20,7 +20,7 @@ RUN apt update
 RUN apt -y upgrade
 
 RUN apt -y install zsh git locales locales-all rsync openssh-client sshpass \
-    vim tzdata pwgen zip unzip tree tmux dialog \
+    vim tzdata pwgen zip unzip tree tmux dialog asciidoc doxygen \
     net-tools dnsutils net-tools iputils-arping iputils-ping telnet \
     imagemagick ffmpeg fonts-dejavu-extra texlive-full \
     build-essential cmake pkg-config libtool automake autoconf autoconf-archive binutils cpio mold \
@@ -87,6 +87,7 @@ RUN echo 'export PATH=$HOME/.local/bin:$PATH' >> $HOME/.zshrc
 RUN git config --global core.quotepath false
 RUN git config --global http.version HTTP/1.1
 RUN git config --global pull.rebase false
+RUN git config --global url."https://".insteadOf git://
 RUN echo 'set-option -g history-limit 102400' > $HOME/.tmux.conf
 RUN echo 'set-option -g default-shell "/bin/zsh"' >> $HOME/.tmux.conf
 
@@ -109,6 +110,17 @@ RUN cd $HOME/downloads \
     && php composer \
     && mv composer.phar $HOME/.local/bin/composer
 
+# https://github.com/rui314/mold
+# RUN git clone -b v1.6.0 https://github.com/rui314/mold.git $HOME/downloads/mold
+# RUN apt install -y libssl-dev libxxhash-dev zlib1g-dev \
+#     file bsdmainutils
+# RUN zsh -c "source $HOME/.zshrc \
+#     && mkdir $HOME/build/mold \
+#     && cd $HOME/build/mold \
+#     && cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ $HOME/downloads/mold \
+#     && make -j \
+#     && make install "
+
 # https://github.com/richfelker/musl-cross-make
 RUN git clone https://github.com/richfelker/musl-cross-make.git $HOME/build/musl-cross-make
 RUN cd $HOME/build/musl-cross-make \
@@ -127,7 +139,7 @@ RUN cd $HOME/build/musl-cross-make \
     && make \
     && make install
 
-ENV BAZEL_VERSION "v1.14.0"
+ENV BAZEL_VERSION "v1.15.0"
 RUN wget -q -O $HOME/.local/bin/bazel \
     https://github.com/bazelbuild/bazelisk/releases/download/${BAZEL_VERSION}/bazelisk-linux-amd64
 RUN chmod +x $HOME/.local/bin/bazel

+ 316 - 236
protocols/nut.proto

@@ -7,40 +7,23 @@ import "google/protobuf/empty.proto";
 import "google/protobuf/timestamp.proto";
 import "google/protobuf/duration.proto";
 
-// ----------------------------------------------------------------------------
-
-message IdRequest { int32 id = 1; }
-
-message Resource {
-  string type = 1;
-  optional int32 id = 2;
-}
-
-message Permission {
-  oneof subject {
-    string user = 1;
-    string role = 2;
-  }
-  string operation = 11;
-  Resource resource = 12;
+message IdRequest {
+  int32 id = 1;
 }
 
-// ----------------------------------------------------------------------------
 message Pager {
-  int32 page = 1;
-  int32 size = 2;
+  int64 page = 1;
+  int64 size = 2;
 }
 
 message Pagination {
-  int32 page = 1;
-  int32 size = 2;
-  int32 total = 3;
+  int64 page = 1;
+  int64 size = 2;
+  int64 total = 3;
   bool has_next = 11;
   bool has_previous = 12;
 }
 
-// ----------------------------------------------------------------------------
-
 message MediaContent {
   enum Editor {
     TEXTAREA = 0;
@@ -48,7 +31,7 @@ message MediaContent {
   }
 
   enum Status {
-    Publish = 0;
+    Published = 0;
     Draft = 1;
     Pending = 2;
     Private = 3;
@@ -58,105 +41,93 @@ message MediaContent {
   Editor editor = 1;
   string body = 2;
   Status status = 3;
+
+  optional google.protobuf.Timestamp published_at = 11;
 }
 
-// ----------------------------------------------------------------------------
+message UserDetail {
+  int32 id = 1;
+  string uid = 2;
+  string nickname = 3;
+  string real_name = 4;
+  string email = 5;
+}
 
-message SmsTask {
-  string from = 1;
-  repeated string to = 2;
-  string body = 3;
+message Resource {
+  string type = 1;
+  optional int32 id = 2;
 }
 
-message EmailTask {
-  enum ContentType {
-    TEXT_PLAIN = 0;
-    TEXT_HTML = 1;
-  }
-  message Attachment {
-    string name = 1;
-    ContentType content_type = 2;
-    bytes payload = 11;
+message Permission {
+  oneof subject {
+    int32 user = 1;
+    int32 role = 2;
   }
-  string subject = 1;
-  string body = 2;
-  ContentType content_type = 3;
-
-  string to = 11;
-  repeated string cc = 12;
-  repeated string bcc = 13;
-  repeated Attachment attachments = 21;
+  string operation = 11;
+  Resource resource = 12;
 }
-// ----------------------------------------------------------------------------
-
-message UserDetail {
-  string nick_name = 1;
-  string real_name = 2;
 
-  string home = 11;
-}
+// ----------------------------------------------------------------------------
 
 service User {
   rpc SignIn(UserSignInRequest) returns (UserSignInResponse) {}
   rpc SignUp(UserSignUpRequest) returns (google.protobuf.Empty) {}
-  rpc ConfirmByEmail(UserEmailRequest) returns (google.protobuf.Empty) {}
+  rpc ConfirmByEmail(UserQueryRequest) returns (google.protobuf.Empty) {}
   rpc ConfirmByToken(UserTokenRequest) returns (google.protobuf.Empty) {}
-  rpc UnlockByEmail(UserEmailRequest) returns (google.protobuf.Empty) {}
+  rpc UnlockByEmail(UserQueryRequest) returns (google.protobuf.Empty) {}
   rpc UnlockByToken(UserTokenRequest) returns (google.protobuf.Empty) {}
-  rpc ForgotPassword(UserEmailRequest) returns (google.protobuf.Empty) {}
+  rpc ForgotPassword(UserQueryRequest) returns (google.protobuf.Empty) {}
   rpc ResetPassword(UserResetPasswordRequest) returns (google.protobuf.Empty) {}
 
   rpc Refresh(google.protobuf.Duration) returns (UserSignInResponse) {}
-  rpc Logs(UserLogsRequest) returns (UserLogsResponse) {}
+  rpc Logs(Pager) returns (UserLogsResponse) {}
   rpc SetProfile(UserSetProfileRequest) returns (google.protobuf.Empty) {}
   rpc ChangePassword(UserChangePasswordRequest)
       returns (google.protobuf.Empty) {}
   rpc SignOut(google.protobuf.Empty) returns (google.protobuf.Empty) {}
 
   rpc Index(Pager) returns (UserIndexResponse) {}
-  rpc Show(UserQueryRequest) returns (UserIndexResponse.Item) {}
-  rpc Disable(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc Enable(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc Lock(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc Unlock(UserQueryRequest) returns (google.protobuf.Empty) {}
-  rpc Confirm(UserQueryRequest) returns (google.protobuf.Empty) {}
+  rpc Show(IdRequest) returns (UserIndexResponse.Item) {}
+  rpc Disable(IdRequest) returns (google.protobuf.Empty) {}
+  rpc Enable(IdRequest) returns (google.protobuf.Empty) {}
+  rpc Lock(IdRequest) returns (google.protobuf.Empty) {}
+  rpc Unlock(IdRequest) returns (google.protobuf.Empty) {}
+  rpc Confirm(IdRequest) returns (google.protobuf.Empty) {}
   rpc SetPassword(UserSetPasswordRequest) returns (google.protobuf.Empty) {}
 }
 
-message UserQueryRequest {
-  message Provider {
-    enum Type {
-      EMAIL = 0;
-      GMAIL = 1;
-      WECHAT = 2;
-      FACEBOOK = 3;
-      GITHUB = 4;
-    }
-    Type type = 1;
-    string id = 2;
-  }
-  oneof who {
-    string uid = 1;
-    string nick_name = 2;
-    Provider provider = 3;
-  }
-}
-
 message UserSignInRequest {
   UserQueryRequest query = 1;
   string password = 2;
   google.protobuf.Duration ttl = 11;
 }
+
+message UserQueryRequest {
+  oneof user {
+    string nickname = 1;
+    string email = 2;
+  }
+  string home = 9;
+}
+
 message UserSignInResponse {
+  message Payload {
+    string nickname = 1;
+    string email = 2;
+    string real_name = 11;
+    string lang = 12;
+    string time_zone = 13;
+    string avatar = 99;
+  }
   string token = 1;
-  string real_name = 2;
+  Payload payload = 2;
   repeated string roles = 11;
-  Permission permissions = 12;
+  repeated Permission permissions = 12;
 }
 
 message UserSignUpRequest {
   string real_name = 1;
-  string nick_name = 2;
+  string nickname = 2;
   string email = 3;
   string password = 4;
   string lang = 11;
@@ -164,20 +135,17 @@ message UserSignUpRequest {
   string home = 21;
 }
 
-message UserEmailRequest {
-  UserQueryRequest query = 1;
-  string home = 9;
+message UserTokenRequest {
+  string payload = 1;
 }
 
-message UserTokenRequest { string token = 1; }
-
 message UserResetPasswordRequest {
   string token = 1;
   string password = 2;
 }
 
 message UserSetPasswordRequest {
-  int32 user = 1;
+  int32 id = 1;
   string password = 2;
 }
 
@@ -193,7 +161,7 @@ message UserSetProfileRequest {
 message UserGetProfileResponse {
   string real_name = 1;
   string avatar = 2;
-  string nick_name = 3;
+  string nickname = 3;
   string email = 4;
   string time_zone = 8;
   string lang = 9;
@@ -201,13 +169,6 @@ message UserGetProfileResponse {
   string phone = 12;
 }
 
-message UserLogsRequest {
-  Pager pager = 1;
-
-  optional UserLogsResponse.Item.Level level = 11;
-  optional string ip = 12;
-}
-
 message UserLogsResponse {
   message Item {
     enum Level {
@@ -234,14 +195,26 @@ message UserChangePasswordRequest {
   string new_password = 2;
 }
 
+message UserProvider {
+  enum Type {
+    EMAIL = 0;
+    GMAIL = 1;
+    WECHAT = 2;
+    FACEBOOK = 3;
+    GITHUB = 4;
+  }
+  Type type = 1;
+  string id = 2;
+}
+
 message UserIndexResponse {
   message Item {
     int32 id = 1;
     string uid = 2;
     string email = 3;
-    string nick_name = 4;
+    string nickname = 4;
     string real_name = 5;
-    string provider_type = 6;
+    UserProvider.Type provider_type = 6;
     google.protobuf.Timestamp updated_at = 9;
     optional google.protobuf.Timestamp last_sign_in_at = 11;
     optional string last_sign_in_ip = 12;
@@ -263,30 +236,28 @@ message UserIndexResponse {
 // ----------------------------------------------------------------------------
 
 service Attachment {
-  rpc Index(Pager) returns (AttachmetIndexResponse) {}
+  rpc Index(Pager) returns (AttachmentIndexResponse) {}
   rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Show(AttachemtShowRequest) returns (AttachemtShowResponse) {}
+  rpc Show(AttachmentShowRequest) returns (AttachmentShowResponse) {}
 }
-message AttachemtShowRequest {
+message AttachmentShowRequest {
   int32 id = 1;
   google.protobuf.Duration ttl = 2;
 }
-message AttachemtShowResponse {
-  AttachmetIndexResponse.Item item = 1;
+message AttachmentShowResponse {
+  AttachmentIndexResponse.Item item = 1;
   string url = 2;
 }
 
-message AttachmetIndexResponse {
+message AttachmentIndexResponse {
   message Item {
-
     int32 id = 1;
     string bucket = 2;
     string name = 3;
     string title = 4;
     int64 size = 5;
     string content_type = 6;
-    string region = 7;
-    MediaContent.Status status = 8;
+    MediaContent.Status status = 7;
 
     google.protobuf.Timestamp updated_at = 11;
   }
@@ -297,77 +268,108 @@ message AttachmetIndexResponse {
 // ----------------------------------------------------------------------------
 
 service Policy {
+  rpc AddRole(PolicyAddRoleRequest) returns (google.protobuf.Empty) {}
   rpc GetAllRoles(google.protobuf.Empty) returns (PolicyRoleListResponse) {}
-  rpc GetAllUsers(google.protobuf.Empty) returns (PolicyUserListResponse) {}
-  rpc DeleteUser(PolicyUserRequest) returns (google.protobuf.Empty) {}
-  rpc DeleteRole(PolicyRoleRequest) returns (google.protobuf.Empty) {}
-  rpc GetRolesForUser(PolicyUserRequest) returns (PolicyRoleListResponse) {}
-  rpc GetUsersForRole(PolicyRoleRequest) returns (PolicyUserListResponse) {}
+  rpc DeleteRole(IdRequest) returns (google.protobuf.Empty) {}
+  rpc GetRolesForUser(IdRequest) returns (PolicyRolesForUserResponse) {}
+  rpc GetUsersForRole(IdRequest) returns (PolicyUsersForRoleResponse) {}
   rpc AddRolesForUser(PolicyAddRolesForUserRequest)
       returns (google.protobuf.Empty) {}
   rpc DeleteRolesForUser(PolicyDeleteRolesForUserRequest)
       returns (google.protobuf.Empty) {}
-  rpc GetImplicitRolesForUser(PolicyUserRequest)
-      returns (PolicyRoleListResponse) {}
-  rpc GetImplicitUsersForRole(PolicyRoleRequest)
-      returns (PolicyRoleListResponse) {}
-
-  rpc GetPermissionsForUser(PolicyUserRequest)
-      returns (PolicyPermissionsResponse) {}
-  rpc GetPermissionsForRole(PolicyRoleRequest)
-      returns (PolicyPermissionsResponse) {}
-  rpc GetImplicitPermissionsForUser(PolicyUserRequest)
-      returns (PolicyPermissionsResponse) {}
-  rpc GetImplicitPermissionsForRole(PolicyRoleRequest)
-      returns (PolicyPermissionsResponse) {}
-
-  rpc GetImplicitResourcesForUser(PolicyUserRequest)
-      returns (PolicyResourceResponse) {}
-  rpc GetImplicitResourcesForRole(PolicyRoleRequest)
-      returns (PolicyResourceResponse) {}
-
-  rpc AddPermissions(PolicyPermissionsRequest) returns (google.protobuf.Empty) {
-  }
-  rpc DeletePermissions(PolicyPermissionsRequest)
-      returns (google.protobuf.Empty) {}
+  rpc GetImplicitRolesForUser(IdRequest)
+      returns (PolicyImplicitRolesForUserResponse) {}
+  rpc GetImplicitUsersForRole(IdRequest)
+      returns (PolicyImplicitUsersForRoleResponse) {}
+
+  rpc GetPermissionsForUser(IdRequest) returns (PolicyPermissionList) {}
+  rpc GetPermissionsForRole(IdRequest) returns (PolicyPermissionList) {}
+  rpc GetImplicitPermissionsForUser(IdRequest) returns (PolicyPermissionList) {}
+  rpc GetImplicitPermissionsForRole(IdRequest) returns (PolicyPermissionList) {}
+
+  rpc AddPermissions(PolicyPermissionList) returns (google.protobuf.Empty) {}
+  rpc DeletePermissions(PolicyPermissionList) returns (google.protobuf.Empty) {}
 }
 
-message PolicyUserRequest { string code = 1; }
+message PolicyAddRoleRequest {
+  string code = 1;
+  oneof nested {
+    int32 left = 2;
+    int32 parent = 3;
+  }
+}
+
+message PolicyUsersForRoleResponse {
+  message Item {
+    UserDetail user = 1;
+    google.protobuf.Timestamp not_before = 11;
+    google.protobuf.Timestamp expired_at = 12;
+  }
+  repeated Item items = 1;
+}
+message PolicyImplicitUsersForRoleResponse {
+  repeated UserDetail items = 1;
+}
 
-message PolicyUserListResponse { repeated string items = 1; }
+message PolicyRolesForUserResponse {
+  message Item {
+    int32 id = 1;
+    string code = 2;
+    google.protobuf.Timestamp not_before = 11;
+    google.protobuf.Timestamp expired_at = 12;
+  }
+  repeated Item items = 1;
+}
 
-message PolicyRoleRequest { string code = 1; }
+message PolicyImplicitRolesForUserResponse {
+  repeated string items = 1;
+}
 
-message PolicyRoleListResponse { repeated string items = 1; }
+message PolicyRoleListResponse {
+  message Item {
+    int32 id = 1;
+    string code = 2;
+    int32 left = 3;
+    int32 right = 4;
+    google.protobuf.Timestamp updated_at = 9;
+  }
+  repeated Item items = 1;
+}
 
 message PolicyAddRolesForUserRequest {
-  string user = 1;
-  repeated string roles = 2;
+  int32 user = 1;
+  repeated int32 roles = 2;
   google.protobuf.Timestamp not_before = 11;
   google.protobuf.Timestamp expired_at = 12;
 }
 
 message PolicyDeleteRolesForUserRequest {
-  string user = 1;
-  repeated string roles = 2;
+  int32 user = 1;
+  repeated int32 roles = 2;
 }
 
-message PolicyPermissionsRequest { repeated Permission items = 1; }
-
-message PolicyPermissionsResponse { repeated Permission items = 1; }
-
-message PolicyResourceResponse { repeated Resource items = 1; }
+message PolicyPermissionList {
+  repeated Permission items = 1;
+}
 
-// ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 
 service Locale {
   rpc Set(LocaleSetRequest) returns (google.protobuf.Empty) {}
   rpc Get(LocaleGetRequest) returns (LocaleIndexResponse.Item) {}
+  rpc ByLang(LocaleByLangRequest) returns (LocaleByLangResponse) {}
   rpc Index(Pager) returns (LocaleIndexResponse) {}
   rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
 }
 
+message LocaleByLangRequest {
+  string lang = 1;
+}
+
+message LocaleByLangResponse {
+  repeated LocaleIndexResponse.Item items = 1;
+}
+
 message LocaleIndexResponse {
   message Item {
     int32 id = 1;
@@ -389,32 +391,46 @@ message LocaleSetRequest {
   string code = 2;
   string message = 3;
 }
-
 // ----------------------------------------------------------------------------
+service Notification {
+  rpc Index(Pager) returns (IndexNotificationResponse) {}
+}
 
-service Setting {
-  rpc Set(SettingSetRequest) returns (google.protobuf.Empty) {}
-  rpc Get(SettingGetRequest) returns (SettingGetResponse) {}
+message IndexNotificationResponse {
+  message Item {
+    oneof message {
+      EmailTask email = 1;
+      SmsTask sms = 2;
+    }
+    google.protobuf.Timestamp created_at = 19;
+  }
+  repeated Item items = 1;
+  Pagination pagination = 9;
 }
 
-message SettingGetResponse { bytes value = 1; }
+// ----------------------------------------------------------------------------
 
-message SettingGetRequest {
-  optional int32 user = 1;
-  string key = 2;
+service LeaveWord {
+  rpc Create(MediaContent) returns (google.protobuf.Empty) {}
+  rpc Index(Pager) returns (LeaveWordIndexResponse) {}
+  rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
 }
 
-message SettingSetRequest {
-  optional int32 user = 1;
-  string key = 2;
-  bytes value = 3;
-  bool encrypt = 9;
+message LeaveWordIndexResponse {
+  message Item {
+    int32 id = 1;
+    string lang = 2;
+    string ip = 3;
+    MediaContent content = 8;
+    google.protobuf.Timestamp updated_at = 11;
+    google.protobuf.Timestamp created_at = 12;
+  }
+  repeated Item items = 1;
+  Pagination pagination = 9;
 }
 
 // ----------------------------------------------------------------------------
 
-// ----------------------------------------------------------------------------
-
 service Site {
   rpc SetMaintenanceMode(SiteMaintenanceModeRequest)
       returns (google.protobuf.Empty) {}
@@ -430,26 +446,47 @@ service Site {
   rpc SetInfo(SiteSetInfoRequest) returns (google.protobuf.Empty) {}
   rpc SetLogo(SiteSetLogoRequest) returns (google.protobuf.Empty) {}
 
-  rpc SetAws(AwsProfile) returns (google.protobuf.Empty) {}
-  rpc GetAws(google.protobuf.Empty) returns (AwsProfile) {}
-  rpc TestAwsS3(google.protobuf.Empty) returns (SiteAwsS3TestResponse) {}
+  rpc SetMinio(MinioProfile) returns (google.protobuf.Empty) {}
+  rpc GetMinio(google.protobuf.Empty) returns (MinioProfile) {}
+  rpc TestMinio(MinioProfile) returns (SiteMinioTestResponse) {}
+
+  rpc SetTwilio(TwilioProfile) returns (google.protobuf.Empty) {}
+  rpc GetTwilio(google.protobuf.Empty) returns (TwilioProfile) {}
+  rpc TestTwilio(SiteTwilioTestRequest) returns (google.protobuf.Empty) {}
+
   rpc SetSmtp(SmtpProfile) returns (google.protobuf.Empty) {}
   rpc GetSmtp(google.protobuf.Empty) returns (SmtpProfile) {}
-  rpc TestSmtp(SiteSmtpTestRequst) returns (google.protobuf.Empty) {}
+  rpc TestSmtp(SiteSmtpTestRequest) returns (google.protobuf.Empty) {}
+
   rpc SetBing(BingProfile) returns (google.protobuf.Empty) {}
   rpc GetBing(google.protobuf.Empty) returns (BingProfile) {}
+
+  rpc SetIndexNow(IndexNowProfile) returns (google.protobuf.Empty) {}
+  rpc GetIndexNow(google.protobuf.Empty) returns (IndexNowProfile) {}
+  rpc PingIndexNow(IndexNowPingRequest) returns (google.protobuf.Empty) {}
+
   rpc SetGoogle(GoogleProfile) returns (google.protobuf.Empty) {}
   rpc GetGoogle(google.protobuf.Empty) returns (GoogleProfile) {}
+  rpc PingGoogle(SitemapPingRequest) returns (google.protobuf.Empty) {}
+
   rpc SetBaidu(BaiduProfile) returns (google.protobuf.Empty) {}
   rpc GetBaidu(google.protobuf.Empty) returns (BaiduProfile) {}
+  rpc PingBaidu(SitemapPingRequest) returns (google.protobuf.Empty) {}
 
   rpc Status(google.protobuf.Empty) returns (SiteStatusResponse) {}
+}
 
-  rpc NewLeaveWord(SiteNewLeaveWordRequest) returns (google.protobuf.Empty) {}
-  rpc IndexLeaveWord(Pager) returns (SiteIndexLeaveWordResponse) {}
-  rpc DestroyLeaveWord(IdRequest) returns (google.protobuf.Empty) {}
+message IndexNowProfile {
+  string key = 1;
+}
 
-  rpc IndexNotification(Pager) returns (SiteIndexNotificationResponse) {}
+message IndexNowPingRequest {
+  string key = 1;
+  string home = 9;
+}
+
+message SitemapPingRequest {
+  string home = 1;
 }
 
 message SiteMaintenanceModeRequest {
@@ -460,29 +497,98 @@ message SiteMaintenanceModeRequest {
   optional Item item = 1;
 }
 
-message SiteInstallRequest { UserSignUpRequest user = 1; }
+message SiteInstallRequest {
+  UserSignUpRequest user = 1;
+}
+
+message MinioProfile {
+  optional string region = 1;
+  string host = 2;
+  int32 port = 3;
+  bool https = 4;
+  string access_key = 8;
+  string secret_key = 9;
+}
+
+message SiteMinioTestResponse {
+  repeated string buckets = 1;
+}
+
+message TwilioProfile {
+  string from = 1;
+  string account_sid = 2;
+  string auth_token = 3;
+  optional string sms_status_callback = 9;
+}
+
+message SmtpProfile {
+  // https://github.com/karastojko/mailio/blob/master/include/mailio/smtp.hpp#L229
+  enum AuthMethod {
+    None = 0;
+    Login = 1;
+    StartTls = 2;
+  }
+  string host = 1;
+  uint32 port = 2;
+  AuthMethod auth_method = 3;
+  repeated EmailTask.Address cc = 8;
+  repeated EmailTask.Address bcc = 9;
 
-message AwsProfile {
-  string region = 1;
-  optional string endpoint = 2;
-  string access_key_id = 3;
-  string secret_access_key = 4;
+  EmailTask.Address user = 11;
+  string password = 12;
 }
-message SiteAwsS3TestResponse { repeated string buckets = 1; }
 
-message SiteSmtpTestRequst {
+message EmailTask {
+  message Address {
+    string name = 1;
+    string email = 2;
+  }
+  enum ContentType {
+    Plain = 0;
+    Html = 1;
+  }
+  message Attachment {
+    string name = 1;
+    string content_type = 2;
+    bytes payload = 3;
+  }
+  string subject = 1;
+  string content = 2;
+  ContentType content_type = 3;
+
+  Address to = 11;
+  repeated Address cc = 12;
+  repeated Address bcc = 13;
+  repeated Attachment attachments = 21;
+}
+
+message SiteTwilioTestRequest {
   string to = 1;
+  string message = 2;
+  TwilioProfile profile = 9;
+}
+
+message SiteSmtpTestRequest {
+  EmailTask.Address to = 1;
   string subject = 2;
-  string body = 3;
+  string content = 3;
+  SmtpProfile profile = 9;
 }
 
-message SiteSetLogoRequest { string url = 1; }
-message SiteSetCopyrightRequest { string payload = 1; }
-message SiteSetKeywordsRequest { repeated string items = 1; }
+message SiteSetLogoRequest {
+  string url = 1;
+}
+message SiteSetCopyrightRequest {
+  string payload = 1;
+}
+message SiteSetKeywordsRequest {
+  repeated string items = 1;
+}
 message SiteSetInfoRequest {
-  string title = 1;
-  string subhead = 2;
-  string description = 3;
+  string lang = 1;
+  string title = 11;
+  string subhead = 12;
+  string description = 13;
 }
 
 message SiteLayoutResponse {
@@ -500,19 +606,6 @@ message SiteLayoutResponse {
   repeated string languages = 9;
 }
 
-message SiteNewLeaveWordRequest { string body = 1; }
-message SiteIndexLeaveWordResponse {
-  message Item {
-    int32 id = 1;
-    string lang = 2;
-    string ip = 3;
-    string body = 4;
-    google.protobuf.Timestamp created_at = 9;
-  }
-  repeated Item items = 1;
-  Pagination pagination = 9;
-}
-
 message GoogleProfile {
   // https://developers.google.com/recaptcha/intro
   message ReCaptcha {
@@ -529,27 +622,14 @@ message BaiduProfile {
   }
   optional SiteVerify site_verify = 1;
 }
-message BingProfile { optional string site_verify_id = 1; }
-
-message SmtpProfile {
-  string host = 1;
-  uint32 port = 2;
-  string user = 3;
-  string password = 4;
-  string cc = 5;
-  string bcc = 6;
+message BingProfile {
+  optional string site_verify_id = 1;
 }
 
-message SiteIndexNotificationResponse {
-  message Item {
-    oneof message {
-      EmailTask email = 1;
-      SmsTask sms = 2;
-    }
-    google.protobuf.Timestamp created_at = 19;
-  }
-  repeated Item items = 1;
-  Pagination pagination = 9;
+message SmsTask {
+  string from = 1;
+  repeated string to = 2;
+  string body = 3;
 }
 
 message SiteStatusResponse {
@@ -574,7 +654,9 @@ message SiteStatusResponse {
     string info = 1;
     repeated Item items = 2;
   }
-  message RabbitMq { string protocol = 1; }
+  message RabbitMq {
+    string protocol = 1;
+  }
   message OpenSearch {
     string url = 1;
     string info = 2;
@@ -619,6 +701,7 @@ message ShorterLinkIndexResponse {
     int32 id = 1;
     string url = 2;
     string details = 3;
+    string code = 9;
 
     google.protobuf.Timestamp updated_at = 11;
   }
@@ -650,7 +733,6 @@ message TagIndexResponse {
     int32 id = 1;
     string code = 2;
     int32 priority = 3;
-
     google.protobuf.Timestamp updated_at = 11;
   }
   repeated Item items = 1;
@@ -672,32 +754,30 @@ service Category {
   rpc Create(CategoryCreateRequest) returns (google.protobuf.Empty) {}
   rpc Update(CategoryUpdateRequest) returns (google.protobuf.Empty) {}
   rpc Destroy(IdRequest) returns (google.protobuf.Empty) {}
-  rpc Index(Pager) returns (CategoryIndexResponse) {}
+  rpc Index(google.protobuf.Empty) returns (CategoryIndexResponse) {}
 }
 message CategoryIndexResponse {
   message Item {
     int32 id = 1;
     string code = 2;
-    optional int32 parent_id = 3;
-    int32 priority = 4;
+    int32 left = 3;
+    int32 right = 4;
 
     google.protobuf.Timestamp updated_at = 11;
   }
-  Pagination pagination = 1;
-  repeated Item items = 11;
+  repeated Item items = 1;
 }
 message CategoryCreateRequest {
-  string lang = 1;
-  string code = 2;
-  optional int32 parent_id = 3;
-  int32 priority = 11;
+  string code = 1;
+  oneof by {
+    int32 left = 2;
+    int32 parent = 3;
+  }
 }
 
 message CategoryUpdateRequest {
   int32 id = 1;
   string code = 2;
-  optional int32 parent_id = 3;
-  int32 priority = 11;
 }
 
 // ----------------------------------------------------------------------------

+ 23 - 0
scripts/ops/ngbe.sh

@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+. /etc/os-release
+
+export WORKSPACE=$PWD/ngbe-1.2.3
+
+if [ ! -d $WORKSPACE ]
+then
+    echo "coun't find the source folder $WORKSPACE"
+    exit 1
+fi
+
+apt install -y build-essential
+cd $WORKSPACE/src
+make
+make install
+
+echo 'ngbe' > /etc/modules-load.d/ngbe.conf
+
+echo 'done.'
+exit 0