From 253275b280f5f37cfc7a501a52c478cc7923407b Mon Sep 17 00:00:00 2001 From: Yvan <8574526@qq,com> Date: Tue, 6 Jan 2026 12:20:42 +0800 Subject: [PATCH] init --- .gitignore | 40 + Dockerfile | 24 + LICENSE | 21 + Makefile | 84 ++ README.md | 62 + api/kratos/admin/v1/admin.pb.go | 708 +++++++++++ api/kratos/admin/v1/admin.proto | 161 +++ api/kratos/admin/v1/admin_grpc.pb.go | 408 +++++++ api/kratos/admin/v1/admin_http.pb.go | 370 ++++++ configs/config.yaml | 15 + go.mod | 50 + go.sum | 186 +++ internal/biz/README.md | 1 + internal/biz/admin.go | 105 ++ internal/biz/biz.go | 6 + internal/biz/errros.go | 8 + internal/biz/pagination.go | 39 + internal/conf/conf.pb.go | 544 +++++++++ internal/conf/conf.proto | 41 + internal/data/README.md | 1 + internal/data/admin.go | 127 ++ internal/data/data.go | 43 + internal/data/ent/admin.go | 172 +++ internal/data/ent/admin/admin.go | 116 ++ internal/data/ent/admin/where.go | 510 ++++++++ internal/data/ent/admin_create.go | 859 +++++++++++++ internal/data/ent/admin_delete.go | 88 ++ internal/data/ent/admin_query.go | 527 ++++++++ internal/data/ent/admin_update.go | 382 ++++++ internal/data/ent/client.go | 366 ++++++ internal/data/ent/ent.go | 608 +++++++++ internal/data/ent/enttest/enttest.go | 84 ++ internal/data/ent/generate.go | 3 + internal/data/ent/hook/hook.go | 199 +++ internal/data/ent/migrate/migrate.go | 64 + internal/data/ent/migrate/schema.go | 35 + internal/data/ent/mutation.go | 684 +++++++++++ internal/data/ent/predicate/predicate.go | 10 + internal/data/ent/runtime.go | 48 + internal/data/ent/runtime/runtime.go | 10 + internal/data/ent/schema/admin.go | 27 + internal/data/ent/tx.go | 236 ++++ internal/server/grpc.go | 33 + internal/server/http.go | 37 + internal/server/server.go | 8 + internal/service/README.md | 1 + internal/service/admin.go | 243 ++++ internal/service/service.go | 6 + openapi.yaml | 247 ++++ pkg/auth/auth.go | 32 + pkg/auth/config.go | 22 + pkg/auth/middleware.go | 89 ++ pkg/auth/token.go | 45 + pkg/validate/validate.go | 24 + third_party/README.md | 1 + third_party/errors/errors.proto | 18 + third_party/google/api/annotations.proto | 31 + third_party/google/api/client.proto | 101 ++ third_party/google/api/field_behavior.proto | 80 ++ third_party/google/api/http.proto | 375 ++++++ third_party/google/api/httpbody.proto | 77 ++ third_party/google/protobuf/any.proto | 158 +++ third_party/google/protobuf/api.proto | 208 ++++ .../google/protobuf/compiler/plugin.proto | 183 +++ third_party/google/protobuf/descriptor.proto | 921 ++++++++++++++ third_party/google/protobuf/duration.proto | 116 ++ third_party/google/protobuf/empty.proto | 52 + third_party/google/protobuf/field_mask.proto | 245 ++++ .../google/protobuf/source_context.proto | 48 + third_party/google/protobuf/struct.proto | 95 ++ third_party/google/protobuf/timestamp.proto | 147 +++ third_party/google/protobuf/type.proto | 187 +++ third_party/google/protobuf/wrappers.proto | 123 ++ third_party/openapi/v3/annotations.proto | 60 + third_party/openapi/v3/openapi.proto | 672 ++++++++++ third_party/validate/README.md | 3 + third_party/validate/validate.proto | 863 +++++++++++++ web/.commitlintrc.js | 1 + web/.editorconfig | 16 + web/.gitignore | 41 + web/.husky/commit-msg | 1 + web/.husky/pre-commit | 1 + web/.lintstagedrc | 5 + web/.npmrc | 1 + web/CODE_OF_CONDUCT.md | 46 + web/LICENSE | 21 + web/README.ar-DZ.md | 125 ++ web/README.es-ES.md | 125 ++ web/README.fr-FR.md | 125 ++ web/README.ja-JP.md | 125 ++ web/README.md | 127 ++ web/README.pt-BR.md | 125 ++ web/README.ru-RU.md | 125 ++ web/README.tr-TR.md | 125 ++ web/README.zh-CN.md | 120 ++ web/biome.json | 49 + web/config/config.ts | 177 +++ web/config/defaultSettings.ts | 28 + web/config/oneapi.json | 593 +++++++++ web/config/proxy.ts | 23 + web/config/routes.ts | 47 + web/jest.config.ts | 21 + web/mock/listTableList.ts | 187 +++ web/mock/monitor.mock.ts | 14 + web/mock/notices.ts | 117 ++ web/mock/requestRecord.mock.js | 345 ++++++ web/mock/route.ts | 5 + web/mock/user.ts | 205 ++++ web/package.json | 97 ++ web/public/CNAME | 1 + web/public/favicon.ico | Bin 0 -> 4286 bytes web/public/icons/icon-128x128.png | Bin 0 -> 1329 bytes web/public/icons/icon-192x192.png | Bin 0 -> 1856 bytes web/public/icons/icon-512x512.png | Bin 0 -> 5082 bytes web/public/logo.svg | 1 + web/public/pro_icon.svg | 5 + web/public/scripts/loading.js | 202 +++ web/src/access.ts | 11 + web/src/app.tsx | 154 +++ web/src/components/Footer/index.tsx | 36 + web/src/components/HeaderDropdown/index.tsx | 41 + .../RightContent/AvatarDropdown.tsx | 144 +++ web/src/components/RightContent/index.tsx | 32 + web/src/components/index.ts | 12 + web/src/global.less | 94 ++ web/src/global.style.ts | 42 + web/src/global.tsx | 93 ++ web/src/loading.tsx | 7 + web/src/locales/bn-BD.ts | 25 + web/src/locales/bn-BD/component.ts | 5 + web/src/locales/bn-BD/globalHeader.ts | 17 + web/src/locales/bn-BD/menu.ts | 52 + web/src/locales/bn-BD/pages.ts | 73 ++ web/src/locales/bn-BD/pwa.ts | 7 + web/src/locales/bn-BD/settingDrawer.ts | 32 + web/src/locales/bn-BD/settings.ts | 60 + web/src/locales/en-US.ts | 25 + web/src/locales/en-US/component.ts | 5 + web/src/locales/en-US/globalHeader.ts | 18 + web/src/locales/en-US/menu.ts | 52 + web/src/locales/en-US/pages.ts | 76 ++ web/src/locales/en-US/pwa.ts | 7 + web/src/locales/en-US/settingDrawer.ts | 32 + web/src/locales/en-US/settings.ts | 61 + web/src/locales/fa-IR.ts | 25 + web/src/locales/fa-IR/component.ts | 5 + web/src/locales/fa-IR/globalHeader.ts | 18 + web/src/locales/fa-IR/menu.ts | 52 + web/src/locales/fa-IR/pages.ts | 75 ++ web/src/locales/fa-IR/pwa.ts | 7 + web/src/locales/fa-IR/settingDrawer.ts | 32 + web/src/locales/fa-IR/settings.ts | 64 + web/src/locales/id-ID.ts | 25 + web/src/locales/id-ID/component.ts | 5 + web/src/locales/id-ID/globalHeader.ts | 18 + web/src/locales/id-ID/menu.ts | 53 + web/src/locales/id-ID/pages.ts | 75 ++ web/src/locales/id-ID/pwa.ts | 7 + web/src/locales/id-ID/settingDrawer.ts | 33 + web/src/locales/id-ID/settings.ts | 64 + web/src/locales/ja-JP.ts | 25 + web/src/locales/ja-JP/component.ts | 5 + web/src/locales/ja-JP/globalHeader.ts | 17 + web/src/locales/ja-JP/menu.ts | 52 + web/src/locales/ja-JP/pages.ts | 77 ++ web/src/locales/ja-JP/pwa.ts | 7 + web/src/locales/ja-JP/settingDrawer.ts | 33 + web/src/locales/ja-JP/settings.ts | 63 + web/src/locales/pt-BR.ts | 22 + web/src/locales/pt-BR/component.ts | 5 + web/src/locales/pt-BR/globalHeader.ts | 18 + web/src/locales/pt-BR/menu.ts | 54 + web/src/locales/pt-BR/pages.ts | 77 ++ web/src/locales/pt-BR/pwa.ts | 7 + web/src/locales/pt-BR/settingDrawer.ts | 33 + web/src/locales/pt-BR/settings.ts | 66 + web/src/locales/zh-CN.ts | 24 + web/src/locales/zh-CN/component.ts | 5 + web/src/locales/zh-CN/globalHeader.ts | 17 + web/src/locales/zh-CN/menu.ts | 51 + web/src/locales/zh-CN/pages.ts | 78 ++ web/src/locales/zh-CN/pwa.ts | 6 + web/src/locales/zh-CN/settingDrawer.ts | 32 + web/src/locales/zh-CN/settings.ts | 59 + web/src/locales/zh-TW.ts | 22 + web/src/locales/zh-TW/component.ts | 5 + web/src/locales/zh-TW/globalHeader.ts | 17 + web/src/locales/zh-TW/menu.ts | 52 + web/src/locales/zh-TW/pages.ts | 71 ++ web/src/locales/zh-TW/pwa.ts | 6 + web/src/locales/zh-TW/settingDrawer.ts | 32 + web/src/locales/zh-TW/settings.ts | 59 + web/src/manifest.json | 22 + web/src/pages/404.tsx | 20 + web/src/pages/Admin.tsx | 51 + web/src/pages/Welcome.tsx | 166 +++ .../pages/admins/components/CreateForm.tsx | 154 +++ .../pages/admins/components/UpdateForm.tsx | 154 +++ web/src/pages/admins/index.tsx | 264 ++++ .../login/__snapshots__/login.test.tsx.snap | 1088 +++++++++++++++++ web/src/pages/user/login/index.tsx | 388 ++++++ web/src/pages/user/login/login.test.tsx | 102 ++ web/src/requestErrorConfig.ts | 54 + web/src/service-worker.js | 66 + web/src/services/ant-design-pro/api.ts | 94 ++ web/src/services/ant-design-pro/index.ts | 10 + web/src/services/ant-design-pro/login.ts | 21 + web/src/services/ant-design-pro/typings.d.ts | 101 ++ web/src/services/index.ts | 24 + web/src/services/kratos/admin/v1/index.ts | 330 +++++ web/src/services/swagger/index.ts | 12 + web/src/services/swagger/pet.ts | 153 +++ web/src/services/swagger/store.ts | 48 + web/src/services/swagger/typings.d.ts | 112 ++ web/src/services/swagger/user.ts | 100 ++ web/src/typings.d.ts | 16 + web/tests/setupTests.jsx | 78 ++ web/tsconfig.json | 22 + web/types/index.d.ts | 120 ++ 219 files changed, 23633 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 api/kratos/admin/v1/admin.pb.go create mode 100644 api/kratos/admin/v1/admin.proto create mode 100644 api/kratos/admin/v1/admin_grpc.pb.go create mode 100644 api/kratos/admin/v1/admin_http.pb.go create mode 100644 configs/config.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/biz/README.md create mode 100644 internal/biz/admin.go create mode 100644 internal/biz/biz.go create mode 100644 internal/biz/errros.go create mode 100644 internal/biz/pagination.go create mode 100644 internal/conf/conf.pb.go create mode 100644 internal/conf/conf.proto create mode 100644 internal/data/README.md create mode 100644 internal/data/admin.go create mode 100644 internal/data/data.go create mode 100644 internal/data/ent/admin.go create mode 100644 internal/data/ent/admin/admin.go create mode 100644 internal/data/ent/admin/where.go create mode 100644 internal/data/ent/admin_create.go create mode 100644 internal/data/ent/admin_delete.go create mode 100644 internal/data/ent/admin_query.go create mode 100644 internal/data/ent/admin_update.go create mode 100644 internal/data/ent/client.go create mode 100644 internal/data/ent/ent.go create mode 100644 internal/data/ent/enttest/enttest.go create mode 100644 internal/data/ent/generate.go create mode 100644 internal/data/ent/hook/hook.go create mode 100644 internal/data/ent/migrate/migrate.go create mode 100644 internal/data/ent/migrate/schema.go create mode 100644 internal/data/ent/mutation.go create mode 100644 internal/data/ent/predicate/predicate.go create mode 100644 internal/data/ent/runtime.go create mode 100644 internal/data/ent/runtime/runtime.go create mode 100644 internal/data/ent/schema/admin.go create mode 100644 internal/data/ent/tx.go create mode 100644 internal/server/grpc.go create mode 100644 internal/server/http.go create mode 100644 internal/server/server.go create mode 100644 internal/service/README.md create mode 100644 internal/service/admin.go create mode 100644 internal/service/service.go create mode 100644 openapi.yaml create mode 100644 pkg/auth/auth.go create mode 100644 pkg/auth/config.go create mode 100644 pkg/auth/middleware.go create mode 100644 pkg/auth/token.go create mode 100644 pkg/validate/validate.go create mode 100644 third_party/README.md create mode 100644 third_party/errors/errors.proto create mode 100644 third_party/google/api/annotations.proto create mode 100644 third_party/google/api/client.proto create mode 100644 third_party/google/api/field_behavior.proto create mode 100644 third_party/google/api/http.proto create mode 100644 third_party/google/api/httpbody.proto create mode 100644 third_party/google/protobuf/any.proto create mode 100644 third_party/google/protobuf/api.proto create mode 100644 third_party/google/protobuf/compiler/plugin.proto create mode 100644 third_party/google/protobuf/descriptor.proto create mode 100644 third_party/google/protobuf/duration.proto create mode 100644 third_party/google/protobuf/empty.proto create mode 100644 third_party/google/protobuf/field_mask.proto create mode 100644 third_party/google/protobuf/source_context.proto create mode 100644 third_party/google/protobuf/struct.proto create mode 100644 third_party/google/protobuf/timestamp.proto create mode 100644 third_party/google/protobuf/type.proto create mode 100644 third_party/google/protobuf/wrappers.proto create mode 100644 third_party/openapi/v3/annotations.proto create mode 100644 third_party/openapi/v3/openapi.proto create mode 100644 third_party/validate/README.md create mode 100644 third_party/validate/validate.proto create mode 100644 web/.commitlintrc.js create mode 100644 web/.editorconfig create mode 100644 web/.gitignore create mode 100644 web/.husky/commit-msg create mode 100644 web/.husky/pre-commit create mode 100644 web/.lintstagedrc create mode 100644 web/.npmrc create mode 100644 web/CODE_OF_CONDUCT.md create mode 100644 web/LICENSE create mode 100644 web/README.ar-DZ.md create mode 100644 web/README.es-ES.md create mode 100644 web/README.fr-FR.md create mode 100644 web/README.ja-JP.md create mode 100644 web/README.md create mode 100644 web/README.pt-BR.md create mode 100644 web/README.ru-RU.md create mode 100644 web/README.tr-TR.md create mode 100644 web/README.zh-CN.md create mode 100644 web/biome.json create mode 100644 web/config/config.ts create mode 100644 web/config/defaultSettings.ts create mode 100644 web/config/oneapi.json create mode 100644 web/config/proxy.ts create mode 100644 web/config/routes.ts create mode 100644 web/jest.config.ts create mode 100644 web/mock/listTableList.ts create mode 100644 web/mock/monitor.mock.ts create mode 100644 web/mock/notices.ts create mode 100644 web/mock/requestRecord.mock.js create mode 100644 web/mock/route.ts create mode 100644 web/mock/user.ts create mode 100644 web/package.json create mode 100644 web/public/CNAME create mode 100644 web/public/favicon.ico create mode 100644 web/public/icons/icon-128x128.png create mode 100644 web/public/icons/icon-192x192.png create mode 100644 web/public/icons/icon-512x512.png create mode 100644 web/public/logo.svg create mode 100644 web/public/pro_icon.svg create mode 100644 web/public/scripts/loading.js create mode 100644 web/src/access.ts create mode 100644 web/src/app.tsx create mode 100644 web/src/components/Footer/index.tsx create mode 100644 web/src/components/HeaderDropdown/index.tsx create mode 100644 web/src/components/RightContent/AvatarDropdown.tsx create mode 100644 web/src/components/RightContent/index.tsx create mode 100644 web/src/components/index.ts create mode 100644 web/src/global.less create mode 100644 web/src/global.style.ts create mode 100644 web/src/global.tsx create mode 100644 web/src/loading.tsx create mode 100644 web/src/locales/bn-BD.ts create mode 100644 web/src/locales/bn-BD/component.ts create mode 100644 web/src/locales/bn-BD/globalHeader.ts create mode 100644 web/src/locales/bn-BD/menu.ts create mode 100644 web/src/locales/bn-BD/pages.ts create mode 100644 web/src/locales/bn-BD/pwa.ts create mode 100644 web/src/locales/bn-BD/settingDrawer.ts create mode 100644 web/src/locales/bn-BD/settings.ts create mode 100644 web/src/locales/en-US.ts create mode 100644 web/src/locales/en-US/component.ts create mode 100644 web/src/locales/en-US/globalHeader.ts create mode 100644 web/src/locales/en-US/menu.ts create mode 100644 web/src/locales/en-US/pages.ts create mode 100644 web/src/locales/en-US/pwa.ts create mode 100644 web/src/locales/en-US/settingDrawer.ts create mode 100644 web/src/locales/en-US/settings.ts create mode 100644 web/src/locales/fa-IR.ts create mode 100644 web/src/locales/fa-IR/component.ts create mode 100644 web/src/locales/fa-IR/globalHeader.ts create mode 100644 web/src/locales/fa-IR/menu.ts create mode 100644 web/src/locales/fa-IR/pages.ts create mode 100644 web/src/locales/fa-IR/pwa.ts create mode 100644 web/src/locales/fa-IR/settingDrawer.ts create mode 100644 web/src/locales/fa-IR/settings.ts create mode 100644 web/src/locales/id-ID.ts create mode 100644 web/src/locales/id-ID/component.ts create mode 100644 web/src/locales/id-ID/globalHeader.ts create mode 100644 web/src/locales/id-ID/menu.ts create mode 100644 web/src/locales/id-ID/pages.ts create mode 100644 web/src/locales/id-ID/pwa.ts create mode 100644 web/src/locales/id-ID/settingDrawer.ts create mode 100644 web/src/locales/id-ID/settings.ts create mode 100644 web/src/locales/ja-JP.ts create mode 100644 web/src/locales/ja-JP/component.ts create mode 100644 web/src/locales/ja-JP/globalHeader.ts create mode 100644 web/src/locales/ja-JP/menu.ts create mode 100644 web/src/locales/ja-JP/pages.ts create mode 100644 web/src/locales/ja-JP/pwa.ts create mode 100644 web/src/locales/ja-JP/settingDrawer.ts create mode 100644 web/src/locales/ja-JP/settings.ts create mode 100644 web/src/locales/pt-BR.ts create mode 100644 web/src/locales/pt-BR/component.ts create mode 100644 web/src/locales/pt-BR/globalHeader.ts create mode 100644 web/src/locales/pt-BR/menu.ts create mode 100644 web/src/locales/pt-BR/pages.ts create mode 100644 web/src/locales/pt-BR/pwa.ts create mode 100644 web/src/locales/pt-BR/settingDrawer.ts create mode 100644 web/src/locales/pt-BR/settings.ts create mode 100644 web/src/locales/zh-CN.ts create mode 100644 web/src/locales/zh-CN/component.ts create mode 100644 web/src/locales/zh-CN/globalHeader.ts create mode 100644 web/src/locales/zh-CN/menu.ts create mode 100644 web/src/locales/zh-CN/pages.ts create mode 100644 web/src/locales/zh-CN/pwa.ts create mode 100644 web/src/locales/zh-CN/settingDrawer.ts create mode 100644 web/src/locales/zh-CN/settings.ts create mode 100644 web/src/locales/zh-TW.ts create mode 100644 web/src/locales/zh-TW/component.ts create mode 100644 web/src/locales/zh-TW/globalHeader.ts create mode 100644 web/src/locales/zh-TW/menu.ts create mode 100644 web/src/locales/zh-TW/pages.ts create mode 100644 web/src/locales/zh-TW/pwa.ts create mode 100644 web/src/locales/zh-TW/settingDrawer.ts create mode 100644 web/src/locales/zh-TW/settings.ts create mode 100644 web/src/manifest.json create mode 100644 web/src/pages/404.tsx create mode 100644 web/src/pages/Admin.tsx create mode 100644 web/src/pages/Welcome.tsx create mode 100644 web/src/pages/admins/components/CreateForm.tsx create mode 100644 web/src/pages/admins/components/UpdateForm.tsx create mode 100644 web/src/pages/admins/index.tsx create mode 100644 web/src/pages/user/login/__snapshots__/login.test.tsx.snap create mode 100644 web/src/pages/user/login/index.tsx create mode 100644 web/src/pages/user/login/login.test.tsx create mode 100644 web/src/requestErrorConfig.ts create mode 100644 web/src/service-worker.js create mode 100644 web/src/services/ant-design-pro/api.ts create mode 100644 web/src/services/ant-design-pro/index.ts create mode 100644 web/src/services/ant-design-pro/login.ts create mode 100644 web/src/services/ant-design-pro/typings.d.ts create mode 100644 web/src/services/index.ts create mode 100644 web/src/services/kratos/admin/v1/index.ts create mode 100644 web/src/services/swagger/index.ts create mode 100644 web/src/services/swagger/pet.ts create mode 100644 web/src/services/swagger/store.ts create mode 100644 web/src/services/swagger/typings.d.ts create mode 100644 web/src/services/swagger/user.ts create mode 100644 web/src/typings.d.ts create mode 100644 web/tests/setupTests.jsx create mode 100644 web/tsconfig.json create mode 100644 web/types/index.d.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5e2699 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Reference https://github.com/github/gitignore/blob/master/Go.gitignore +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ + +# Go workspace file +go.work + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# OS General +Thumbs.db +.DS_Store + +# project +*.cert +*.key +*.log +bin/ +/cmd/kratos-admin + +# Develop tools +.vscode/ +.cache/ +.idea/ +*.swp diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..848a8a1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:1.19 AS builder + +COPY . /src +WORKDIR /src + +RUN GOPROXY=https://goproxy.cn make build + +FROM debian:stable-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + netbase \ + && rm -rf /var/lib/apt/lists/ \ + && apt-get autoremove -y && apt-get autoclean -y + +COPY --from=builder /src/bin /app + +WORKDIR /app + +EXPOSE 8000 +EXPOSE 9000 +VOLUME /data/conf + +CMD ["./server", "-conf", "/data/conf"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..684318c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 go-kratos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a510050 --- /dev/null +++ b/Makefile @@ -0,0 +1,84 @@ +GOHOSTOS:=$(shell go env GOHOSTOS) +GOPATH:=$(shell go env GOPATH) +VERSION=$(shell git describe --tags --always) + +ifeq ($(GOHOSTOS), windows) + #the `find.exe` is different from `find` in bash/shell. + #to see https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/find. + #changed to use git-bash.exe to run find cli or other cli friendly, caused of every developer has a Git. + #Git_Bash= $(subst cmd\,bin\bash.exe,$(dir $(shell where git))) + Git_Bash=$(subst \,/,$(subst cmd\,bin\bash.exe,$(dir $(shell where git)))) + INTERNAL_PROTO_FILES=$(shell $(Git_Bash) -c "find internal -name *.proto") + API_PROTO_FILES=$(shell $(Git_Bash) -c "find api -name *.proto") +else + INTERNAL_PROTO_FILES=$(shell find internal -name *.proto) + API_PROTO_FILES=$(shell find api -name *.proto) +endif + +.PHONY: init +# init env +init: + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + go install github.com/go-kratos/kratos/cmd/kratos/v2@latest + go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest + go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest + go install go.einride.tech/protoc-gen-typescript-http@latest + go install github.com/google/wire/cmd/wire@latest + +.PHONY: config +# generate internal proto +config: + protoc --proto_path=./internal \ + --proto_path=./third_party \ + --go_out=paths=source_relative:./internal \ + $(INTERNAL_PROTO_FILES) + +.PHONY: api +# generate api proto +api: + protoc --proto_path=./api \ + --proto_path=./third_party \ + --go_out=paths=source_relative:./api \ + --go-http_out=paths=source_relative:./api \ + --go-grpc_out=paths=source_relative:./api \ + --openapi_out=fq_schema_naming=true,default_response=false:. \ + --typescript-http_out ./web/src/services \ + $(API_PROTO_FILES) + +.PHONY: build +# build +build: + mkdir -p bin/ && go build -ldflags "-X main.Version=$(VERSION)" -o ./bin/ ./... + +.PHONY: generate +# generate +generate: + go generate ./... + go mod tidy + +.PHONY: all +# generate all +all: + make api; + make config; + make generate; + +# show help +help: + @echo '' + @echo 'Usage:' + @echo ' make [target]' + @echo '' + @echo 'Targets:' + @awk '/^[a-zA-Z\-\_0-9]+:/ { \ + helpMessage = match(lastLine, /^# (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")); \ + helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ + printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) + +.DEFAULT_GOAL := help diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc3dae0 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# Kratos Admin Template + +## Best Practice +Google AIP(https://google.aip.dev/general): +1. Resource-oriented design +2. Filtering +3. Pagination +4. Field masks +5. Field behavior + +## Generate API files +```shell +# Download and update dependencies +make init +# Generate API files (include: pb.go, http, grpc, validate, swagger, index.ts) by proto file +make api +``` + +## Run Web Application +```shell +# Enter web directory, install dependencies and start development server +cd web +npm install +npm run dev +``` + +The generated clients work with any Promise-based HTTP client that returns JSON. +Services are defined and re-exported from this file: `web/src/services/index.ts`. +```typescript +import { createAdminServiceClient } from "@/services/kratos/admin/v1/index"; + +type Request = { + path: string; + method: string; + body: string | null; +}; + +function requestHandler({ path, method, body }: Request) { ... } + +export function createAdminService() { + return createAdminServiceClient(requestHandler); +} +``` + +Example using the generated client: +```typescript +import { createAdminService } from "@/services/index"; + +const adminService = createAdminService(); + +const handleLogin = async (username: string, password: string) => { + try { + const response = await adminService.Login({ + username: username, + password: password, + }); + console.log("Login successful:", response); + } catch (error) { + console.error("Login failed:", error); + } +}; +``` diff --git a/api/kratos/admin/v1/admin.pb.go b/api/kratos/admin/v1/admin.pb.go new file mode 100644 index 0000000..876c6da --- /dev/null +++ b/api/kratos/admin/v1/admin.pb.go @@ -0,0 +1,708 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v4.23.2 +// source: kratos/admin/v1/admin.proto + +package v1 + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Admin is the admin message. +type Admin struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The unique ID of the user. + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // The name of the user. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // The email of the user. + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + // The phone number of the user. + Phone string `protobuf:"bytes,4,opt,name=phone,proto3" json:"phone,omitempty"` + // The avatar URL of the user. + Avatar string `protobuf:"bytes,5,opt,name=avatar,proto3" json:"avatar,omitempty"` + // The access level of the user. + // Possible values are: "admin", "user", etc. + Access string `protobuf:"bytes,6,opt,name=access,proto3" json:"access,omitempty"` + // The password of the user. + Password string `protobuf:"bytes,7,opt,name=password,proto3" json:"password,omitempty"` + // The timestamp at which the user was created. + CreateTime *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` + // The latest timestamp at which the user was updated. + UpdateTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Admin) Reset() { + *x = Admin{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Admin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Admin) ProtoMessage() {} + +func (x *Admin) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Admin.ProtoReflect.Descriptor instead. +func (*Admin) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{0} +} + +func (x *Admin) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Admin) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Admin) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *Admin) GetPhone() string { + if x != nil { + return x.Phone + } + return "" +} + +func (x *Admin) GetAvatar() string { + if x != nil { + return x.Avatar + } + return "" +} + +func (x *Admin) GetAccess() string { + if x != nil { + return x.Access + } + return "" +} + +func (x *Admin) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *Admin) GetCreateTime() *timestamppb.Timestamp { + if x != nil { + return x.CreateTime + } + return nil +} + +func (x *Admin) GetUpdateTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdateTime + } + return nil +} + +// AdminSet is the set of admins. +type AdminSet struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The set of admins. + Admins []*Admin `protobuf:"bytes,1,rep,name=admins,proto3" json:"admins,omitempty"` + // The next page token. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdminSet) Reset() { + *x = AdminSet{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdminSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdminSet) ProtoMessage() {} + +func (x *AdminSet) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdminSet.ProtoReflect.Descriptor instead. +func (*AdminSet) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{1} +} + +func (x *AdminSet) GetAdmins() []*Admin { + if x != nil { + return x.Admins + } + return nil +} + +func (x *AdminSet) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// LoginRequest is the request message for the Login method. +type LoginRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required. Password of the user. + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` + // Required. Exactly one identity must be set. + // + // Types that are valid to be assigned to Identity: + // + // *LoginRequest_Username + // *LoginRequest_Email + Identity isLoginRequest_Identity `protobuf_oneof:"identity"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LoginRequest) Reset() { + *x = LoginRequest{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LoginRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginRequest) ProtoMessage() {} + +func (x *LoginRequest) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. +func (*LoginRequest) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{2} +} + +func (x *LoginRequest) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *LoginRequest) GetIdentity() isLoginRequest_Identity { + if x != nil { + return x.Identity + } + return nil +} + +func (x *LoginRequest) GetUsername() string { + if x != nil { + if x, ok := x.Identity.(*LoginRequest_Username); ok { + return x.Username + } + } + return "" +} + +func (x *LoginRequest) GetEmail() string { + if x != nil { + if x, ok := x.Identity.(*LoginRequest_Email); ok { + return x.Email + } + } + return "" +} + +type isLoginRequest_Identity interface { + isLoginRequest_Identity() +} + +type LoginRequest_Username struct { + Username string `protobuf:"bytes,2,opt,name=username,proto3,oneof"` +} + +type LoginRequest_Email struct { + Email string `protobuf:"bytes,3,opt,name=email,proto3,oneof"` +} + +func (*LoginRequest_Username) isLoginRequest_Identity() {} + +func (*LoginRequest_Email) isLoginRequest_Identity() {} + +// GetAdminRequest is the request message for the GetAdmin method. +type GetAdminRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the admin to retrieve. + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAdminRequest) Reset() { + *x = GetAdminRequest{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAdminRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdminRequest) ProtoMessage() {} + +func (x *GetAdminRequest) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdminRequest.ProtoReflect.Descriptor instead. +func (*GetAdminRequest) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{3} +} + +func (x *GetAdminRequest) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +// ListAdminsResponse is the response message for the ListAdmins method. +type ListAdminsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional. The number of admins per page. + PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // Optional. The page token. + PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // Optional. The standard list filter. + // Supported fields: + // - `name` (i.e. `name="John Doe"`) + // - `create_time` range (i.e. `timestamp>="2025-01-31T11:30:00-04:00"` where + // the timestamp is in RFC 3339 format) + // + // More detail in [AIP-160](https://google.aip.dev/160). + Filter string `protobuf:"bytes,3,opt,name=filter,proto3" json:"filter,omitempty"` + // Optional. A comma-separated list of fields to order by, sorted in ascending + // order. Use "desc" after a field name for descending. Supported fields: + // - `create_time` + // + // Example: `create_time desc`. + OrderBy string `protobuf:"bytes,4,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListAdminsRequest) Reset() { + *x = ListAdminsRequest{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListAdminsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAdminsRequest) ProtoMessage() {} + +func (x *ListAdminsRequest) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAdminsRequest.ProtoReflect.Descriptor instead. +func (*ListAdminsRequest) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{4} +} + +func (x *ListAdminsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListAdminsRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListAdminsRequest) GetFilter() string { + if x != nil { + return x.Filter + } + return "" +} + +func (x *ListAdminsRequest) GetOrderBy() string { + if x != nil { + return x.OrderBy + } + return "" +} + +// CreateAdminRequest is the request message for the CreateAdmin method. +type CreateAdminRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required. The admin to create. + Admin *Admin `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAdminRequest) Reset() { + *x = CreateAdminRequest{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAdminRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAdminRequest) ProtoMessage() {} + +func (x *CreateAdminRequest) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAdminRequest.ProtoReflect.Descriptor instead. +func (*CreateAdminRequest) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{5} +} + +func (x *CreateAdminRequest) GetAdmin() *Admin { + if x != nil { + return x.Admin + } + return nil +} + +// UpdateAdminRequest is the request message for the UpdateAdmin method. +type UpdateAdminRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required. The admin to update. + Admin *Admin `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty"` + // Required. Mask of fields to update. + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAdminRequest) Reset() { + *x = UpdateAdminRequest{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAdminRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAdminRequest) ProtoMessage() {} + +func (x *UpdateAdminRequest) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAdminRequest.ProtoReflect.Descriptor instead. +func (*UpdateAdminRequest) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateAdminRequest) GetAdmin() *Admin { + if x != nil { + return x.Admin + } + return nil +} + +func (x *UpdateAdminRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +// DeleteAdminRequest is the request message for the DeleteAdmin method. +type DeleteAdminRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required. The ID of the admin to delete. + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAdminRequest) Reset() { + *x = DeleteAdminRequest{} + mi := &file_kratos_admin_v1_admin_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAdminRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAdminRequest) ProtoMessage() {} + +func (x *DeleteAdminRequest) ProtoReflect() protoreflect.Message { + mi := &file_kratos_admin_v1_admin_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAdminRequest.ProtoReflect.Descriptor instead. +func (*DeleteAdminRequest) Descriptor() ([]byte, []int) { + return file_kratos_admin_v1_admin_proto_rawDescGZIP(), []int{7} +} + +func (x *DeleteAdminRequest) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +var File_kratos_admin_v1_admin_proto protoreflect.FileDescriptor + +const file_kratos_admin_v1_admin_proto_rawDesc = "" + + "\n" + + "\x1bkratos/admin/v1/admin.proto\x12\x0fkratos.admin.v1\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a google/protobuf/field_mask.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/api/field_behavior.proto\"\x9d\x02\n" + + "\x05Admin\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05email\x18\x03 \x01(\tR\x05email\x12\x14\n" + + "\x05phone\x18\x04 \x01(\tR\x05phone\x12\x16\n" + + "\x06avatar\x18\x05 \x01(\tR\x06avatar\x12\x16\n" + + "\x06access\x18\x06 \x01(\tR\x06access\x12\x1a\n" + + "\bpassword\x18\a \x01(\tR\bpassword\x12;\n" + + "\vcreate_time\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "createTime\x12;\n" + + "\vupdate_time\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "updateTime\"b\n" + + "\bAdminSet\x12.\n" + + "\x06admins\x18\x01 \x03(\v2\x16.kratos.admin.v1.AdminR\x06admins\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"r\n" + + "\fLoginRequest\x12 \n" + + "\bpassword\x18\x01 \x01(\tB\x04\xe2A\x01\x02R\bpassword\x12\x1c\n" + + "\busername\x18\x02 \x01(\tH\x00R\busername\x12\x16\n" + + "\x05email\x18\x03 \x01(\tH\x00R\x05emailB\n" + + "\n" + + "\bidentity\"'\n" + + "\x0fGetAdminRequest\x12\x14\n" + + "\x02id\x18\x01 \x01(\x03B\x04\xe2A\x01\x02R\x02id\"\x82\x01\n" + + "\x11ListAdminsRequest\x12\x1b\n" + + "\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" + + "\n" + + "page_token\x18\x02 \x01(\tR\tpageToken\x12\x16\n" + + "\x06filter\x18\x03 \x01(\tR\x06filter\x12\x19\n" + + "\border_by\x18\x04 \x01(\tR\aorderBy\"H\n" + + "\x12CreateAdminRequest\x122\n" + + "\x05admin\x18\x01 \x01(\v2\x16.kratos.admin.v1.AdminB\x04\xe2A\x01\x02R\x05admin\"\x8b\x01\n" + + "\x12UpdateAdminRequest\x122\n" + + "\x05admin\x18\x01 \x01(\v2\x16.kratos.admin.v1.AdminB\x04\xe2A\x01\x02R\x05admin\x12A\n" + + "\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskB\x04\xe2A\x01\x02R\n" + + "updateMask\"*\n" + + "\x12DeleteAdminRequest\x12\x14\n" + + "\x02id\x18\x01 \x01(\x03B\x04\xe2A\x01\x02R\x02id2\xa0\x06\n" + + "\fAdminService\x12[\n" + + "\x05Login\x12\x1d.kratos.admin.v1.LoginRequest\x1a\x16.kratos.admin.v1.Admin\"\x1b\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/v1/admins/login\x12V\n" + + "\x06Logout\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/v1/admins/logout\x12U\n" + + "\aCurrent\x12\x16.google.protobuf.Empty\x1a\x16.kratos.admin.v1.Admin\"\x1a\x82\xd3\xe4\x93\x02\x14\x12\x12/v1/admins/current\x12d\n" + + "\n" + + "ListAdmins\x12\".kratos.admin.v1.ListAdminsRequest\x1a\x19.kratos.admin.v1.AdminSet\"\x17\x82\xd3\xe4\x93\x02\x11\x12\x0f/v1/admins/list\x12l\n" + + "\vCreateAdmin\x12#.kratos.admin.v1.CreateAdminRequest\x1a\x16.kratos.admin.v1.Admin\" \x82\xd3\xe4\x93\x02\x1a:\x05admin\"\x11/v1/admins/create\x12l\n" + + "\vUpdateAdmin\x12#.kratos.admin.v1.UpdateAdminRequest\x1a\x16.kratos.admin.v1.Admin\" \x82\xd3\xe4\x93\x02\x1a:\x05admin\x1a\x11/v1/admins/update\x12c\n" + + "\vDeleteAdmin\x12#.kratos.admin.v1.DeleteAdminRequest\x1a\x16.google.protobuf.Empty\"\x17\x82\xd3\xe4\x93\x02\x11*\x0f/v1/admins/{id}\x12]\n" + + "\bGetAdmin\x12 .kratos.admin.v1.GetAdminRequest\x1a\x16.kratos.admin.v1.Admin\"\x17\x82\xd3\xe4\x93\x02\x11\x12\x0f/v1/admins/{id}BQ\n" + + "\x13api.kratos.admin.v1P\x01Z8kra/api/kratos/admin/v1;v1b\x06proto3" + +var ( + file_kratos_admin_v1_admin_proto_rawDescOnce sync.Once + file_kratos_admin_v1_admin_proto_rawDescData []byte +) + +func file_kratos_admin_v1_admin_proto_rawDescGZIP() []byte { + file_kratos_admin_v1_admin_proto_rawDescOnce.Do(func() { + file_kratos_admin_v1_admin_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_kratos_admin_v1_admin_proto_rawDesc), len(file_kratos_admin_v1_admin_proto_rawDesc))) + }) + return file_kratos_admin_v1_admin_proto_rawDescData +} + +var file_kratos_admin_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_kratos_admin_v1_admin_proto_goTypes = []any{ + (*Admin)(nil), // 0: kratos.admin.v1.Admin + (*AdminSet)(nil), // 1: kratos.admin.v1.AdminSet + (*LoginRequest)(nil), // 2: kratos.admin.v1.LoginRequest + (*GetAdminRequest)(nil), // 3: kratos.admin.v1.GetAdminRequest + (*ListAdminsRequest)(nil), // 4: kratos.admin.v1.ListAdminsRequest + (*CreateAdminRequest)(nil), // 5: kratos.admin.v1.CreateAdminRequest + (*UpdateAdminRequest)(nil), // 6: kratos.admin.v1.UpdateAdminRequest + (*DeleteAdminRequest)(nil), // 7: kratos.admin.v1.DeleteAdminRequest + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*fieldmaskpb.FieldMask)(nil), // 9: google.protobuf.FieldMask + (*emptypb.Empty)(nil), // 10: google.protobuf.Empty +} +var file_kratos_admin_v1_admin_proto_depIdxs = []int32{ + 8, // 0: kratos.admin.v1.Admin.create_time:type_name -> google.protobuf.Timestamp + 8, // 1: kratos.admin.v1.Admin.update_time:type_name -> google.protobuf.Timestamp + 0, // 2: kratos.admin.v1.AdminSet.admins:type_name -> kratos.admin.v1.Admin + 0, // 3: kratos.admin.v1.CreateAdminRequest.admin:type_name -> kratos.admin.v1.Admin + 0, // 4: kratos.admin.v1.UpdateAdminRequest.admin:type_name -> kratos.admin.v1.Admin + 9, // 5: kratos.admin.v1.UpdateAdminRequest.update_mask:type_name -> google.protobuf.FieldMask + 2, // 6: kratos.admin.v1.AdminService.Login:input_type -> kratos.admin.v1.LoginRequest + 10, // 7: kratos.admin.v1.AdminService.Logout:input_type -> google.protobuf.Empty + 10, // 8: kratos.admin.v1.AdminService.Current:input_type -> google.protobuf.Empty + 4, // 9: kratos.admin.v1.AdminService.ListAdmins:input_type -> kratos.admin.v1.ListAdminsRequest + 5, // 10: kratos.admin.v1.AdminService.CreateAdmin:input_type -> kratos.admin.v1.CreateAdminRequest + 6, // 11: kratos.admin.v1.AdminService.UpdateAdmin:input_type -> kratos.admin.v1.UpdateAdminRequest + 7, // 12: kratos.admin.v1.AdminService.DeleteAdmin:input_type -> kratos.admin.v1.DeleteAdminRequest + 3, // 13: kratos.admin.v1.AdminService.GetAdmin:input_type -> kratos.admin.v1.GetAdminRequest + 0, // 14: kratos.admin.v1.AdminService.Login:output_type -> kratos.admin.v1.Admin + 10, // 15: kratos.admin.v1.AdminService.Logout:output_type -> google.protobuf.Empty + 0, // 16: kratos.admin.v1.AdminService.Current:output_type -> kratos.admin.v1.Admin + 1, // 17: kratos.admin.v1.AdminService.ListAdmins:output_type -> kratos.admin.v1.AdminSet + 0, // 18: kratos.admin.v1.AdminService.CreateAdmin:output_type -> kratos.admin.v1.Admin + 0, // 19: kratos.admin.v1.AdminService.UpdateAdmin:output_type -> kratos.admin.v1.Admin + 10, // 20: kratos.admin.v1.AdminService.DeleteAdmin:output_type -> google.protobuf.Empty + 0, // 21: kratos.admin.v1.AdminService.GetAdmin:output_type -> kratos.admin.v1.Admin + 14, // [14:22] is the sub-list for method output_type + 6, // [6:14] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_kratos_admin_v1_admin_proto_init() } +func file_kratos_admin_v1_admin_proto_init() { + if File_kratos_admin_v1_admin_proto != nil { + return + } + file_kratos_admin_v1_admin_proto_msgTypes[2].OneofWrappers = []any{ + (*LoginRequest_Username)(nil), + (*LoginRequest_Email)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_kratos_admin_v1_admin_proto_rawDesc), len(file_kratos_admin_v1_admin_proto_rawDesc)), + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_kratos_admin_v1_admin_proto_goTypes, + DependencyIndexes: file_kratos_admin_v1_admin_proto_depIdxs, + MessageInfos: file_kratos_admin_v1_admin_proto_msgTypes, + }.Build() + File_kratos_admin_v1_admin_proto = out.File + file_kratos_admin_v1_admin_proto_goTypes = nil + file_kratos_admin_v1_admin_proto_depIdxs = nil +} diff --git a/api/kratos/admin/v1/admin.proto b/api/kratos/admin/v1/admin.proto new file mode 100644 index 0000000..3685257 --- /dev/null +++ b/api/kratos/admin/v1/admin.proto @@ -0,0 +1,161 @@ +syntax = "proto3"; + +package kratos.admin.v1; + +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/field_mask.proto"; +import "google/api/annotations.proto"; +import "google/api/field_behavior.proto"; + +option go_package = "kra/api/kratos/admin/v1;v1"; +option java_multiple_files = true; +option java_package = "api.kratos.admin.v1"; + +// Admin is the admin message. +message Admin { + // The unique ID of the user. + int64 id = 1; + // The name of the user. + string name = 2; + // The email of the user. + string email = 3; + // The phone number of the user. + string phone = 4; + // The avatar URL of the user. + string avatar = 5; + // The access level of the user. + // Possible values are: "admin", "user", etc. + string access = 6; + // The password of the user. + string password = 7; + // The timestamp at which the user was created. + google.protobuf.Timestamp create_time = 8; + // The latest timestamp at which the user was updated. + google.protobuf.Timestamp update_time = 9; +} + +// AdminSet is the set of admins. +message AdminSet { + // The set of admins. + repeated Admin admins = 1; + // The next page token. + string next_page_token = 2; +} + +// AdminService is the admin service definition. +service AdminService { + // Login a user and return the username. + rpc Login (LoginRequest) returns (Admin) { + option (google.api.http) = { + post: "/v1/admins/login" + body: "*" + }; + } + // Logout the currently logged-in user. + rpc Logout (google.protobuf.Empty) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/admins/logout" + body: "*" + }; + } + // Current returns the currently logged-in user. + rpc Current (google.protobuf.Empty) returns (Admin) { + option (google.api.http) = { + get: "/v1/admins/current" + }; + } + // ListAdmins returns a list of admins. + rpc ListAdmins(ListAdminsRequest) returns (AdminSet) { + option (google.api.http) = { + get: "/v1/admins/list" + }; + } + // CreateAdmin creates a new admin. + rpc CreateAdmin(CreateAdminRequest) returns (Admin) { + option (google.api.http) = { + post: "/v1/admins/create" + body: "admin" + }; + } + // UpdateAdmin updates an existing admin. + rpc UpdateAdmin(UpdateAdminRequest) returns (Admin) { + option (google.api.http) = { + put: "/v1/admins/update" + body: "admin" + }; + } + // DeleteAdmin deletes an admin by ID. + rpc DeleteAdmin(DeleteAdminRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1/admins/{id}" + }; + } + // GetAdmin retrieves an admin by ID. + rpc GetAdmin(GetAdminRequest) returns (Admin) { + option (google.api.http) = { + get: "/v1/admins/{id}" + }; + } +} + +// LoginRequest is the request message for the Login method. +message LoginRequest { + // Required. Password of the user. + string password = 1 [(google.api.field_behavior) = REQUIRED]; + // Required. Exactly one identity must be set. + oneof identity { + string username = 2; + string email = 3; + } +} + +// GetAdminRequest is the request message for the GetAdmin method. +message GetAdminRequest { + // The ID of the admin to retrieve. + int64 id = 1 [(google.api.field_behavior) = REQUIRED]; +} + +// ListAdminsResponse is the response message for the ListAdmins method. +message ListAdminsRequest { + // Optional. The number of admins per page. + int32 page_size = 1; + // Optional. The page token. + string page_token = 2; + // Optional. The standard list filter. + // Supported fields: + // * `name` (i.e. `name="John Doe"`) + // * `email` (i.e. `email="admin@go-kratos.dev"`) + // * `phone` (i.e. `phone="+1234567890"`) + // * `create_time` range (i.e. `timestamp>="2025-01-31T11:30:00-04:00"` where + // the timestamp is in RFC 3339 format) + // + // More detail in [AIP-160](https://google.aip.dev/160). + string filter = 3; + // Optional. A comma-separated list of fields to order by, sorted in ascending + // order. Use "desc" after a field name for descending. Supported fields: + // - `create_time` + // + // Example: `create_time desc`. + string order_by = 4; +} + +// CreateAdminRequest is the request message for the CreateAdmin method. +message CreateAdminRequest { + // Required. The admin to create. + Admin admin = 1 [(google.api.field_behavior) = REQUIRED]; +} + +// UpdateAdminRequest is the request message for the UpdateAdmin method. +message UpdateAdminRequest { + // Required. The admin to update. + Admin admin = 1 [(google.api.field_behavior) = REQUIRED]; + // Required. Mask of fields to update. + google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// DeleteAdminRequest is the request message for the DeleteAdmin method. +message DeleteAdminRequest { + // Required. The ID of the admin to delete. + int64 id = 1 [(google.api.field_behavior) = REQUIRED]; +} diff --git a/api/kratos/admin/v1/admin_grpc.pb.go b/api/kratos/admin/v1/admin_grpc.pb.go new file mode 100644 index 0000000..db70f31 --- /dev/null +++ b/api/kratos/admin/v1/admin_grpc.pb.go @@ -0,0 +1,408 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.0 +// - protoc v4.23.2 +// source: kratos/admin/v1/admin.proto + +package v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// 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.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + AdminService_Login_FullMethodName = "/kratos.admin.v1.AdminService/Login" + AdminService_Logout_FullMethodName = "/kratos.admin.v1.AdminService/Logout" + AdminService_Current_FullMethodName = "/kratos.admin.v1.AdminService/Current" + AdminService_ListAdmins_FullMethodName = "/kratos.admin.v1.AdminService/ListAdmins" + AdminService_CreateAdmin_FullMethodName = "/kratos.admin.v1.AdminService/CreateAdmin" + AdminService_UpdateAdmin_FullMethodName = "/kratos.admin.v1.AdminService/UpdateAdmin" + AdminService_DeleteAdmin_FullMethodName = "/kratos.admin.v1.AdminService/DeleteAdmin" + AdminService_GetAdmin_FullMethodName = "/kratos.admin.v1.AdminService/GetAdmin" +) + +// AdminServiceClient is the client API for AdminService 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. +// +// AdminService is the admin service definition. +type AdminServiceClient interface { + // Login a user and return the username. + Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*Admin, error) + // Logout the currently logged-in user. + Logout(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) + // Current returns the currently logged-in user. + Current(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Admin, error) + // ListAdmins returns a list of admins. + ListAdmins(ctx context.Context, in *ListAdminsRequest, opts ...grpc.CallOption) (*AdminSet, error) + // CreateAdmin creates a new admin. + CreateAdmin(ctx context.Context, in *CreateAdminRequest, opts ...grpc.CallOption) (*Admin, error) + // UpdateAdmin updates an existing admin. + UpdateAdmin(ctx context.Context, in *UpdateAdminRequest, opts ...grpc.CallOption) (*Admin, error) + // DeleteAdmin deletes an admin by ID. + DeleteAdmin(ctx context.Context, in *DeleteAdminRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // GetAdmin retrieves an admin by ID. + GetAdmin(ctx context.Context, in *GetAdminRequest, opts ...grpc.CallOption) (*Admin, error) +} + +type adminServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAdminServiceClient(cc grpc.ClientConnInterface) AdminServiceClient { + return &adminServiceClient{cc} +} + +func (c *adminServiceClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*Admin, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Admin) + err := c.cc.Invoke(ctx, AdminService_Login_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) Logout(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, AdminService_Logout_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) Current(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Admin, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Admin) + err := c.cc.Invoke(ctx, AdminService_Current_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) ListAdmins(ctx context.Context, in *ListAdminsRequest, opts ...grpc.CallOption) (*AdminSet, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AdminSet) + err := c.cc.Invoke(ctx, AdminService_ListAdmins_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) CreateAdmin(ctx context.Context, in *CreateAdminRequest, opts ...grpc.CallOption) (*Admin, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Admin) + err := c.cc.Invoke(ctx, AdminService_CreateAdmin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) UpdateAdmin(ctx context.Context, in *UpdateAdminRequest, opts ...grpc.CallOption) (*Admin, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Admin) + err := c.cc.Invoke(ctx, AdminService_UpdateAdmin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) DeleteAdmin(ctx context.Context, in *DeleteAdminRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, AdminService_DeleteAdmin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) GetAdmin(ctx context.Context, in *GetAdminRequest, opts ...grpc.CallOption) (*Admin, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Admin) + err := c.cc.Invoke(ctx, AdminService_GetAdmin_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdminServiceServer is the server API for AdminService service. +// All implementations must embed UnimplementedAdminServiceServer +// for forward compatibility. +// +// AdminService is the admin service definition. +type AdminServiceServer interface { + // Login a user and return the username. + Login(context.Context, *LoginRequest) (*Admin, error) + // Logout the currently logged-in user. + Logout(context.Context, *emptypb.Empty) (*emptypb.Empty, error) + // Current returns the currently logged-in user. + Current(context.Context, *emptypb.Empty) (*Admin, error) + // ListAdmins returns a list of admins. + ListAdmins(context.Context, *ListAdminsRequest) (*AdminSet, error) + // CreateAdmin creates a new admin. + CreateAdmin(context.Context, *CreateAdminRequest) (*Admin, error) + // UpdateAdmin updates an existing admin. + UpdateAdmin(context.Context, *UpdateAdminRequest) (*Admin, error) + // DeleteAdmin deletes an admin by ID. + DeleteAdmin(context.Context, *DeleteAdminRequest) (*emptypb.Empty, error) + // GetAdmin retrieves an admin by ID. + GetAdmin(context.Context, *GetAdminRequest) (*Admin, error) + mustEmbedUnimplementedAdminServiceServer() +} + +// UnimplementedAdminServiceServer 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 UnimplementedAdminServiceServer struct{} + +func (UnimplementedAdminServiceServer) Login(context.Context, *LoginRequest) (*Admin, error) { + return nil, status.Error(codes.Unimplemented, "method Login not implemented") +} +func (UnimplementedAdminServiceServer) Logout(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { + return nil, status.Error(codes.Unimplemented, "method Logout not implemented") +} +func (UnimplementedAdminServiceServer) Current(context.Context, *emptypb.Empty) (*Admin, error) { + return nil, status.Error(codes.Unimplemented, "method Current not implemented") +} +func (UnimplementedAdminServiceServer) ListAdmins(context.Context, *ListAdminsRequest) (*AdminSet, error) { + return nil, status.Error(codes.Unimplemented, "method ListAdmins not implemented") +} +func (UnimplementedAdminServiceServer) CreateAdmin(context.Context, *CreateAdminRequest) (*Admin, error) { + return nil, status.Error(codes.Unimplemented, "method CreateAdmin not implemented") +} +func (UnimplementedAdminServiceServer) UpdateAdmin(context.Context, *UpdateAdminRequest) (*Admin, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateAdmin not implemented") +} +func (UnimplementedAdminServiceServer) DeleteAdmin(context.Context, *DeleteAdminRequest) (*emptypb.Empty, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteAdmin not implemented") +} +func (UnimplementedAdminServiceServer) GetAdmin(context.Context, *GetAdminRequest) (*Admin, error) { + return nil, status.Error(codes.Unimplemented, "method GetAdmin not implemented") +} +func (UnimplementedAdminServiceServer) mustEmbedUnimplementedAdminServiceServer() {} +func (UnimplementedAdminServiceServer) testEmbeddedByValue() {} + +// UnsafeAdminServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AdminServiceServer will +// result in compilation errors. +type UnsafeAdminServiceServer interface { + mustEmbedUnimplementedAdminServiceServer() +} + +func RegisterAdminServiceServer(s grpc.ServiceRegistrar, srv AdminServiceServer) { + // If the following call panics, it indicates UnimplementedAdminServiceServer 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(&AdminService_ServiceDesc, srv) +} + +func _AdminService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LoginRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Login(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Login_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Login(ctx, req.(*LoginRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_Logout_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Logout(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Logout_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Logout(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_Current_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Current(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Current_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Current(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_ListAdmins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAdminsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).ListAdmins(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_ListAdmins_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).ListAdmins(ctx, req.(*ListAdminsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_CreateAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAdminRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).CreateAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_CreateAdmin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).CreateAdmin(ctx, req.(*CreateAdminRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_UpdateAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAdminRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).UpdateAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_UpdateAdmin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).UpdateAdmin(ctx, req.(*UpdateAdminRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_DeleteAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteAdminRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).DeleteAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_DeleteAdmin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).DeleteAdmin(ctx, req.(*DeleteAdminRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_GetAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAdminRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).GetAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_GetAdmin_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).GetAdmin(ctx, req.(*GetAdminRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AdminService_ServiceDesc is the grpc.ServiceDesc for AdminService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AdminService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "kratos.admin.v1.AdminService", + HandlerType: (*AdminServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Login", + Handler: _AdminService_Login_Handler, + }, + { + MethodName: "Logout", + Handler: _AdminService_Logout_Handler, + }, + { + MethodName: "Current", + Handler: _AdminService_Current_Handler, + }, + { + MethodName: "ListAdmins", + Handler: _AdminService_ListAdmins_Handler, + }, + { + MethodName: "CreateAdmin", + Handler: _AdminService_CreateAdmin_Handler, + }, + { + MethodName: "UpdateAdmin", + Handler: _AdminService_UpdateAdmin_Handler, + }, + { + MethodName: "DeleteAdmin", + Handler: _AdminService_DeleteAdmin_Handler, + }, + { + MethodName: "GetAdmin", + Handler: _AdminService_GetAdmin_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "kratos/admin/v1/admin.proto", +} diff --git a/api/kratos/admin/v1/admin_http.pb.go b/api/kratos/admin/v1/admin_http.pb.go new file mode 100644 index 0000000..cf39ecb --- /dev/null +++ b/api/kratos/admin/v1/admin_http.pb.go @@ -0,0 +1,370 @@ +// Code generated by protoc-gen-go-http. DO NOT EDIT. +// versions: +// - protoc-gen-go-http v2.9.2 +// - protoc v4.23.2 +// source: kratos/admin/v1/admin.proto + +package v1 + +import ( + context "context" + http "github.com/go-kratos/kratos/v2/transport/http" + binding "github.com/go-kratos/kratos/v2/transport/http/binding" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the kratos package it is being compiled against. +var _ = new(context.Context) +var _ = binding.EncodeURL + +const _ = http.SupportPackageIsVersion1 + +const OperationAdminServiceCreateAdmin = "/kratos.admin.v1.AdminService/CreateAdmin" +const OperationAdminServiceCurrent = "/kratos.admin.v1.AdminService/Current" +const OperationAdminServiceDeleteAdmin = "/kratos.admin.v1.AdminService/DeleteAdmin" +const OperationAdminServiceGetAdmin = "/kratos.admin.v1.AdminService/GetAdmin" +const OperationAdminServiceListAdmins = "/kratos.admin.v1.AdminService/ListAdmins" +const OperationAdminServiceLogin = "/kratos.admin.v1.AdminService/Login" +const OperationAdminServiceLogout = "/kratos.admin.v1.AdminService/Logout" +const OperationAdminServiceUpdateAdmin = "/kratos.admin.v1.AdminService/UpdateAdmin" + +type AdminServiceHTTPServer interface { + // CreateAdmin CreateAdmin creates a new admin. + CreateAdmin(context.Context, *CreateAdminRequest) (*Admin, error) + // Current Current returns the currently logged-in user. + Current(context.Context, *emptypb.Empty) (*Admin, error) + // DeleteAdmin DeleteAdmin deletes an admin by ID. + DeleteAdmin(context.Context, *DeleteAdminRequest) (*emptypb.Empty, error) + // GetAdmin GetAdmin retrieves an admin by ID. + GetAdmin(context.Context, *GetAdminRequest) (*Admin, error) + // ListAdmins ListAdmins returns a list of admins. + ListAdmins(context.Context, *ListAdminsRequest) (*AdminSet, error) + // Login Login a user and return the username. + Login(context.Context, *LoginRequest) (*Admin, error) + // Logout Logout the currently logged-in user. + Logout(context.Context, *emptypb.Empty) (*emptypb.Empty, error) + // UpdateAdmin UpdateAdmin updates an existing admin. + UpdateAdmin(context.Context, *UpdateAdminRequest) (*Admin, error) +} + +func RegisterAdminServiceHTTPServer(s *http.Server, srv AdminServiceHTTPServer) { + r := s.Route("/") + r.POST("/v1/admins/login", _AdminService_Login0_HTTP_Handler(srv)) + r.POST("/v1/admins/logout", _AdminService_Logout0_HTTP_Handler(srv)) + r.GET("/v1/admins/current", _AdminService_Current0_HTTP_Handler(srv)) + r.GET("/v1/admins/list", _AdminService_ListAdmins0_HTTP_Handler(srv)) + r.POST("/v1/admins/create", _AdminService_CreateAdmin0_HTTP_Handler(srv)) + r.PUT("/v1/admins/update", _AdminService_UpdateAdmin0_HTTP_Handler(srv)) + r.DELETE("/v1/admins/{id}", _AdminService_DeleteAdmin0_HTTP_Handler(srv)) + r.GET("/v1/admins/{id}", _AdminService_GetAdmin0_HTTP_Handler(srv)) +} + +func _AdminService_Login0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in LoginRequest + if err := ctx.Bind(&in); err != nil { + return err + } + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceLogin) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Login(ctx, req.(*LoginRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*Admin) + return ctx.Result(200, reply) + } +} + +func _AdminService_Logout0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in emptypb.Empty + if err := ctx.Bind(&in); err != nil { + return err + } + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceLogout) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Logout(ctx, req.(*emptypb.Empty)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*emptypb.Empty) + return ctx.Result(200, reply) + } +} + +func _AdminService_Current0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in emptypb.Empty + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceCurrent) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Current(ctx, req.(*emptypb.Empty)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*Admin) + return ctx.Result(200, reply) + } +} + +func _AdminService_ListAdmins0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in ListAdminsRequest + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceListAdmins) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.ListAdmins(ctx, req.(*ListAdminsRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*AdminSet) + return ctx.Result(200, reply) + } +} + +func _AdminService_CreateAdmin0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in CreateAdminRequest + if err := ctx.Bind(&in.Admin); err != nil { + return err + } + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceCreateAdmin) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.CreateAdmin(ctx, req.(*CreateAdminRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*Admin) + return ctx.Result(200, reply) + } +} + +func _AdminService_UpdateAdmin0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in UpdateAdminRequest + if err := ctx.Bind(&in.Admin); err != nil { + return err + } + if err := ctx.BindQuery(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceUpdateAdmin) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.UpdateAdmin(ctx, req.(*UpdateAdminRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*Admin) + return ctx.Result(200, reply) + } +} + +func _AdminService_DeleteAdmin0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in DeleteAdminRequest + if err := ctx.BindQuery(&in); err != nil { + return err + } + if err := ctx.BindVars(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceDeleteAdmin) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.DeleteAdmin(ctx, req.(*DeleteAdminRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*emptypb.Empty) + return ctx.Result(200, reply) + } +} + +func _AdminService_GetAdmin0_HTTP_Handler(srv AdminServiceHTTPServer) func(ctx http.Context) error { + return func(ctx http.Context) error { + var in GetAdminRequest + if err := ctx.BindQuery(&in); err != nil { + return err + } + if err := ctx.BindVars(&in); err != nil { + return err + } + http.SetOperation(ctx, OperationAdminServiceGetAdmin) + h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.GetAdmin(ctx, req.(*GetAdminRequest)) + }) + out, err := h(ctx, &in) + if err != nil { + return err + } + reply := out.(*Admin) + return ctx.Result(200, reply) + } +} + +type AdminServiceHTTPClient interface { + // CreateAdmin CreateAdmin creates a new admin. + CreateAdmin(ctx context.Context, req *CreateAdminRequest, opts ...http.CallOption) (rsp *Admin, err error) + // Current Current returns the currently logged-in user. + Current(ctx context.Context, req *emptypb.Empty, opts ...http.CallOption) (rsp *Admin, err error) + // DeleteAdmin DeleteAdmin deletes an admin by ID. + DeleteAdmin(ctx context.Context, req *DeleteAdminRequest, opts ...http.CallOption) (rsp *emptypb.Empty, err error) + // GetAdmin GetAdmin retrieves an admin by ID. + GetAdmin(ctx context.Context, req *GetAdminRequest, opts ...http.CallOption) (rsp *Admin, err error) + // ListAdmins ListAdmins returns a list of admins. + ListAdmins(ctx context.Context, req *ListAdminsRequest, opts ...http.CallOption) (rsp *AdminSet, err error) + // Login Login a user and return the username. + Login(ctx context.Context, req *LoginRequest, opts ...http.CallOption) (rsp *Admin, err error) + // Logout Logout the currently logged-in user. + Logout(ctx context.Context, req *emptypb.Empty, opts ...http.CallOption) (rsp *emptypb.Empty, err error) + // UpdateAdmin UpdateAdmin updates an existing admin. + UpdateAdmin(ctx context.Context, req *UpdateAdminRequest, opts ...http.CallOption) (rsp *Admin, err error) +} + +type AdminServiceHTTPClientImpl struct { + cc *http.Client +} + +func NewAdminServiceHTTPClient(client *http.Client) AdminServiceHTTPClient { + return &AdminServiceHTTPClientImpl{client} +} + +// CreateAdmin CreateAdmin creates a new admin. +func (c *AdminServiceHTTPClientImpl) CreateAdmin(ctx context.Context, in *CreateAdminRequest, opts ...http.CallOption) (*Admin, error) { + var out Admin + pattern := "/v1/admins/create" + path := binding.EncodeURL(pattern, in, false) + opts = append(opts, http.Operation(OperationAdminServiceCreateAdmin)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "POST", path, in.Admin, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// Current Current returns the currently logged-in user. +func (c *AdminServiceHTTPClientImpl) Current(ctx context.Context, in *emptypb.Empty, opts ...http.CallOption) (*Admin, error) { + var out Admin + pattern := "/v1/admins/current" + path := binding.EncodeURL(pattern, in, true) + opts = append(opts, http.Operation(OperationAdminServiceCurrent)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// DeleteAdmin DeleteAdmin deletes an admin by ID. +func (c *AdminServiceHTTPClientImpl) DeleteAdmin(ctx context.Context, in *DeleteAdminRequest, opts ...http.CallOption) (*emptypb.Empty, error) { + var out emptypb.Empty + pattern := "/v1/admins/{id}" + path := binding.EncodeURL(pattern, in, true) + opts = append(opts, http.Operation(OperationAdminServiceDeleteAdmin)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "DELETE", path, nil, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// GetAdmin GetAdmin retrieves an admin by ID. +func (c *AdminServiceHTTPClientImpl) GetAdmin(ctx context.Context, in *GetAdminRequest, opts ...http.CallOption) (*Admin, error) { + var out Admin + pattern := "/v1/admins/{id}" + path := binding.EncodeURL(pattern, in, true) + opts = append(opts, http.Operation(OperationAdminServiceGetAdmin)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// ListAdmins ListAdmins returns a list of admins. +func (c *AdminServiceHTTPClientImpl) ListAdmins(ctx context.Context, in *ListAdminsRequest, opts ...http.CallOption) (*AdminSet, error) { + var out AdminSet + pattern := "/v1/admins/list" + path := binding.EncodeURL(pattern, in, true) + opts = append(opts, http.Operation(OperationAdminServiceListAdmins)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// Login Login a user and return the username. +func (c *AdminServiceHTTPClientImpl) Login(ctx context.Context, in *LoginRequest, opts ...http.CallOption) (*Admin, error) { + var out Admin + pattern := "/v1/admins/login" + path := binding.EncodeURL(pattern, in, false) + opts = append(opts, http.Operation(OperationAdminServiceLogin)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// Logout Logout the currently logged-in user. +func (c *AdminServiceHTTPClientImpl) Logout(ctx context.Context, in *emptypb.Empty, opts ...http.CallOption) (*emptypb.Empty, error) { + var out emptypb.Empty + pattern := "/v1/admins/logout" + path := binding.EncodeURL(pattern, in, false) + opts = append(opts, http.Operation(OperationAdminServiceLogout)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} + +// UpdateAdmin UpdateAdmin updates an existing admin. +func (c *AdminServiceHTTPClientImpl) UpdateAdmin(ctx context.Context, in *UpdateAdminRequest, opts ...http.CallOption) (*Admin, error) { + var out Admin + pattern := "/v1/admins/update" + path := binding.EncodeURL(pattern, in, false) + opts = append(opts, http.Operation(OperationAdminServiceUpdateAdmin)) + opts = append(opts, http.PathTemplate(pattern)) + err := c.cc.Invoke(ctx, "PUT", path, in.Admin, &out, opts...) + if err != nil { + return nil, err + } + return &out, nil +} diff --git a/configs/config.yaml b/configs/config.yaml new file mode 100644 index 0000000..5e5453e --- /dev/null +++ b/configs/config.yaml @@ -0,0 +1,15 @@ +server: + http: + addr: 0.0.0.0:8000 + timeout: 1s + grpc: + addr: 0.0.0.0:9000 + timeout: 1s +data: + database: + driver: mysql + source: root:root@tcp(127.0.0.1:3306)/test?timeout=5s&parseTime=True&loc=Local&charset=utf8mb4 + redis: + addr: 127.0.0.1:6379 + read_timeout: 0.2s + write_timeout: 0.2s diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..13bbba9 --- /dev/null +++ b/go.mod @@ -0,0 +1,50 @@ +module kra + +go 1.24.6 + +require ( + entgo.io/ent v0.14.5 + github.com/go-kratos/aip-go/ents v0.0.0-20251213081434-74ffa1fc1588 + github.com/go-kratos/kratos/v2 v2.8.0 + github.com/go-sql-driver/mysql v1.9.3 + github.com/golang-jwt/jwt/v5 v5.1.0 + github.com/google/uuid v1.6.0 + github.com/google/wire v0.6.0 + go.einride.tech/aip v0.76.0 + go.uber.org/automaxprocs v1.5.1 + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 + google.golang.org/grpc v1.74.2 + google.golang.org/protobuf v1.36.10 +) + +require ( + ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9 // indirect + dario.cat/mergo v1.0.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/agext/levenshtein v1.2.3 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/bmatcuk/doublestar v1.3.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-kratos/aegis v0.2.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/inflect v0.19.0 // indirect + github.com/go-playground/form/v4 v4.2.1 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/hashicorp/hcl/v2 v2.18.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/zclconf/go-cty v1.14.4 // indirect + github.com/zclconf/go-cty-yaml v1.1.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.36.0 // indirect + go.opentelemetry.io/otel/metric v1.36.0 // indirect + go.opentelemetry.io/otel/trace v1.36.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dbd0755 --- /dev/null +++ b/go.sum @@ -0,0 +1,186 @@ +ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9 h1:E0wvcUXTkgyN4wy4LGtNzMNGMytJN8afmIWXJVMi4cc= +ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +entgo.io/ent v0.14.5 h1:Rj2WOYJtCkWyFo6a+5wB3EfBRP0rnx1fMk6gGA0UUe4= +entgo.io/ent v0.14.5/go.mod h1:zTzLmWtPvGpmSwtkaayM2cm5m819NdM7z7tYPq3vN0U= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= +github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ= +github.com/go-kratos/aegis v0.2.0/go.mod h1:v0R2m73WgEEYB3XYu6aE2WcMwsZkJ/Rzuf5eVccm7bI= +github.com/go-kratos/aip-go/ents v0.0.0-20251213081434-74ffa1fc1588 h1:e0dWyNWFeTgGCH7cRMROahTwMaQYtmHce/6fxVmA6yI= +github.com/go-kratos/aip-go/ents v0.0.0-20251213081434-74ffa1fc1588/go.mod h1:ifKMm4eJmaQz5WNKKhfClpCng8UxUB3sArof8wjwG78= +github.com/go-kratos/kratos/v2 v2.8.0 h1:qr27WRTRrI3o4jzJzNKf4XVVoMYIqnQD+4ws1C46yhM= +github.com/go-kratos/kratos/v2 v2.8.0/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/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/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= +github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/form/v4 v4.2.1 h1:HjdRDKO0fftVMU5epjPW2SOREcZ6/wLUzEobqUGJuPw= +github.com/go-playground/form/v4 v4.2.1/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= +github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo= +github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= +github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0= +github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs= +go.einride.tech/aip v0.76.0 h1:JGz5u/67eBGfM02ubGNZtsGSU0vY2zMTWRbadgEkQoM= +go.einride.tech/aip v0.76.0/go.mod h1:E8+wdTApA70odnpFzJgsGogHozC2JCIhFJBKPr8bVig= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= +go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +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= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d h1:/hmn0Ku5kWij/kjGsrcJeC1T/MrJi2iNWwgAqrihFwc= +google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +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= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= diff --git a/internal/biz/README.md b/internal/biz/README.md new file mode 100644 index 0000000..26a66b6 --- /dev/null +++ b/internal/biz/README.md @@ -0,0 +1 @@ +# Biz diff --git a/internal/biz/admin.go b/internal/biz/admin.go new file mode 100644 index 0000000..7770477 --- /dev/null +++ b/internal/biz/admin.go @@ -0,0 +1,105 @@ +package biz + +import ( + "context" + "time" + + "github.com/go-kratos/kratos/v2/errors" + "github.com/go-kratos/kratos/v2/log" +) + +// Admin is a Admin model. +type Admin struct { + ID int64 + Name string + Email string + Password string + Access string + Avatar string + CreateTime time.Time + UpdateTime time.Time +} + +// AdminRepo is a Greater repo. +type AdminRepo interface { + FindByID(context.Context, int64) (*Admin, error) + FindByName(context.Context, string) (*Admin, error) + FindByEmail(context.Context, string) (*Admin, error) + ListAdmins(context.Context, ...ListOption) ([]*Admin, error) + CreateAdmin(context.Context, *Admin) (*Admin, error) + UpdateAdmin(context.Context, *Admin) (*Admin, error) + DeleteAdmin(context.Context, int64) error +} + +// AdminUsecase is a Admin usecase. +type AdminUsecase struct { + admin AdminRepo +} + +// NewAdminUsecase new a Admin usecase. +func NewAdminUsecase(repo AdminRepo) *AdminUsecase { + return &AdminUsecase{admin: repo} +} + +// LoginByUsername logs in a user by username and password. +func (uc *AdminUsecase) LoginByUsername(ctx context.Context, username, password string) (*Admin, error) { + user, err := uc.admin.FindByName(ctx, username) + if err != nil { + return nil, err + } + if user.Password != password { + return nil, errors.Unauthorized("AUTH", "invalid credentials") + } + return user, nil +} + +// LoginByEmail logs in a user by email and password. +func (uc *AdminUsecase) LoginByEmail(ctx context.Context, username, password string) (*Admin, error) { + user, err := uc.admin.FindByEmail(ctx, username) + if err != nil { + return nil, err + } + if user.Password != password { + return nil, errors.Unauthorized("AUTH", "invalid credentials") + } + return user, nil +} + +// Logout logs out the current user. +func (uc *AdminUsecase) Logout(ctx context.Context, adminID int64) error { + admin, err := uc.admin.FindByID(ctx, adminID) + if err != nil { + return err + } + log.Infof("admin %s logged out", admin.Name) + return nil +} + +// Current returns the current logged in user. +func (uc *AdminUsecase) GetAdmin(ctx context.Context, id int64) (*Admin, error) { + return uc.admin.FindByID(ctx, id) +} + +// ListAdmins lists admin users with pagination. +func (uc *AdminUsecase) ListAdmins(ctx context.Context, opts ...ListOption) ([]*Admin, error) { + admins, err := uc.admin.ListAdmins(ctx, opts...) + if err != nil { + return nil, err + } + return admins, nil +} + +// CreateAdmin creates a new admin user. +func (uc *AdminUsecase) CreateAdmin(ctx context.Context, admin *Admin) (*Admin, error) { + return uc.admin.CreateAdmin(ctx, admin) +} + +// UpdateAdmin updates an existing admin user. +func (uc *AdminUsecase) UpdateAdmin(ctx context.Context, admin *Admin) (*Admin, error) { + return uc.admin.UpdateAdmin(ctx, admin) +} + +// DeleteAdmin deletes an admin user by ID. +func (uc *AdminUsecase) DeleteAdmin(ctx context.Context, id int64) error { + return uc.admin.DeleteAdmin(ctx, id) +} diff --git a/internal/biz/biz.go b/internal/biz/biz.go new file mode 100644 index 0000000..9eb395f --- /dev/null +++ b/internal/biz/biz.go @@ -0,0 +1,6 @@ +package biz + +import "github.com/google/wire" + +// ProviderSet is biz providers. +var ProviderSet = wire.NewSet(NewAdminUsecase) diff --git a/internal/biz/errros.go b/internal/biz/errros.go new file mode 100644 index 0000000..2ca7d70 --- /dev/null +++ b/internal/biz/errros.go @@ -0,0 +1,8 @@ +package biz + +import "github.com/go-kratos/kratos/v2/errors" + +var ( + // ErrAdminNotFound error admin not found. + ErrAdminNotFound = errors.NotFound("ADMIN", "admin not found") +) diff --git a/internal/biz/pagination.go b/internal/biz/pagination.go new file mode 100644 index 0000000..27bdbc4 --- /dev/null +++ b/internal/biz/pagination.go @@ -0,0 +1,39 @@ +package biz + +import ( + "go.einride.tech/aip/filtering" + "go.einride.tech/aip/ordering" +) + +type ListOption func(*ListOptions) + +type ListOptions struct { + Filter filtering.Filter + OrderBy ordering.OrderBy + Offset int + Limit int +} + +func ListFilter(filter filtering.Filter) ListOption { + return func(o *ListOptions) { + o.Filter = filter + } +} + +func ListOrderBy(orderBy ordering.OrderBy) ListOption { + return func(o *ListOptions) { + o.OrderBy = orderBy + } +} + +func ListOffset(offset int) ListOption { + return func(o *ListOptions) { + o.Offset = offset + } +} + +func ListLimit(limit int) ListOption { + return func(o *ListOptions) { + o.Limit = limit + } +} diff --git a/internal/conf/conf.pb.go b/internal/conf/conf.pb.go new file mode 100644 index 0000000..0ae7ff7 --- /dev/null +++ b/internal/conf/conf.pb.go @@ -0,0 +1,544 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.5 +// protoc v4.23.2 +// source: conf/conf.proto + +package conf + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Bootstrap struct { + state protoimpl.MessageState `protogen:"open.v1"` + Server *Server `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"` + Data *Data `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Bootstrap) Reset() { + *x = Bootstrap{} + mi := &file_conf_conf_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Bootstrap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bootstrap) ProtoMessage() {} + +func (x *Bootstrap) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bootstrap.ProtoReflect.Descriptor instead. +func (*Bootstrap) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{0} +} + +func (x *Bootstrap) GetServer() *Server { + if x != nil { + return x.Server + } + return nil +} + +func (x *Bootstrap) GetData() *Data { + if x != nil { + return x.Data + } + return nil +} + +type Server struct { + state protoimpl.MessageState `protogen:"open.v1"` + Http *Server_HTTP `protobuf:"bytes,1,opt,name=http,proto3" json:"http,omitempty"` + Grpc *Server_GRPC `protobuf:"bytes,2,opt,name=grpc,proto3" json:"grpc,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Server) Reset() { + *x = Server{} + mi := &file_conf_conf_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Server) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server) ProtoMessage() {} + +func (x *Server) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server.ProtoReflect.Descriptor instead. +func (*Server) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{1} +} + +func (x *Server) GetHttp() *Server_HTTP { + if x != nil { + return x.Http + } + return nil +} + +func (x *Server) GetGrpc() *Server_GRPC { + if x != nil { + return x.Grpc + } + return nil +} + +type Data struct { + state protoimpl.MessageState `protogen:"open.v1"` + Database *Data_Database `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"` + Redis *Data_Redis `protobuf:"bytes,2,opt,name=redis,proto3" json:"redis,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Data) Reset() { + *x = Data{} + mi := &file_conf_conf_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Data) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data) ProtoMessage() {} + +func (x *Data) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data.ProtoReflect.Descriptor instead. +func (*Data) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{2} +} + +func (x *Data) GetDatabase() *Data_Database { + if x != nil { + return x.Database + } + return nil +} + +func (x *Data) GetRedis() *Data_Redis { + if x != nil { + return x.Redis + } + return nil +} + +type Server_HTTP struct { + state protoimpl.MessageState `protogen:"open.v1"` + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + Timeout *durationpb.Duration `protobuf:"bytes,3,opt,name=timeout,proto3" json:"timeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Server_HTTP) Reset() { + *x = Server_HTTP{} + mi := &file_conf_conf_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Server_HTTP) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server_HTTP) ProtoMessage() {} + +func (x *Server_HTTP) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server_HTTP.ProtoReflect.Descriptor instead. +func (*Server_HTTP) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *Server_HTTP) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +func (x *Server_HTTP) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Server_HTTP) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +type Server_GRPC struct { + state protoimpl.MessageState `protogen:"open.v1"` + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + Timeout *durationpb.Duration `protobuf:"bytes,3,opt,name=timeout,proto3" json:"timeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Server_GRPC) Reset() { + *x = Server_GRPC{} + mi := &file_conf_conf_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Server_GRPC) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server_GRPC) ProtoMessage() {} + +func (x *Server_GRPC) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server_GRPC.ProtoReflect.Descriptor instead. +func (*Server_GRPC) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *Server_GRPC) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +func (x *Server_GRPC) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Server_GRPC) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +type Data_Database struct { + state protoimpl.MessageState `protogen:"open.v1"` + Driver string `protobuf:"bytes,1,opt,name=driver,proto3" json:"driver,omitempty"` + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Data_Database) Reset() { + *x = Data_Database{} + mi := &file_conf_conf_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Data_Database) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data_Database) ProtoMessage() {} + +func (x *Data_Database) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data_Database.ProtoReflect.Descriptor instead. +func (*Data_Database) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *Data_Database) GetDriver() string { + if x != nil { + return x.Driver + } + return "" +} + +func (x *Data_Database) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +type Data_Redis struct { + state protoimpl.MessageState `protogen:"open.v1"` + Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + ReadTimeout *durationpb.Duration `protobuf:"bytes,3,opt,name=read_timeout,json=readTimeout,proto3" json:"read_timeout,omitempty"` + WriteTimeout *durationpb.Duration `protobuf:"bytes,4,opt,name=write_timeout,json=writeTimeout,proto3" json:"write_timeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Data_Redis) Reset() { + *x = Data_Redis{} + mi := &file_conf_conf_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Data_Redis) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data_Redis) ProtoMessage() {} + +func (x *Data_Redis) ProtoReflect() protoreflect.Message { + mi := &file_conf_conf_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data_Redis.ProtoReflect.Descriptor instead. +func (*Data_Redis) Descriptor() ([]byte, []int) { + return file_conf_conf_proto_rawDescGZIP(), []int{2, 1} +} + +func (x *Data_Redis) GetNetwork() string { + if x != nil { + return x.Network + } + return "" +} + +func (x *Data_Redis) GetAddr() string { + if x != nil { + return x.Addr + } + return "" +} + +func (x *Data_Redis) GetReadTimeout() *durationpb.Duration { + if x != nil { + return x.ReadTimeout + } + return nil +} + +func (x *Data_Redis) GetWriteTimeout() *durationpb.Duration { + if x != nil { + return x.WriteTimeout + } + return nil +} + +var File_conf_conf_proto protoreflect.FileDescriptor + +var file_conf_conf_proto_rawDesc = string([]byte{ + 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0a, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 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, 0x5d, 0x0a, + 0x09, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6b, 0x72, 0x61, + 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x06, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xb8, 0x02, 0x0a, + 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x04, + 0x68, 0x74, 0x74, 0x70, 0x12, 0x2b, 0x0a, 0x04, 0x67, 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x04, 0x67, 0x72, 0x70, + 0x63, 0x1a, 0x69, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x18, 0x03, 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, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x1a, 0x69, 0x0a, 0x04, + 0x47, 0x52, 0x50, 0x43, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, + 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, + 0x64, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 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, 0x07, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0xdd, 0x02, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, + 0x12, 0x35, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x72, 0x65, 0x64, 0x69, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x64, 0x69, 0x73, 0x52, 0x05, + 0x72, 0x65, 0x64, 0x69, 0x73, 0x1a, 0x3a, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x1a, 0xb3, 0x01, 0x0a, 0x05, 0x52, 0x65, 0x64, 0x69, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x3c, 0x0a, 0x0c, 0x72, 0x65, 0x61, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 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, 0x61, 0x64, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 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, 0x0c, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42, 0x21, 0x5a, 0x1f, 0x6b, 0x72, 0x61, 0x74, 0x6f, + 0x73, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +}) + +var ( + file_conf_conf_proto_rawDescOnce sync.Once + file_conf_conf_proto_rawDescData []byte +) + +func file_conf_conf_proto_rawDescGZIP() []byte { + file_conf_conf_proto_rawDescOnce.Do(func() { + file_conf_conf_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_conf_conf_proto_rawDesc), len(file_conf_conf_proto_rawDesc))) + }) + return file_conf_conf_proto_rawDescData +} + +var file_conf_conf_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_conf_conf_proto_goTypes = []any{ + (*Bootstrap)(nil), // 0: kratos.api.Bootstrap + (*Server)(nil), // 1: kratos.api.Server + (*Data)(nil), // 2: kratos.api.Data + (*Server_HTTP)(nil), // 3: kratos.api.Server.HTTP + (*Server_GRPC)(nil), // 4: kratos.api.Server.GRPC + (*Data_Database)(nil), // 5: kratos.api.Data.Database + (*Data_Redis)(nil), // 6: kratos.api.Data.Redis + (*durationpb.Duration)(nil), // 7: google.protobuf.Duration +} +var file_conf_conf_proto_depIdxs = []int32{ + 1, // 0: kratos.api.Bootstrap.server:type_name -> kratos.api.Server + 2, // 1: kratos.api.Bootstrap.data:type_name -> kratos.api.Data + 3, // 2: kratos.api.Server.http:type_name -> kratos.api.Server.HTTP + 4, // 3: kratos.api.Server.grpc:type_name -> kratos.api.Server.GRPC + 5, // 4: kratos.api.Data.database:type_name -> kratos.api.Data.Database + 6, // 5: kratos.api.Data.redis:type_name -> kratos.api.Data.Redis + 7, // 6: kratos.api.Server.HTTP.timeout:type_name -> google.protobuf.Duration + 7, // 7: kratos.api.Server.GRPC.timeout:type_name -> google.protobuf.Duration + 7, // 8: kratos.api.Data.Redis.read_timeout:type_name -> google.protobuf.Duration + 7, // 9: kratos.api.Data.Redis.write_timeout:type_name -> google.protobuf.Duration + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_conf_conf_proto_init() } +func file_conf_conf_proto_init() { + if File_conf_conf_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_conf_conf_proto_rawDesc), len(file_conf_conf_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_conf_conf_proto_goTypes, + DependencyIndexes: file_conf_conf_proto_depIdxs, + MessageInfos: file_conf_conf_proto_msgTypes, + }.Build() + File_conf_conf_proto = out.File + file_conf_conf_proto_goTypes = nil + file_conf_conf_proto_depIdxs = nil +} diff --git a/internal/conf/conf.proto b/internal/conf/conf.proto new file mode 100644 index 0000000..e1de5d2 --- /dev/null +++ b/internal/conf/conf.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; +package kratos.api; + +option go_package = "kratos-admin/internal/conf;conf"; + +import "google/protobuf/duration.proto"; + +message Bootstrap { + Server server = 1; + Data data = 2; +} + +message Server { + message HTTP { + string network = 1; + string addr = 2; + google.protobuf.Duration timeout = 3; + } + message GRPC { + string network = 1; + string addr = 2; + google.protobuf.Duration timeout = 3; + } + HTTP http = 1; + GRPC grpc = 2; +} + +message Data { + message Database { + string driver = 1; + string source = 2; + } + message Redis { + string network = 1; + string addr = 2; + google.protobuf.Duration read_timeout = 3; + google.protobuf.Duration write_timeout = 4; + } + Database database = 1; + Redis redis = 2; +} diff --git a/internal/data/README.md b/internal/data/README.md new file mode 100644 index 0000000..599c41b --- /dev/null +++ b/internal/data/README.md @@ -0,0 +1 @@ +# Data diff --git a/internal/data/admin.go b/internal/data/admin.go new file mode 100644 index 0000000..b555f85 --- /dev/null +++ b/internal/data/admin.go @@ -0,0 +1,127 @@ +package data + +import ( + "context" + "time" + + "github.com/go-kratos/aip-go/ents" + "kra/internal/biz" + "kra/internal/data/ent" + "kra/internal/data/ent/admin" +) + +func convertAdmin(po *ent.Admin) *biz.Admin { + return &biz.Admin{ + ID: po.ID, + Name: po.Name, + Email: po.Email, + Avatar: po.Avatar, + Access: po.Access, + Password: po.Password, + CreateTime: po.CreateTime, + UpdateTime: po.UpdateTime, + } +} + +type adminRepo struct { + data *Data +} + +// NewAdminRepo creates a new AdminRepo instance. +func NewAdminRepo(data *Data) biz.AdminRepo { + return &adminRepo{ + data: data, + } +} + +func (r *adminRepo) FindByID(ctx context.Context, id int64) (*biz.Admin, error) { + po, err := r.data.db.Admin.Get(ctx, id) + if err != nil { + if ent.IsNotFound(err) { + return nil, biz.ErrAdminNotFound + } + return nil, err + } + return convertAdmin(po), nil +} + +func (r *adminRepo) FindByName(ctx context.Context, name string) (*biz.Admin, error) { + po, err := r.data.db.Admin.Query().Where(admin.NameEQ(name)).Only(ctx) + if err != nil { + if ent.IsNotFound(err) { + return nil, biz.ErrAdminNotFound + } + return nil, err + } + return convertAdmin(po), nil +} + +func (r *adminRepo) FindByEmail(ctx context.Context, email string) (*biz.Admin, error) { + po, err := r.data.db.Admin.Query().Where(admin.EmailEQ(email)).Only(ctx) + if err != nil { + if ent.IsNotFound(err) { + return nil, biz.ErrAdminNotFound + } + return nil, err + } + return convertAdmin(po), nil +} + +func (r *adminRepo) ListAdmins(ctx context.Context, opts ...biz.ListOption) ([]*biz.Admin, error) { + o := biz.ListOptions{Limit: 20} + for _, opt := range opts { + opt(&o) + } + pos, err := r.data.db.Admin.Query(). + Where(ents.ApplyFilter(o.Filter)). + Order(ents.ApplyOrderBy(o.OrderBy)). + Offset(o.Offset). + Limit(o.Limit). + All(ctx) + if err != nil { + return nil, err + } + var admins []*biz.Admin + for _, po := range pos { + admins = append(admins, convertAdmin(po)) + } + return admins, nil +} + +func (r *adminRepo) CreateAdmin(ctx context.Context, admin *biz.Admin) (*biz.Admin, error) { + po, err := r.data.db.Admin.Create(). + SetName(admin.Name). + SetEmail(admin.Email). + SetAvatar(admin.Avatar). + SetAccess(admin.Access). + SetPassword(admin.Password). + SetCreateTime(time.Now()). + SetUpdateTime(time.Now()). + Save(ctx) + if err != nil { + return nil, err + } + return convertAdmin(po), nil +} + +func (r *adminRepo) UpdateAdmin(ctx context.Context, admin *biz.Admin) (*biz.Admin, error) { + update := r.data.db.Admin.UpdateOneID(admin.ID). + SetName(admin.Name). + SetEmail(admin.Email). + SetAccess(admin.Access). + SetAvatar(admin.Avatar). + SetUpdateTime(time.Now()) + // Only update the password if it's not empty + if admin.Password != "" { + update.SetPassword(admin.Password) + } + po, err := update.Save(ctx) + if err != nil { + return nil, err + } + return convertAdmin(po), nil +} + +func (r *adminRepo) DeleteAdmin(ctx context.Context, id int64) error { + return r.data.db.Admin.DeleteOneID(id).Exec(ctx) +} diff --git a/internal/data/data.go b/internal/data/data.go new file mode 100644 index 0000000..4c037a5 --- /dev/null +++ b/internal/data/data.go @@ -0,0 +1,43 @@ +package data + +import ( + "context" + "log" + "os" + + "kra/internal/conf" + "kra/internal/data/ent" + "kra/internal/data/ent/migrate" + _ "github.com/go-sql-driver/mysql" + "github.com/google/wire" +) + +// ProviderSet is data providers. +var ProviderSet = wire.NewSet(NewData, NewAdminRepo) + +// Data is a struct that contains the database client. +type Data struct { + db *ent.Client +} + +// NewData creates a new Data instance. +func NewData(c *conf.Data) (*Data, func(), error) { + db, err := ent.Open(c.Database.Driver, c.Database.Source) + if err != nil { + log.Fatalf("failed opening connection to database: %v", err) + } + if os.Getenv("DEPLOY_ENV") == "dev" { + // Enable debug mode for detailed logging. + db = db.Debug() + // Run the auto migration tool. + if err = db.Schema.Create(context.Background(), migrate.WithDropIndex(true)); err != nil { + return nil, nil, err + } + } + cleanup := func() { + db.Close() + } + return &Data{ + db: db, + }, cleanup, nil +} diff --git a/internal/data/ent/admin.go b/internal/data/ent/admin.go new file mode 100644 index 0000000..3a98dc3 --- /dev/null +++ b/internal/data/ent/admin.go @@ -0,0 +1,172 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "kra/internal/data/ent/admin" +) + +// Admin is the model entity for the Admin schema. +type Admin struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Email holds the value of the "email" field. + Email string `json:"email,omitempty"` + // Avatar holds the value of the "avatar" field. + Avatar string `json:"avatar,omitempty"` + // Access holds the value of the "access" field. + Access string `json:"access,omitempty"` + // Password holds the value of the "password" field. + Password string `json:"password,omitempty"` + // CreateTime holds the value of the "create_time" field. + CreateTime time.Time `json:"create_time,omitempty"` + // UpdateTime holds the value of the "update_time" field. + UpdateTime time.Time `json:"update_time,omitempty"` + selectValues sql.SelectValues +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Admin) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case admin.FieldID: + values[i] = new(sql.NullInt64) + case admin.FieldName, admin.FieldEmail, admin.FieldAvatar, admin.FieldAccess, admin.FieldPassword: + values[i] = new(sql.NullString) + case admin.FieldCreateTime, admin.FieldUpdateTime: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Admin fields. +func (_m *Admin) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case admin.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + _m.ID = int64(value.Int64) + case admin.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + _m.Name = value.String + } + case admin.FieldEmail: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field email", values[i]) + } else if value.Valid { + _m.Email = value.String + } + case admin.FieldAvatar: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field avatar", values[i]) + } else if value.Valid { + _m.Avatar = value.String + } + case admin.FieldAccess: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field access", values[i]) + } else if value.Valid { + _m.Access = value.String + } + case admin.FieldPassword: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field password", values[i]) + } else if value.Valid { + _m.Password = value.String + } + case admin.FieldCreateTime: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field create_time", values[i]) + } else if value.Valid { + _m.CreateTime = value.Time + } + case admin.FieldUpdateTime: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field update_time", values[i]) + } else if value.Valid { + _m.UpdateTime = value.Time + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Admin. +// This includes values selected through modifiers, order, etc. +func (_m *Admin) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// Update returns a builder for updating this Admin. +// Note that you need to call Admin.Unwrap() before calling this method if this Admin +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *Admin) Update() *AdminUpdateOne { + return NewAdminClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the Admin entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (_m *Admin) Unwrap() *Admin { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: Admin is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *Admin) String() string { + var builder strings.Builder + builder.WriteString("Admin(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("name=") + builder.WriteString(_m.Name) + builder.WriteString(", ") + builder.WriteString("email=") + builder.WriteString(_m.Email) + builder.WriteString(", ") + builder.WriteString("avatar=") + builder.WriteString(_m.Avatar) + builder.WriteString(", ") + builder.WriteString("access=") + builder.WriteString(_m.Access) + builder.WriteString(", ") + builder.WriteString("password=") + builder.WriteString(_m.Password) + builder.WriteString(", ") + builder.WriteString("create_time=") + builder.WriteString(_m.CreateTime.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("update_time=") + builder.WriteString(_m.UpdateTime.Format(time.ANSIC)) + builder.WriteByte(')') + return builder.String() +} + +// Admins is a parsable slice of Admin. +type Admins []*Admin diff --git a/internal/data/ent/admin/admin.go b/internal/data/ent/admin/admin.go new file mode 100644 index 0000000..767c0ee --- /dev/null +++ b/internal/data/ent/admin/admin.go @@ -0,0 +1,116 @@ +// Code generated by ent, DO NOT EDIT. + +package admin + +import ( + "time" + + "entgo.io/ent/dialect/sql" +) + +const ( + // Label holds the string label denoting the admin type in the database. + Label = "admin" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldEmail holds the string denoting the email field in the database. + FieldEmail = "email" + // FieldAvatar holds the string denoting the avatar field in the database. + FieldAvatar = "avatar" + // FieldAccess holds the string denoting the access field in the database. + FieldAccess = "access" + // FieldPassword holds the string denoting the password field in the database. + FieldPassword = "password" + // FieldCreateTime holds the string denoting the create_time field in the database. + FieldCreateTime = "create_time" + // FieldUpdateTime holds the string denoting the update_time field in the database. + FieldUpdateTime = "update_time" + // Table holds the table name of the admin in the database. + Table = "admins" +) + +// Columns holds all SQL columns for admin fields. +var Columns = []string{ + FieldID, + FieldName, + FieldEmail, + FieldAvatar, + FieldAccess, + FieldPassword, + FieldCreateTime, + FieldUpdateTime, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // DefaultName holds the default value on creation for the "name" field. + DefaultName string + // DefaultEmail holds the default value on creation for the "email" field. + DefaultEmail string + // DefaultAvatar holds the default value on creation for the "avatar" field. + DefaultAvatar string + // DefaultAccess holds the default value on creation for the "access" field. + DefaultAccess string + // DefaultPassword holds the default value on creation for the "password" field. + DefaultPassword string + // DefaultCreateTime holds the default value on creation for the "create_time" field. + DefaultCreateTime func() time.Time + // DefaultUpdateTime holds the default value on creation for the "update_time" field. + DefaultUpdateTime func() time.Time + // UpdateDefaultUpdateTime holds the default value on update for the "update_time" field. + UpdateDefaultUpdateTime func() time.Time +) + +// OrderOption defines the ordering options for the Admin queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByEmail orders the results by the email field. +func ByEmail(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldEmail, opts...).ToFunc() +} + +// ByAvatar orders the results by the avatar field. +func ByAvatar(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldAvatar, opts...).ToFunc() +} + +// ByAccess orders the results by the access field. +func ByAccess(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldAccess, opts...).ToFunc() +} + +// ByPassword orders the results by the password field. +func ByPassword(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPassword, opts...).ToFunc() +} + +// ByCreateTime orders the results by the create_time field. +func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreateTime, opts...).ToFunc() +} + +// ByUpdateTime orders the results by the update_time field. +func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdateTime, opts...).ToFunc() +} diff --git a/internal/data/ent/admin/where.go b/internal/data/ent/admin/where.go new file mode 100644 index 0000000..42c98e2 --- /dev/null +++ b/internal/data/ent/admin/where.go @@ -0,0 +1,510 @@ +// Code generated by ent, DO NOT EDIT. + +package admin + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "kra/internal/data/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldID, id)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldName, v)) +} + +// Email applies equality check predicate on the "email" field. It's identical to EmailEQ. +func Email(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldEmail, v)) +} + +// Avatar applies equality check predicate on the "avatar" field. It's identical to AvatarEQ. +func Avatar(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldAvatar, v)) +} + +// Access applies equality check predicate on the "access" field. It's identical to AccessEQ. +func Access(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldAccess, v)) +} + +// Password applies equality check predicate on the "password" field. It's identical to PasswordEQ. +func Password(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldPassword, v)) +} + +// CreateTime applies equality check predicate on the "create_time" field. It's identical to CreateTimeEQ. +func CreateTime(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldCreateTime, v)) +} + +// UpdateTime applies equality check predicate on the "update_time" field. It's identical to UpdateTimeEQ. +func UpdateTime(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldUpdateTime, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Admin { + return predicate.Admin(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldContainsFold(FieldName, v)) +} + +// EmailEQ applies the EQ predicate on the "email" field. +func EmailEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldEmail, v)) +} + +// EmailNEQ applies the NEQ predicate on the "email" field. +func EmailNEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldEmail, v)) +} + +// EmailIn applies the In predicate on the "email" field. +func EmailIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldEmail, vs...)) +} + +// EmailNotIn applies the NotIn predicate on the "email" field. +func EmailNotIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldEmail, vs...)) +} + +// EmailGT applies the GT predicate on the "email" field. +func EmailGT(v string) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldEmail, v)) +} + +// EmailGTE applies the GTE predicate on the "email" field. +func EmailGTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldEmail, v)) +} + +// EmailLT applies the LT predicate on the "email" field. +func EmailLT(v string) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldEmail, v)) +} + +// EmailLTE applies the LTE predicate on the "email" field. +func EmailLTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldEmail, v)) +} + +// EmailContains applies the Contains predicate on the "email" field. +func EmailContains(v string) predicate.Admin { + return predicate.Admin(sql.FieldContains(FieldEmail, v)) +} + +// EmailHasPrefix applies the HasPrefix predicate on the "email" field. +func EmailHasPrefix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasPrefix(FieldEmail, v)) +} + +// EmailHasSuffix applies the HasSuffix predicate on the "email" field. +func EmailHasSuffix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasSuffix(FieldEmail, v)) +} + +// EmailEqualFold applies the EqualFold predicate on the "email" field. +func EmailEqualFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldEqualFold(FieldEmail, v)) +} + +// EmailContainsFold applies the ContainsFold predicate on the "email" field. +func EmailContainsFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldContainsFold(FieldEmail, v)) +} + +// AvatarEQ applies the EQ predicate on the "avatar" field. +func AvatarEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldAvatar, v)) +} + +// AvatarNEQ applies the NEQ predicate on the "avatar" field. +func AvatarNEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldAvatar, v)) +} + +// AvatarIn applies the In predicate on the "avatar" field. +func AvatarIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldAvatar, vs...)) +} + +// AvatarNotIn applies the NotIn predicate on the "avatar" field. +func AvatarNotIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldAvatar, vs...)) +} + +// AvatarGT applies the GT predicate on the "avatar" field. +func AvatarGT(v string) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldAvatar, v)) +} + +// AvatarGTE applies the GTE predicate on the "avatar" field. +func AvatarGTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldAvatar, v)) +} + +// AvatarLT applies the LT predicate on the "avatar" field. +func AvatarLT(v string) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldAvatar, v)) +} + +// AvatarLTE applies the LTE predicate on the "avatar" field. +func AvatarLTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldAvatar, v)) +} + +// AvatarContains applies the Contains predicate on the "avatar" field. +func AvatarContains(v string) predicate.Admin { + return predicate.Admin(sql.FieldContains(FieldAvatar, v)) +} + +// AvatarHasPrefix applies the HasPrefix predicate on the "avatar" field. +func AvatarHasPrefix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasPrefix(FieldAvatar, v)) +} + +// AvatarHasSuffix applies the HasSuffix predicate on the "avatar" field. +func AvatarHasSuffix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasSuffix(FieldAvatar, v)) +} + +// AvatarEqualFold applies the EqualFold predicate on the "avatar" field. +func AvatarEqualFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldEqualFold(FieldAvatar, v)) +} + +// AvatarContainsFold applies the ContainsFold predicate on the "avatar" field. +func AvatarContainsFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldContainsFold(FieldAvatar, v)) +} + +// AccessEQ applies the EQ predicate on the "access" field. +func AccessEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldAccess, v)) +} + +// AccessNEQ applies the NEQ predicate on the "access" field. +func AccessNEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldAccess, v)) +} + +// AccessIn applies the In predicate on the "access" field. +func AccessIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldAccess, vs...)) +} + +// AccessNotIn applies the NotIn predicate on the "access" field. +func AccessNotIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldAccess, vs...)) +} + +// AccessGT applies the GT predicate on the "access" field. +func AccessGT(v string) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldAccess, v)) +} + +// AccessGTE applies the GTE predicate on the "access" field. +func AccessGTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldAccess, v)) +} + +// AccessLT applies the LT predicate on the "access" field. +func AccessLT(v string) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldAccess, v)) +} + +// AccessLTE applies the LTE predicate on the "access" field. +func AccessLTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldAccess, v)) +} + +// AccessContains applies the Contains predicate on the "access" field. +func AccessContains(v string) predicate.Admin { + return predicate.Admin(sql.FieldContains(FieldAccess, v)) +} + +// AccessHasPrefix applies the HasPrefix predicate on the "access" field. +func AccessHasPrefix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasPrefix(FieldAccess, v)) +} + +// AccessHasSuffix applies the HasSuffix predicate on the "access" field. +func AccessHasSuffix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasSuffix(FieldAccess, v)) +} + +// AccessEqualFold applies the EqualFold predicate on the "access" field. +func AccessEqualFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldEqualFold(FieldAccess, v)) +} + +// AccessContainsFold applies the ContainsFold predicate on the "access" field. +func AccessContainsFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldContainsFold(FieldAccess, v)) +} + +// PasswordEQ applies the EQ predicate on the "password" field. +func PasswordEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldPassword, v)) +} + +// PasswordNEQ applies the NEQ predicate on the "password" field. +func PasswordNEQ(v string) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldPassword, v)) +} + +// PasswordIn applies the In predicate on the "password" field. +func PasswordIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldPassword, vs...)) +} + +// PasswordNotIn applies the NotIn predicate on the "password" field. +func PasswordNotIn(vs ...string) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldPassword, vs...)) +} + +// PasswordGT applies the GT predicate on the "password" field. +func PasswordGT(v string) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldPassword, v)) +} + +// PasswordGTE applies the GTE predicate on the "password" field. +func PasswordGTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldPassword, v)) +} + +// PasswordLT applies the LT predicate on the "password" field. +func PasswordLT(v string) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldPassword, v)) +} + +// PasswordLTE applies the LTE predicate on the "password" field. +func PasswordLTE(v string) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldPassword, v)) +} + +// PasswordContains applies the Contains predicate on the "password" field. +func PasswordContains(v string) predicate.Admin { + return predicate.Admin(sql.FieldContains(FieldPassword, v)) +} + +// PasswordHasPrefix applies the HasPrefix predicate on the "password" field. +func PasswordHasPrefix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasPrefix(FieldPassword, v)) +} + +// PasswordHasSuffix applies the HasSuffix predicate on the "password" field. +func PasswordHasSuffix(v string) predicate.Admin { + return predicate.Admin(sql.FieldHasSuffix(FieldPassword, v)) +} + +// PasswordEqualFold applies the EqualFold predicate on the "password" field. +func PasswordEqualFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldEqualFold(FieldPassword, v)) +} + +// PasswordContainsFold applies the ContainsFold predicate on the "password" field. +func PasswordContainsFold(v string) predicate.Admin { + return predicate.Admin(sql.FieldContainsFold(FieldPassword, v)) +} + +// CreateTimeEQ applies the EQ predicate on the "create_time" field. +func CreateTimeEQ(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldCreateTime, v)) +} + +// CreateTimeNEQ applies the NEQ predicate on the "create_time" field. +func CreateTimeNEQ(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldCreateTime, v)) +} + +// CreateTimeIn applies the In predicate on the "create_time" field. +func CreateTimeIn(vs ...time.Time) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldCreateTime, vs...)) +} + +// CreateTimeNotIn applies the NotIn predicate on the "create_time" field. +func CreateTimeNotIn(vs ...time.Time) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldCreateTime, vs...)) +} + +// CreateTimeGT applies the GT predicate on the "create_time" field. +func CreateTimeGT(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldCreateTime, v)) +} + +// CreateTimeGTE applies the GTE predicate on the "create_time" field. +func CreateTimeGTE(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldCreateTime, v)) +} + +// CreateTimeLT applies the LT predicate on the "create_time" field. +func CreateTimeLT(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldCreateTime, v)) +} + +// CreateTimeLTE applies the LTE predicate on the "create_time" field. +func CreateTimeLTE(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldCreateTime, v)) +} + +// UpdateTimeEQ applies the EQ predicate on the "update_time" field. +func UpdateTimeEQ(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldEQ(FieldUpdateTime, v)) +} + +// UpdateTimeNEQ applies the NEQ predicate on the "update_time" field. +func UpdateTimeNEQ(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldNEQ(FieldUpdateTime, v)) +} + +// UpdateTimeIn applies the In predicate on the "update_time" field. +func UpdateTimeIn(vs ...time.Time) predicate.Admin { + return predicate.Admin(sql.FieldIn(FieldUpdateTime, vs...)) +} + +// UpdateTimeNotIn applies the NotIn predicate on the "update_time" field. +func UpdateTimeNotIn(vs ...time.Time) predicate.Admin { + return predicate.Admin(sql.FieldNotIn(FieldUpdateTime, vs...)) +} + +// UpdateTimeGT applies the GT predicate on the "update_time" field. +func UpdateTimeGT(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldGT(FieldUpdateTime, v)) +} + +// UpdateTimeGTE applies the GTE predicate on the "update_time" field. +func UpdateTimeGTE(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldGTE(FieldUpdateTime, v)) +} + +// UpdateTimeLT applies the LT predicate on the "update_time" field. +func UpdateTimeLT(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldLT(FieldUpdateTime, v)) +} + +// UpdateTimeLTE applies the LTE predicate on the "update_time" field. +func UpdateTimeLTE(v time.Time) predicate.Admin { + return predicate.Admin(sql.FieldLTE(FieldUpdateTime, v)) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Admin) predicate.Admin { + return predicate.Admin(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Admin) predicate.Admin { + return predicate.Admin(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Admin) predicate.Admin { + return predicate.Admin(sql.NotPredicates(p)) +} diff --git a/internal/data/ent/admin_create.go b/internal/data/ent/admin_create.go new file mode 100644 index 0000000..a9fc110 --- /dev/null +++ b/internal/data/ent/admin_create.go @@ -0,0 +1,859 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "kra/internal/data/ent/admin" +) + +// AdminCreate is the builder for creating a Admin entity. +type AdminCreate struct { + config + mutation *AdminMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetName sets the "name" field. +func (_c *AdminCreate) SetName(v string) *AdminCreate { + _c.mutation.SetName(v) + return _c +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_c *AdminCreate) SetNillableName(v *string) *AdminCreate { + if v != nil { + _c.SetName(*v) + } + return _c +} + +// SetEmail sets the "email" field. +func (_c *AdminCreate) SetEmail(v string) *AdminCreate { + _c.mutation.SetEmail(v) + return _c +} + +// SetNillableEmail sets the "email" field if the given value is not nil. +func (_c *AdminCreate) SetNillableEmail(v *string) *AdminCreate { + if v != nil { + _c.SetEmail(*v) + } + return _c +} + +// SetAvatar sets the "avatar" field. +func (_c *AdminCreate) SetAvatar(v string) *AdminCreate { + _c.mutation.SetAvatar(v) + return _c +} + +// SetNillableAvatar sets the "avatar" field if the given value is not nil. +func (_c *AdminCreate) SetNillableAvatar(v *string) *AdminCreate { + if v != nil { + _c.SetAvatar(*v) + } + return _c +} + +// SetAccess sets the "access" field. +func (_c *AdminCreate) SetAccess(v string) *AdminCreate { + _c.mutation.SetAccess(v) + return _c +} + +// SetNillableAccess sets the "access" field if the given value is not nil. +func (_c *AdminCreate) SetNillableAccess(v *string) *AdminCreate { + if v != nil { + _c.SetAccess(*v) + } + return _c +} + +// SetPassword sets the "password" field. +func (_c *AdminCreate) SetPassword(v string) *AdminCreate { + _c.mutation.SetPassword(v) + return _c +} + +// SetNillablePassword sets the "password" field if the given value is not nil. +func (_c *AdminCreate) SetNillablePassword(v *string) *AdminCreate { + if v != nil { + _c.SetPassword(*v) + } + return _c +} + +// SetCreateTime sets the "create_time" field. +func (_c *AdminCreate) SetCreateTime(v time.Time) *AdminCreate { + _c.mutation.SetCreateTime(v) + return _c +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (_c *AdminCreate) SetNillableCreateTime(v *time.Time) *AdminCreate { + if v != nil { + _c.SetCreateTime(*v) + } + return _c +} + +// SetUpdateTime sets the "update_time" field. +func (_c *AdminCreate) SetUpdateTime(v time.Time) *AdminCreate { + _c.mutation.SetUpdateTime(v) + return _c +} + +// SetNillableUpdateTime sets the "update_time" field if the given value is not nil. +func (_c *AdminCreate) SetNillableUpdateTime(v *time.Time) *AdminCreate { + if v != nil { + _c.SetUpdateTime(*v) + } + return _c +} + +// SetID sets the "id" field. +func (_c *AdminCreate) SetID(v int64) *AdminCreate { + _c.mutation.SetID(v) + return _c +} + +// Mutation returns the AdminMutation object of the builder. +func (_c *AdminCreate) Mutation() *AdminMutation { + return _c.mutation +} + +// Save creates the Admin in the database. +func (_c *AdminCreate) Save(ctx context.Context) (*Admin, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *AdminCreate) SaveX(ctx context.Context) *Admin { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *AdminCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *AdminCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *AdminCreate) defaults() { + if _, ok := _c.mutation.Name(); !ok { + v := admin.DefaultName + _c.mutation.SetName(v) + } + if _, ok := _c.mutation.Email(); !ok { + v := admin.DefaultEmail + _c.mutation.SetEmail(v) + } + if _, ok := _c.mutation.Avatar(); !ok { + v := admin.DefaultAvatar + _c.mutation.SetAvatar(v) + } + if _, ok := _c.mutation.Access(); !ok { + v := admin.DefaultAccess + _c.mutation.SetAccess(v) + } + if _, ok := _c.mutation.Password(); !ok { + v := admin.DefaultPassword + _c.mutation.SetPassword(v) + } + if _, ok := _c.mutation.CreateTime(); !ok { + v := admin.DefaultCreateTime() + _c.mutation.SetCreateTime(v) + } + if _, ok := _c.mutation.UpdateTime(); !ok { + v := admin.DefaultUpdateTime() + _c.mutation.SetUpdateTime(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *AdminCreate) check() error { + if _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Admin.name"`)} + } + if _, ok := _c.mutation.Email(); !ok { + return &ValidationError{Name: "email", err: errors.New(`ent: missing required field "Admin.email"`)} + } + if _, ok := _c.mutation.Avatar(); !ok { + return &ValidationError{Name: "avatar", err: errors.New(`ent: missing required field "Admin.avatar"`)} + } + if _, ok := _c.mutation.Access(); !ok { + return &ValidationError{Name: "access", err: errors.New(`ent: missing required field "Admin.access"`)} + } + if _, ok := _c.mutation.Password(); !ok { + return &ValidationError{Name: "password", err: errors.New(`ent: missing required field "Admin.password"`)} + } + if _, ok := _c.mutation.CreateTime(); !ok { + return &ValidationError{Name: "create_time", err: errors.New(`ent: missing required field "Admin.create_time"`)} + } + if _, ok := _c.mutation.UpdateTime(); !ok { + return &ValidationError{Name: "update_time", err: errors.New(`ent: missing required field "Admin.update_time"`)} + } + return nil +} + +func (_c *AdminCreate) sqlSave(ctx context.Context) (*Admin, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + if _spec.ID.Value != _node.ID { + id := _spec.ID.Value.(int64) + _node.ID = int64(id) + } + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *AdminCreate) createSpec() (*Admin, *sqlgraph.CreateSpec) { + var ( + _node = &Admin{config: _c.config} + _spec = sqlgraph.NewCreateSpec(admin.Table, sqlgraph.NewFieldSpec(admin.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if id, ok := _c.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = id + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(admin.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Email(); ok { + _spec.SetField(admin.FieldEmail, field.TypeString, value) + _node.Email = value + } + if value, ok := _c.mutation.Avatar(); ok { + _spec.SetField(admin.FieldAvatar, field.TypeString, value) + _node.Avatar = value + } + if value, ok := _c.mutation.Access(); ok { + _spec.SetField(admin.FieldAccess, field.TypeString, value) + _node.Access = value + } + if value, ok := _c.mutation.Password(); ok { + _spec.SetField(admin.FieldPassword, field.TypeString, value) + _node.Password = value + } + if value, ok := _c.mutation.CreateTime(); ok { + _spec.SetField(admin.FieldCreateTime, field.TypeTime, value) + _node.CreateTime = value + } + if value, ok := _c.mutation.UpdateTime(); ok { + _spec.SetField(admin.FieldUpdateTime, field.TypeTime, value) + _node.UpdateTime = value + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.Admin.Create(). +// SetName(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.AdminUpsert) { +// SetName(v+v). +// }). +// Exec(ctx) +func (_c *AdminCreate) OnConflict(opts ...sql.ConflictOption) *AdminUpsertOne { + _c.conflict = opts + return &AdminUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.Admin.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *AdminCreate) OnConflictColumns(columns ...string) *AdminUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &AdminUpsertOne{ + create: _c, + } +} + +type ( + // AdminUpsertOne is the builder for "upsert"-ing + // one Admin node. + AdminUpsertOne struct { + create *AdminCreate + } + + // AdminUpsert is the "OnConflict" setter. + AdminUpsert struct { + *sql.UpdateSet + } +) + +// SetName sets the "name" field. +func (u *AdminUpsert) SetName(v string) *AdminUpsert { + u.Set(admin.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *AdminUpsert) UpdateName() *AdminUpsert { + u.SetExcluded(admin.FieldName) + return u +} + +// SetEmail sets the "email" field. +func (u *AdminUpsert) SetEmail(v string) *AdminUpsert { + u.Set(admin.FieldEmail, v) + return u +} + +// UpdateEmail sets the "email" field to the value that was provided on create. +func (u *AdminUpsert) UpdateEmail() *AdminUpsert { + u.SetExcluded(admin.FieldEmail) + return u +} + +// SetAvatar sets the "avatar" field. +func (u *AdminUpsert) SetAvatar(v string) *AdminUpsert { + u.Set(admin.FieldAvatar, v) + return u +} + +// UpdateAvatar sets the "avatar" field to the value that was provided on create. +func (u *AdminUpsert) UpdateAvatar() *AdminUpsert { + u.SetExcluded(admin.FieldAvatar) + return u +} + +// SetAccess sets the "access" field. +func (u *AdminUpsert) SetAccess(v string) *AdminUpsert { + u.Set(admin.FieldAccess, v) + return u +} + +// UpdateAccess sets the "access" field to the value that was provided on create. +func (u *AdminUpsert) UpdateAccess() *AdminUpsert { + u.SetExcluded(admin.FieldAccess) + return u +} + +// SetPassword sets the "password" field. +func (u *AdminUpsert) SetPassword(v string) *AdminUpsert { + u.Set(admin.FieldPassword, v) + return u +} + +// UpdatePassword sets the "password" field to the value that was provided on create. +func (u *AdminUpsert) UpdatePassword() *AdminUpsert { + u.SetExcluded(admin.FieldPassword) + return u +} + +// SetUpdateTime sets the "update_time" field. +func (u *AdminUpsert) SetUpdateTime(v time.Time) *AdminUpsert { + u.Set(admin.FieldUpdateTime, v) + return u +} + +// UpdateUpdateTime sets the "update_time" field to the value that was provided on create. +func (u *AdminUpsert) UpdateUpdateTime() *AdminUpsert { + u.SetExcluded(admin.FieldUpdateTime) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. +// Using this option is equivalent to using: +// +// client.Admin.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// sql.ResolveWith(func(u *sql.UpdateSet) { +// u.SetIgnore(admin.FieldID) +// }), +// ). +// Exec(ctx) +func (u *AdminUpsertOne) UpdateNewValues() *AdminUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + if _, exists := u.create.mutation.ID(); exists { + s.SetIgnore(admin.FieldID) + } + if _, exists := u.create.mutation.CreateTime(); exists { + s.SetIgnore(admin.FieldCreateTime) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.Admin.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *AdminUpsertOne) Ignore() *AdminUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *AdminUpsertOne) DoNothing() *AdminUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the AdminCreate.OnConflict +// documentation for more info. +func (u *AdminUpsertOne) Update(set func(*AdminUpsert)) *AdminUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&AdminUpsert{UpdateSet: update}) + })) + return u +} + +// SetName sets the "name" field. +func (u *AdminUpsertOne) SetName(v string) *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *AdminUpsertOne) UpdateName() *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.UpdateName() + }) +} + +// SetEmail sets the "email" field. +func (u *AdminUpsertOne) SetEmail(v string) *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.SetEmail(v) + }) +} + +// UpdateEmail sets the "email" field to the value that was provided on create. +func (u *AdminUpsertOne) UpdateEmail() *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.UpdateEmail() + }) +} + +// SetAvatar sets the "avatar" field. +func (u *AdminUpsertOne) SetAvatar(v string) *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.SetAvatar(v) + }) +} + +// UpdateAvatar sets the "avatar" field to the value that was provided on create. +func (u *AdminUpsertOne) UpdateAvatar() *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.UpdateAvatar() + }) +} + +// SetAccess sets the "access" field. +func (u *AdminUpsertOne) SetAccess(v string) *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.SetAccess(v) + }) +} + +// UpdateAccess sets the "access" field to the value that was provided on create. +func (u *AdminUpsertOne) UpdateAccess() *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.UpdateAccess() + }) +} + +// SetPassword sets the "password" field. +func (u *AdminUpsertOne) SetPassword(v string) *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.SetPassword(v) + }) +} + +// UpdatePassword sets the "password" field to the value that was provided on create. +func (u *AdminUpsertOne) UpdatePassword() *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.UpdatePassword() + }) +} + +// SetUpdateTime sets the "update_time" field. +func (u *AdminUpsertOne) SetUpdateTime(v time.Time) *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.SetUpdateTime(v) + }) +} + +// UpdateUpdateTime sets the "update_time" field to the value that was provided on create. +func (u *AdminUpsertOne) UpdateUpdateTime() *AdminUpsertOne { + return u.Update(func(s *AdminUpsert) { + s.UpdateUpdateTime() + }) +} + +// Exec executes the query. +func (u *AdminUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for AdminCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *AdminUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// Exec executes the UPSERT query and returns the inserted/updated ID. +func (u *AdminUpsertOne) ID(ctx context.Context) (id int64, err error) { + node, err := u.create.Save(ctx) + if err != nil { + return id, err + } + return node.ID, nil +} + +// IDX is like ID, but panics if an error occurs. +func (u *AdminUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// AdminCreateBulk is the builder for creating many Admin entities in bulk. +type AdminCreateBulk struct { + config + err error + builders []*AdminCreate + conflict []sql.ConflictOption +} + +// Save creates the Admin entities in the database. +func (_c *AdminCreateBulk) Save(ctx context.Context) ([]*Admin, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*Admin, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*AdminMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = _c.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil && nodes[i].ID == 0 { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int64(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *AdminCreateBulk) SaveX(ctx context.Context) []*Admin { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *AdminCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *AdminCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.Admin.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.AdminUpsert) { +// SetName(v+v). +// }). +// Exec(ctx) +func (_c *AdminCreateBulk) OnConflict(opts ...sql.ConflictOption) *AdminUpsertBulk { + _c.conflict = opts + return &AdminUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.Admin.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *AdminCreateBulk) OnConflictColumns(columns ...string) *AdminUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &AdminUpsertBulk{ + create: _c, + } +} + +// AdminUpsertBulk is the builder for "upsert"-ing +// a bulk of Admin nodes. +type AdminUpsertBulk struct { + create *AdminCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.Admin.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// sql.ResolveWith(func(u *sql.UpdateSet) { +// u.SetIgnore(admin.FieldID) +// }), +// ). +// Exec(ctx) +func (u *AdminUpsertBulk) UpdateNewValues() *AdminUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + for _, b := range u.create.builders { + if _, exists := b.mutation.ID(); exists { + s.SetIgnore(admin.FieldID) + } + if _, exists := b.mutation.CreateTime(); exists { + s.SetIgnore(admin.FieldCreateTime) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.Admin.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *AdminUpsertBulk) Ignore() *AdminUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *AdminUpsertBulk) DoNothing() *AdminUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the AdminCreateBulk.OnConflict +// documentation for more info. +func (u *AdminUpsertBulk) Update(set func(*AdminUpsert)) *AdminUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&AdminUpsert{UpdateSet: update}) + })) + return u +} + +// SetName sets the "name" field. +func (u *AdminUpsertBulk) SetName(v string) *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *AdminUpsertBulk) UpdateName() *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.UpdateName() + }) +} + +// SetEmail sets the "email" field. +func (u *AdminUpsertBulk) SetEmail(v string) *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.SetEmail(v) + }) +} + +// UpdateEmail sets the "email" field to the value that was provided on create. +func (u *AdminUpsertBulk) UpdateEmail() *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.UpdateEmail() + }) +} + +// SetAvatar sets the "avatar" field. +func (u *AdminUpsertBulk) SetAvatar(v string) *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.SetAvatar(v) + }) +} + +// UpdateAvatar sets the "avatar" field to the value that was provided on create. +func (u *AdminUpsertBulk) UpdateAvatar() *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.UpdateAvatar() + }) +} + +// SetAccess sets the "access" field. +func (u *AdminUpsertBulk) SetAccess(v string) *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.SetAccess(v) + }) +} + +// UpdateAccess sets the "access" field to the value that was provided on create. +func (u *AdminUpsertBulk) UpdateAccess() *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.UpdateAccess() + }) +} + +// SetPassword sets the "password" field. +func (u *AdminUpsertBulk) SetPassword(v string) *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.SetPassword(v) + }) +} + +// UpdatePassword sets the "password" field to the value that was provided on create. +func (u *AdminUpsertBulk) UpdatePassword() *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.UpdatePassword() + }) +} + +// SetUpdateTime sets the "update_time" field. +func (u *AdminUpsertBulk) SetUpdateTime(v time.Time) *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.SetUpdateTime(v) + }) +} + +// UpdateUpdateTime sets the "update_time" field to the value that was provided on create. +func (u *AdminUpsertBulk) UpdateUpdateTime() *AdminUpsertBulk { + return u.Update(func(s *AdminUpsert) { + s.UpdateUpdateTime() + }) +} + +// Exec executes the query. +func (u *AdminUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the AdminCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for AdminCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *AdminUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/data/ent/admin_delete.go b/internal/data/ent/admin_delete.go new file mode 100644 index 0000000..881482f --- /dev/null +++ b/internal/data/ent/admin_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "kra/internal/data/ent/admin" + "kra/internal/data/ent/predicate" +) + +// AdminDelete is the builder for deleting a Admin entity. +type AdminDelete struct { + config + hooks []Hook + mutation *AdminMutation +} + +// Where appends a list predicates to the AdminDelete builder. +func (_d *AdminDelete) Where(ps ...predicate.Admin) *AdminDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *AdminDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *AdminDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *AdminDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(admin.Table, sqlgraph.NewFieldSpec(admin.FieldID, field.TypeInt64)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// AdminDeleteOne is the builder for deleting a single Admin entity. +type AdminDeleteOne struct { + _d *AdminDelete +} + +// Where appends a list predicates to the AdminDelete builder. +func (_d *AdminDeleteOne) Where(ps ...predicate.Admin) *AdminDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *AdminDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{admin.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *AdminDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/internal/data/ent/admin_query.go b/internal/data/ent/admin_query.go new file mode 100644 index 0000000..4192c01 --- /dev/null +++ b/internal/data/ent/admin_query.go @@ -0,0 +1,527 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "kra/internal/data/ent/admin" + "kra/internal/data/ent/predicate" +) + +// AdminQuery is the builder for querying Admin entities. +type AdminQuery struct { + config + ctx *QueryContext + order []admin.OrderOption + inters []Interceptor + predicates []predicate.Admin + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the AdminQuery builder. +func (_q *AdminQuery) Where(ps ...predicate.Admin) *AdminQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *AdminQuery) Limit(limit int) *AdminQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *AdminQuery) Offset(offset int) *AdminQuery { + _q.ctx.Offset = &offset + return _q +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (_q *AdminQuery) Unique(unique bool) *AdminQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *AdminQuery) Order(o ...admin.OrderOption) *AdminQuery { + _q.order = append(_q.order, o...) + return _q +} + +// First returns the first Admin entity from the query. +// Returns a *NotFoundError when no Admin was found. +func (_q *AdminQuery) First(ctx context.Context) (*Admin, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{admin.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *AdminQuery) FirstX(ctx context.Context) *Admin { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Admin ID from the query. +// Returns a *NotFoundError when no Admin ID was found. +func (_q *AdminQuery) FirstID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{admin.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *AdminQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Admin entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Admin entity is found. +// Returns a *NotFoundError when no Admin entities are found. +func (_q *AdminQuery) Only(ctx context.Context) (*Admin, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{admin.Label} + default: + return nil, &NotSingularError{admin.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *AdminQuery) OnlyX(ctx context.Context) *Admin { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Admin ID in the query. +// Returns a *NotSingularError when more than one Admin ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *AdminQuery) OnlyID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{admin.Label} + default: + err = &NotSingularError{admin.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *AdminQuery) OnlyIDX(ctx context.Context) int64 { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Admins. +func (_q *AdminQuery) All(ctx context.Context) ([]*Admin, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Admin, *AdminQuery]() + return withInterceptors[[]*Admin](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *AdminQuery) AllX(ctx context.Context) []*Admin { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Admin IDs. +func (_q *AdminQuery) IDs(ctx context.Context) (ids []int64, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(admin.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *AdminQuery) IDsX(ctx context.Context) []int64 { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *AdminQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*AdminQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *AdminQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *AdminQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (_q *AdminQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the AdminQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *AdminQuery) Clone() *AdminQuery { + if _q == nil { + return nil + } + return &AdminQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]admin.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.Admin{}, _q.predicates...), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Admin.Query(). +// GroupBy(admin.FieldName). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *AdminQuery) GroupBy(field string, fields ...string) *AdminGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &AdminGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = admin.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// } +// +// client.Admin.Query(). +// Select(admin.FieldName). +// Scan(ctx, &v) +func (_q *AdminQuery) Select(fields ...string) *AdminSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &AdminSelect{AdminQuery: _q} + sbuild.label = admin.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a AdminSelect configured with the given aggregations. +func (_q *AdminQuery) Aggregate(fns ...AggregateFunc) *AdminSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *AdminQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !admin.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *AdminQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Admin, error) { + var ( + nodes = []*Admin{} + _spec = _q.querySpec() + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Admin).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Admin{config: _q.config} + nodes = append(nodes, node) + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + return nodes, nil +} + +func (_q *AdminQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *AdminQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(admin.Table, admin.Columns, sqlgraph.NewFieldSpec(admin.FieldID, field.TypeInt64)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, admin.FieldID) + for i := range fields { + if fields[i] != admin.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *AdminQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(admin.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = admin.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// AdminGroupBy is the group-by builder for Admin entities. +type AdminGroupBy struct { + selector + build *AdminQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *AdminGroupBy) Aggregate(fns ...AggregateFunc) *AdminGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *AdminGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*AdminQuery, *AdminGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *AdminGroupBy) sqlScan(ctx context.Context, root *AdminQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// AdminSelect is the builder for selecting fields of Admin entities. +type AdminSelect struct { + *AdminQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *AdminSelect) Aggregate(fns ...AggregateFunc) *AdminSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *AdminSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*AdminQuery, *AdminSelect](ctx, _s.AdminQuery, _s, _s.inters, v) +} + +func (_s *AdminSelect) sqlScan(ctx context.Context, root *AdminQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/internal/data/ent/admin_update.go b/internal/data/ent/admin_update.go new file mode 100644 index 0000000..ca468b8 --- /dev/null +++ b/internal/data/ent/admin_update.go @@ -0,0 +1,382 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "kra/internal/data/ent/admin" + "kra/internal/data/ent/predicate" +) + +// AdminUpdate is the builder for updating Admin entities. +type AdminUpdate struct { + config + hooks []Hook + mutation *AdminMutation +} + +// Where appends a list predicates to the AdminUpdate builder. +func (_u *AdminUpdate) Where(ps ...predicate.Admin) *AdminUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetName sets the "name" field. +func (_u *AdminUpdate) SetName(v string) *AdminUpdate { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *AdminUpdate) SetNillableName(v *string) *AdminUpdate { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetEmail sets the "email" field. +func (_u *AdminUpdate) SetEmail(v string) *AdminUpdate { + _u.mutation.SetEmail(v) + return _u +} + +// SetNillableEmail sets the "email" field if the given value is not nil. +func (_u *AdminUpdate) SetNillableEmail(v *string) *AdminUpdate { + if v != nil { + _u.SetEmail(*v) + } + return _u +} + +// SetAvatar sets the "avatar" field. +func (_u *AdminUpdate) SetAvatar(v string) *AdminUpdate { + _u.mutation.SetAvatar(v) + return _u +} + +// SetNillableAvatar sets the "avatar" field if the given value is not nil. +func (_u *AdminUpdate) SetNillableAvatar(v *string) *AdminUpdate { + if v != nil { + _u.SetAvatar(*v) + } + return _u +} + +// SetAccess sets the "access" field. +func (_u *AdminUpdate) SetAccess(v string) *AdminUpdate { + _u.mutation.SetAccess(v) + return _u +} + +// SetNillableAccess sets the "access" field if the given value is not nil. +func (_u *AdminUpdate) SetNillableAccess(v *string) *AdminUpdate { + if v != nil { + _u.SetAccess(*v) + } + return _u +} + +// SetPassword sets the "password" field. +func (_u *AdminUpdate) SetPassword(v string) *AdminUpdate { + _u.mutation.SetPassword(v) + return _u +} + +// SetNillablePassword sets the "password" field if the given value is not nil. +func (_u *AdminUpdate) SetNillablePassword(v *string) *AdminUpdate { + if v != nil { + _u.SetPassword(*v) + } + return _u +} + +// SetUpdateTime sets the "update_time" field. +func (_u *AdminUpdate) SetUpdateTime(v time.Time) *AdminUpdate { + _u.mutation.SetUpdateTime(v) + return _u +} + +// Mutation returns the AdminMutation object of the builder. +func (_u *AdminUpdate) Mutation() *AdminMutation { + return _u.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *AdminUpdate) Save(ctx context.Context) (int, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *AdminUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *AdminUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *AdminUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *AdminUpdate) defaults() { + if _, ok := _u.mutation.UpdateTime(); !ok { + v := admin.UpdateDefaultUpdateTime() + _u.mutation.SetUpdateTime(v) + } +} + +func (_u *AdminUpdate) sqlSave(ctx context.Context) (_node int, err error) { + _spec := sqlgraph.NewUpdateSpec(admin.Table, admin.Columns, sqlgraph.NewFieldSpec(admin.FieldID, field.TypeInt64)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(admin.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Email(); ok { + _spec.SetField(admin.FieldEmail, field.TypeString, value) + } + if value, ok := _u.mutation.Avatar(); ok { + _spec.SetField(admin.FieldAvatar, field.TypeString, value) + } + if value, ok := _u.mutation.Access(); ok { + _spec.SetField(admin.FieldAccess, field.TypeString, value) + } + if value, ok := _u.mutation.Password(); ok { + _spec.SetField(admin.FieldPassword, field.TypeString, value) + } + if value, ok := _u.mutation.UpdateTime(); ok { + _spec.SetField(admin.FieldUpdateTime, field.TypeTime, value) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{admin.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// AdminUpdateOne is the builder for updating a single Admin entity. +type AdminUpdateOne struct { + config + fields []string + hooks []Hook + mutation *AdminMutation +} + +// SetName sets the "name" field. +func (_u *AdminUpdateOne) SetName(v string) *AdminUpdateOne { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *AdminUpdateOne) SetNillableName(v *string) *AdminUpdateOne { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetEmail sets the "email" field. +func (_u *AdminUpdateOne) SetEmail(v string) *AdminUpdateOne { + _u.mutation.SetEmail(v) + return _u +} + +// SetNillableEmail sets the "email" field if the given value is not nil. +func (_u *AdminUpdateOne) SetNillableEmail(v *string) *AdminUpdateOne { + if v != nil { + _u.SetEmail(*v) + } + return _u +} + +// SetAvatar sets the "avatar" field. +func (_u *AdminUpdateOne) SetAvatar(v string) *AdminUpdateOne { + _u.mutation.SetAvatar(v) + return _u +} + +// SetNillableAvatar sets the "avatar" field if the given value is not nil. +func (_u *AdminUpdateOne) SetNillableAvatar(v *string) *AdminUpdateOne { + if v != nil { + _u.SetAvatar(*v) + } + return _u +} + +// SetAccess sets the "access" field. +func (_u *AdminUpdateOne) SetAccess(v string) *AdminUpdateOne { + _u.mutation.SetAccess(v) + return _u +} + +// SetNillableAccess sets the "access" field if the given value is not nil. +func (_u *AdminUpdateOne) SetNillableAccess(v *string) *AdminUpdateOne { + if v != nil { + _u.SetAccess(*v) + } + return _u +} + +// SetPassword sets the "password" field. +func (_u *AdminUpdateOne) SetPassword(v string) *AdminUpdateOne { + _u.mutation.SetPassword(v) + return _u +} + +// SetNillablePassword sets the "password" field if the given value is not nil. +func (_u *AdminUpdateOne) SetNillablePassword(v *string) *AdminUpdateOne { + if v != nil { + _u.SetPassword(*v) + } + return _u +} + +// SetUpdateTime sets the "update_time" field. +func (_u *AdminUpdateOne) SetUpdateTime(v time.Time) *AdminUpdateOne { + _u.mutation.SetUpdateTime(v) + return _u +} + +// Mutation returns the AdminMutation object of the builder. +func (_u *AdminUpdateOne) Mutation() *AdminMutation { + return _u.mutation +} + +// Where appends a list predicates to the AdminUpdate builder. +func (_u *AdminUpdateOne) Where(ps ...predicate.Admin) *AdminUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *AdminUpdateOne) Select(field string, fields ...string) *AdminUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated Admin entity. +func (_u *AdminUpdateOne) Save(ctx context.Context) (*Admin, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *AdminUpdateOne) SaveX(ctx context.Context) *Admin { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *AdminUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *AdminUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *AdminUpdateOne) defaults() { + if _, ok := _u.mutation.UpdateTime(); !ok { + v := admin.UpdateDefaultUpdateTime() + _u.mutation.SetUpdateTime(v) + } +} + +func (_u *AdminUpdateOne) sqlSave(ctx context.Context) (_node *Admin, err error) { + _spec := sqlgraph.NewUpdateSpec(admin.Table, admin.Columns, sqlgraph.NewFieldSpec(admin.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Admin.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, admin.FieldID) + for _, f := range fields { + if !admin.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != admin.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(admin.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Email(); ok { + _spec.SetField(admin.FieldEmail, field.TypeString, value) + } + if value, ok := _u.mutation.Avatar(); ok { + _spec.SetField(admin.FieldAvatar, field.TypeString, value) + } + if value, ok := _u.mutation.Access(); ok { + _spec.SetField(admin.FieldAccess, field.TypeString, value) + } + if value, ok := _u.mutation.Password(); ok { + _spec.SetField(admin.FieldPassword, field.TypeString, value) + } + if value, ok := _u.mutation.UpdateTime(); ok { + _spec.SetField(admin.FieldUpdateTime, field.TypeTime, value) + } + _node = &Admin{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{admin.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/internal/data/ent/client.go b/internal/data/ent/client.go new file mode 100644 index 0000000..a363e2d --- /dev/null +++ b/internal/data/ent/client.go @@ -0,0 +1,366 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "log" + "reflect" + + "kra/internal/data/ent/migrate" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "kra/internal/data/ent/admin" + + stdsql "database/sql" +) + +// Client is the client that holds all ent builders. +type Client struct { + config + // Schema is the client for creating, migrating and dropping schema. + Schema *migrate.Schema + // Admin is the client for interacting with the Admin builders. + Admin *AdminClient +} + +// NewClient creates a new client configured with the given options. +func NewClient(opts ...Option) *Client { + client := &Client{config: newConfig(opts...)} + client.init() + return client +} + +func (c *Client) init() { + c.Schema = migrate.NewSchema(c.driver) + c.Admin = NewAdminClient(c.config) +} + +type ( + // config is the configuration for the client and its builder. + config struct { + // driver used for executing database requests. + driver dialect.Driver + // debug enable a debug logging. + debug bool + // log used for logging on debug mode. + log func(...any) + // hooks to execute on mutations. + hooks *hooks + // interceptors to execute on queries. + inters *inters + } + // Option function to configure the client. + Option func(*config) +) + +// newConfig creates a new config for the client. +func newConfig(opts ...Option) config { + cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}} + cfg.options(opts...) + return cfg +} + +// options applies the options on the config object. +func (c *config) options(opts ...Option) { + for _, opt := range opts { + opt(c) + } + if c.debug { + c.driver = dialect.Debug(c.driver, c.log) + } +} + +// Debug enables debug logging on the ent.Driver. +func Debug() Option { + return func(c *config) { + c.debug = true + } +} + +// Log sets the logging function for debug mode. +func Log(fn func(...any)) Option { + return func(c *config) { + c.log = fn + } +} + +// Driver configures the client driver. +func Driver(driver dialect.Driver) Option { + return func(c *config) { + c.driver = driver + } +} + +// Open opens a database/sql.DB specified by the driver name and +// the data source name, and returns a new client attached to it. +// Optional parameters can be added for configuring the client. +func Open(driverName, dataSourceName string, options ...Option) (*Client, error) { + switch driverName { + case dialect.MySQL, dialect.Postgres, dialect.SQLite: + drv, err := sql.Open(driverName, dataSourceName) + if err != nil { + return nil, err + } + return NewClient(append(options, Driver(drv))...), nil + default: + return nil, fmt.Errorf("unsupported driver: %q", driverName) + } +} + +// ErrTxStarted is returned when trying to start a new transaction from a transactional client. +var ErrTxStarted = errors.New("ent: cannot start a transaction within a transaction") + +// Tx returns a new transactional client. The provided context +// is used until the transaction is committed or rolled back. +func (c *Client) Tx(ctx context.Context) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, ErrTxStarted + } + tx, err := newTx(ctx, c.driver) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %w", err) + } + cfg := c.config + cfg.driver = tx + return &Tx{ + ctx: ctx, + config: cfg, + Admin: NewAdminClient(cfg), + }, nil +} + +// BeginTx returns a transactional client with specified options. +func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, errors.New("ent: cannot start a transaction within a transaction") + } + tx, err := c.driver.(interface { + BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error) + }).BeginTx(ctx, opts) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %w", err) + } + cfg := c.config + cfg.driver = &txDriver{tx: tx, drv: c.driver} + return &Tx{ + ctx: ctx, + config: cfg, + Admin: NewAdminClient(cfg), + }, nil +} + +// Debug returns a new debug-client. It's used to get verbose logging on specific operations. +// +// client.Debug(). +// Admin. +// Query(). +// Count(ctx) +func (c *Client) Debug() *Client { + if c.debug { + return c + } + cfg := c.config + cfg.driver = dialect.Debug(c.driver, c.log) + client := &Client{config: cfg} + client.init() + return client +} + +// Close closes the database connection and prevents new queries from starting. +func (c *Client) Close() error { + return c.driver.Close() +} + +// Use adds the mutation hooks to all the entity clients. +// In order to add hooks to a specific client, call: `client.Node.Use(...)`. +func (c *Client) Use(hooks ...Hook) { + c.Admin.Use(hooks...) +} + +// Intercept adds the query interceptors to all the entity clients. +// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. +func (c *Client) Intercept(interceptors ...Interceptor) { + c.Admin.Intercept(interceptors...) +} + +// Mutate implements the ent.Mutator interface. +func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { + switch m := m.(type) { + case *AdminMutation: + return c.Admin.mutate(ctx, m) + default: + return nil, fmt.Errorf("ent: unknown mutation type %T", m) + } +} + +// AdminClient is a client for the Admin schema. +type AdminClient struct { + config +} + +// NewAdminClient returns a client for the Admin from the given config. +func NewAdminClient(c config) *AdminClient { + return &AdminClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `admin.Hooks(f(g(h())))`. +func (c *AdminClient) Use(hooks ...Hook) { + c.hooks.Admin = append(c.hooks.Admin, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `admin.Intercept(f(g(h())))`. +func (c *AdminClient) Intercept(interceptors ...Interceptor) { + c.inters.Admin = append(c.inters.Admin, interceptors...) +} + +// Create returns a builder for creating a Admin entity. +func (c *AdminClient) Create() *AdminCreate { + mutation := newAdminMutation(c.config, OpCreate) + return &AdminCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Admin entities. +func (c *AdminClient) CreateBulk(builders ...*AdminCreate) *AdminCreateBulk { + return &AdminCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *AdminClient) MapCreateBulk(slice any, setFunc func(*AdminCreate, int)) *AdminCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &AdminCreateBulk{err: fmt.Errorf("calling to AdminClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*AdminCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &AdminCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Admin. +func (c *AdminClient) Update() *AdminUpdate { + mutation := newAdminMutation(c.config, OpUpdate) + return &AdminUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *AdminClient) UpdateOne(_m *Admin) *AdminUpdateOne { + mutation := newAdminMutation(c.config, OpUpdateOne, withAdmin(_m)) + return &AdminUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *AdminClient) UpdateOneID(id int64) *AdminUpdateOne { + mutation := newAdminMutation(c.config, OpUpdateOne, withAdminID(id)) + return &AdminUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Admin. +func (c *AdminClient) Delete() *AdminDelete { + mutation := newAdminMutation(c.config, OpDelete) + return &AdminDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *AdminClient) DeleteOne(_m *Admin) *AdminDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *AdminClient) DeleteOneID(id int64) *AdminDeleteOne { + builder := c.Delete().Where(admin.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &AdminDeleteOne{builder} +} + +// Query returns a query builder for Admin. +func (c *AdminClient) Query() *AdminQuery { + return &AdminQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeAdmin}, + inters: c.Interceptors(), + } +} + +// Get returns a Admin entity by its id. +func (c *AdminClient) Get(ctx context.Context, id int64) (*Admin, error) { + return c.Query().Where(admin.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *AdminClient) GetX(ctx context.Context, id int64) *Admin { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// Hooks returns the client hooks. +func (c *AdminClient) Hooks() []Hook { + return c.hooks.Admin +} + +// Interceptors returns the client interceptors. +func (c *AdminClient) Interceptors() []Interceptor { + return c.inters.Admin +} + +func (c *AdminClient) mutate(ctx context.Context, m *AdminMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&AdminCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&AdminUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&AdminUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&AdminDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Admin mutation op: %q", m.Op()) + } +} + +// hooks and interceptors per client, for fast access. +type ( + hooks struct { + Admin []ent.Hook + } + inters struct { + Admin []ent.Interceptor + } +) + +// ExecContext allows calling the underlying ExecContext method of the driver if it is supported by it. +// See, database/sql#DB.ExecContext for more information. +func (c *config) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) { + ex, ok := c.driver.(interface { + ExecContext(context.Context, string, ...any) (stdsql.Result, error) + }) + if !ok { + return nil, fmt.Errorf("Driver.ExecContext is not supported") + } + return ex.ExecContext(ctx, query, args...) +} + +// QueryContext allows calling the underlying QueryContext method of the driver if it is supported by it. +// See, database/sql#DB.QueryContext for more information. +func (c *config) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) { + q, ok := c.driver.(interface { + QueryContext(context.Context, string, ...any) (*stdsql.Rows, error) + }) + if !ok { + return nil, fmt.Errorf("Driver.QueryContext is not supported") + } + return q.QueryContext(ctx, query, args...) +} diff --git a/internal/data/ent/ent.go b/internal/data/ent/ent.go new file mode 100644 index 0000000..1976d56 --- /dev/null +++ b/internal/data/ent/ent.go @@ -0,0 +1,608 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "reflect" + "sync" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "kra/internal/data/ent/admin" +) + +// ent aliases to avoid import conflicts in user's code. +type ( + Op = ent.Op + Hook = ent.Hook + Value = ent.Value + Query = ent.Query + QueryContext = ent.QueryContext + Querier = ent.Querier + QuerierFunc = ent.QuerierFunc + Interceptor = ent.Interceptor + InterceptFunc = ent.InterceptFunc + Traverser = ent.Traverser + TraverseFunc = ent.TraverseFunc + Policy = ent.Policy + Mutator = ent.Mutator + Mutation = ent.Mutation + MutateFunc = ent.MutateFunc +) + +type clientCtxKey struct{} + +// FromContext returns a Client stored inside a context, or nil if there isn't one. +func FromContext(ctx context.Context) *Client { + c, _ := ctx.Value(clientCtxKey{}).(*Client) + return c +} + +// NewContext returns a new context with the given Client attached. +func NewContext(parent context.Context, c *Client) context.Context { + return context.WithValue(parent, clientCtxKey{}, c) +} + +type txCtxKey struct{} + +// TxFromContext returns a Tx stored inside a context, or nil if there isn't one. +func TxFromContext(ctx context.Context) *Tx { + tx, _ := ctx.Value(txCtxKey{}).(*Tx) + return tx +} + +// NewTxContext returns a new context with the given Tx attached. +func NewTxContext(parent context.Context, tx *Tx) context.Context { + return context.WithValue(parent, txCtxKey{}, tx) +} + +// OrderFunc applies an ordering on the sql selector. +// Deprecated: Use Asc/Desc functions or the package builders instead. +type OrderFunc func(*sql.Selector) + +var ( + initCheck sync.Once + columnCheck sql.ColumnCheck +) + +// checkColumn checks if the column exists in the given table. +func checkColumn(t, c string) error { + initCheck.Do(func() { + columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ + admin.Table: admin.ValidColumn, + }) + }) + return columnCheck(t, c) +} + +// Asc applies the given fields in ASC order. +func Asc(fields ...string) func(*sql.Selector) { + return func(s *sql.Selector) { + for _, f := range fields { + if err := checkColumn(s.TableName(), f); err != nil { + s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) + } + s.OrderBy(sql.Asc(s.C(f))) + } + } +} + +// Desc applies the given fields in DESC order. +func Desc(fields ...string) func(*sql.Selector) { + return func(s *sql.Selector) { + for _, f := range fields { + if err := checkColumn(s.TableName(), f); err != nil { + s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) + } + s.OrderBy(sql.Desc(s.C(f))) + } + } +} + +// AggregateFunc applies an aggregation step on the group-by traversal/selector. +type AggregateFunc func(*sql.Selector) string + +// As is a pseudo aggregation function for renaming another other functions with custom names. For example: +// +// GroupBy(field1, field2). +// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")). +// Scan(ctx, &v) +func As(fn AggregateFunc, end string) AggregateFunc { + return func(s *sql.Selector) string { + return sql.As(fn(s), end) + } +} + +// Count applies the "count" aggregation function on each group. +func Count() AggregateFunc { + return func(s *sql.Selector) string { + return sql.Count("*") + } +} + +// Max applies the "max" aggregation function on the given field of each group. +func Max(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Max(s.C(field)) + } +} + +// Mean applies the "mean" aggregation function on the given field of each group. +func Mean(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Avg(s.C(field)) + } +} + +// Min applies the "min" aggregation function on the given field of each group. +func Min(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Min(s.C(field)) + } +} + +// Sum applies the "sum" aggregation function on the given field of each group. +func Sum(field string) AggregateFunc { + return func(s *sql.Selector) string { + if err := checkColumn(s.TableName(), field); err != nil { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) + return "" + } + return sql.Sum(s.C(field)) + } +} + +// ValidationError returns when validating a field or edge fails. +type ValidationError struct { + Name string // Field or edge name. + err error +} + +// Error implements the error interface. +func (e *ValidationError) Error() string { + return e.err.Error() +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ValidationError) Unwrap() error { + return e.err +} + +// IsValidationError returns a boolean indicating whether the error is a validation error. +func IsValidationError(err error) bool { + if err == nil { + return false + } + var e *ValidationError + return errors.As(err, &e) +} + +// NotFoundError returns when trying to fetch a specific entity and it was not found in the database. +type NotFoundError struct { + label string +} + +// Error implements the error interface. +func (e *NotFoundError) Error() string { + return "ent: " + e.label + " not found" +} + +// IsNotFound returns a boolean indicating whether the error is a not found error. +func IsNotFound(err error) bool { + if err == nil { + return false + } + var e *NotFoundError + return errors.As(err, &e) +} + +// MaskNotFound masks not found error. +func MaskNotFound(err error) error { + if IsNotFound(err) { + return nil + } + return err +} + +// NotSingularError returns when trying to fetch a singular entity and more then one was found in the database. +type NotSingularError struct { + label string +} + +// Error implements the error interface. +func (e *NotSingularError) Error() string { + return "ent: " + e.label + " not singular" +} + +// IsNotSingular returns a boolean indicating whether the error is a not singular error. +func IsNotSingular(err error) bool { + if err == nil { + return false + } + var e *NotSingularError + return errors.As(err, &e) +} + +// NotLoadedError returns when trying to get a node that was not loaded by the query. +type NotLoadedError struct { + edge string +} + +// Error implements the error interface. +func (e *NotLoadedError) Error() string { + return "ent: " + e.edge + " edge was not loaded" +} + +// IsNotLoaded returns a boolean indicating whether the error is a not loaded error. +func IsNotLoaded(err error) bool { + if err == nil { + return false + } + var e *NotLoadedError + return errors.As(err, &e) +} + +// ConstraintError returns when trying to create/update one or more entities and +// one or more of their constraints failed. For example, violation of edge or +// field uniqueness. +type ConstraintError struct { + msg string + wrap error +} + +// Error implements the error interface. +func (e ConstraintError) Error() string { + return "ent: constraint failed: " + e.msg +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ConstraintError) Unwrap() error { + return e.wrap +} + +// IsConstraintError returns a boolean indicating whether the error is a constraint failure. +func IsConstraintError(err error) bool { + if err == nil { + return false + } + var e *ConstraintError + return errors.As(err, &e) +} + +// selector embedded by the different Select/GroupBy builders. +type selector struct { + label string + flds *[]string + fns []AggregateFunc + scan func(context.Context, any) error +} + +// ScanX is like Scan, but panics if an error occurs. +func (s *selector) ScanX(ctx context.Context, v any) { + if err := s.scan(ctx, v); err != nil { + panic(err) + } +} + +// Strings returns list of strings from a selector. It is only allowed when selecting one field. +func (s *selector) Strings(ctx context.Context) ([]string, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Strings is not achievable when selecting more than 1 field") + } + var v []string + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// StringsX is like Strings, but panics if an error occurs. +func (s *selector) StringsX(ctx context.Context) []string { + v, err := s.Strings(ctx) + if err != nil { + panic(err) + } + return v +} + +// String returns a single string from a selector. It is only allowed when selecting one field. +func (s *selector) String(ctx context.Context) (_ string, err error) { + var v []string + if v, err = s.Strings(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Strings returned %d results when one was expected", len(v)) + } + return +} + +// StringX is like String, but panics if an error occurs. +func (s *selector) StringX(ctx context.Context) string { + v, err := s.String(ctx) + if err != nil { + panic(err) + } + return v +} + +// Ints returns list of ints from a selector. It is only allowed when selecting one field. +func (s *selector) Ints(ctx context.Context) ([]int, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Ints is not achievable when selecting more than 1 field") + } + var v []int + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// IntsX is like Ints, but panics if an error occurs. +func (s *selector) IntsX(ctx context.Context) []int { + v, err := s.Ints(ctx) + if err != nil { + panic(err) + } + return v +} + +// Int returns a single int from a selector. It is only allowed when selecting one field. +func (s *selector) Int(ctx context.Context) (_ int, err error) { + var v []int + if v, err = s.Ints(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Ints returned %d results when one was expected", len(v)) + } + return +} + +// IntX is like Int, but panics if an error occurs. +func (s *selector) IntX(ctx context.Context) int { + v, err := s.Int(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64s returns list of float64s from a selector. It is only allowed when selecting one field. +func (s *selector) Float64s(ctx context.Context) ([]float64, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Float64s is not achievable when selecting more than 1 field") + } + var v []float64 + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// Float64sX is like Float64s, but panics if an error occurs. +func (s *selector) Float64sX(ctx context.Context) []float64 { + v, err := s.Float64s(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64 returns a single float64 from a selector. It is only allowed when selecting one field. +func (s *selector) Float64(ctx context.Context) (_ float64, err error) { + var v []float64 + if v, err = s.Float64s(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Float64s returned %d results when one was expected", len(v)) + } + return +} + +// Float64X is like Float64, but panics if an error occurs. +func (s *selector) Float64X(ctx context.Context) float64 { + v, err := s.Float64(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bools returns list of bools from a selector. It is only allowed when selecting one field. +func (s *selector) Bools(ctx context.Context) ([]bool, error) { + if len(*s.flds) > 1 { + return nil, errors.New("ent: Bools is not achievable when selecting more than 1 field") + } + var v []bool + if err := s.scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// BoolsX is like Bools, but panics if an error occurs. +func (s *selector) BoolsX(ctx context.Context) []bool { + v, err := s.Bools(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bool returns a single bool from a selector. It is only allowed when selecting one field. +func (s *selector) Bool(ctx context.Context) (_ bool, err error) { + var v []bool + if v, err = s.Bools(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{s.label} + default: + err = fmt.Errorf("ent: Bools returned %d results when one was expected", len(v)) + } + return +} + +// BoolX is like Bool, but panics if an error occurs. +func (s *selector) BoolX(ctx context.Context) bool { + v, err := s.Bool(ctx) + if err != nil { + panic(err) + } + return v +} + +// withHooks invokes the builder operation with the given hooks, if any. +func withHooks[V Value, M any, PM interface { + *M + Mutation +}](ctx context.Context, exec func(context.Context) (V, error), mutation PM, hooks []Hook) (value V, err error) { + if len(hooks) == 0 { + return exec(ctx) + } + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutationT, ok := any(m).(PM) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + // Set the mutation to the builder. + *mutation = *mutationT + return exec(ctx) + }) + for i := len(hooks) - 1; i >= 0; i-- { + if hooks[i] == nil { + return value, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)") + } + mut = hooks[i](mut) + } + v, err := mut.Mutate(ctx, mutation) + if err != nil { + return value, err + } + nv, ok := v.(V) + if !ok { + return value, fmt.Errorf("unexpected node type %T returned from %T", v, mutation) + } + return nv, nil +} + +// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist. +func setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context { + if ent.QueryFromContext(ctx) == nil { + qc.Op = op + ctx = ent.NewQueryContext(ctx, qc) + } + return ctx +} + +func querierAll[V Value, Q interface { + sqlAll(context.Context, ...queryHook) (V, error) +}]() Querier { + return QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + query, ok := q.(Q) + if !ok { + return nil, fmt.Errorf("unexpected query type %T", q) + } + return query.sqlAll(ctx) + }) +} + +func querierCount[Q interface { + sqlCount(context.Context) (int, error) +}]() Querier { + return QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + query, ok := q.(Q) + if !ok { + return nil, fmt.Errorf("unexpected query type %T", q) + } + return query.sqlCount(ctx) + }) +} + +func withInterceptors[V Value](ctx context.Context, q Query, qr Querier, inters []Interceptor) (v V, err error) { + for i := len(inters) - 1; i >= 0; i-- { + qr = inters[i].Intercept(qr) + } + rv, err := qr.Query(ctx, q) + if err != nil { + return v, err + } + vt, ok := rv.(V) + if !ok { + return v, fmt.Errorf("unexpected type %T returned from %T. expected type: %T", vt, q, v) + } + return vt, nil +} + +func scanWithInterceptors[Q1 ent.Query, Q2 interface { + sqlScan(context.Context, Q1, any) error +}](ctx context.Context, rootQuery Q1, selectOrGroup Q2, inters []Interceptor, v any) error { + rv := reflect.ValueOf(v) + var qr Querier = QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + query, ok := q.(Q1) + if !ok { + return nil, fmt.Errorf("unexpected query type %T", q) + } + if err := selectOrGroup.sqlScan(ctx, query, v); err != nil { + return nil, err + } + if k := rv.Kind(); k == reflect.Pointer && rv.Elem().CanInterface() { + return rv.Elem().Interface(), nil + } + return v, nil + }) + for i := len(inters) - 1; i >= 0; i-- { + qr = inters[i].Intercept(qr) + } + vv, err := qr.Query(ctx, rootQuery) + if err != nil { + return err + } + switch rv2 := reflect.ValueOf(vv); { + case rv.IsNil(), rv2.IsNil(), rv.Kind() != reflect.Pointer: + case rv.Type() == rv2.Type(): + rv.Elem().Set(rv2.Elem()) + case rv.Elem().Type() == rv2.Type(): + rv.Elem().Set(rv2) + } + return nil +} + +// queryHook describes an internal hook for the different sqlAll methods. +type queryHook func(context.Context, *sqlgraph.QuerySpec) diff --git a/internal/data/ent/enttest/enttest.go b/internal/data/ent/enttest/enttest.go new file mode 100644 index 0000000..6b9daaf --- /dev/null +++ b/internal/data/ent/enttest/enttest.go @@ -0,0 +1,84 @@ +// Code generated by ent, DO NOT EDIT. + +package enttest + +import ( + "context" + + "kra/internal/data/ent" + // required by schema hooks. + _ "kra/internal/data/ent/runtime" + + "entgo.io/ent/dialect/sql/schema" + "kra/internal/data/ent/migrate" +) + +type ( + // TestingT is the interface that is shared between + // testing.T and testing.B and used by enttest. + TestingT interface { + FailNow() + Error(...any) + } + + // Option configures client creation. + Option func(*options) + + options struct { + opts []ent.Option + migrateOpts []schema.MigrateOption + } +) + +// WithOptions forwards options to client creation. +func WithOptions(opts ...ent.Option) Option { + return func(o *options) { + o.opts = append(o.opts, opts...) + } +} + +// WithMigrateOptions forwards options to auto migration. +func WithMigrateOptions(opts ...schema.MigrateOption) Option { + return func(o *options) { + o.migrateOpts = append(o.migrateOpts, opts...) + } +} + +func newOptions(opts []Option) *options { + o := &options{} + for _, opt := range opts { + opt(o) + } + return o +} + +// Open calls ent.Open and auto-run migration. +func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { + o := newOptions(opts) + c, err := ent.Open(driverName, dataSourceName, o.opts...) + if err != nil { + t.Error(err) + t.FailNow() + } + migrateSchema(t, c, o) + return c +} + +// NewClient calls ent.NewClient and auto-run migration. +func NewClient(t TestingT, opts ...Option) *ent.Client { + o := newOptions(opts) + c := ent.NewClient(o.opts...) + migrateSchema(t, c, o) + return c +} +func migrateSchema(t TestingT, c *ent.Client, o *options) { + tables, err := schema.CopyTables(migrate.Tables) + if err != nil { + t.Error(err) + t.FailNow() + } + if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil { + t.Error(err) + t.FailNow() + } +} diff --git a/internal/data/ent/generate.go b/internal/data/ent/generate.go new file mode 100644 index 0000000..67985fa --- /dev/null +++ b/internal/data/ent/generate.go @@ -0,0 +1,3 @@ +package ent + +//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema --feature sql/execquery --feature sql/upsert diff --git a/internal/data/ent/hook/hook.go b/internal/data/ent/hook/hook.go new file mode 100644 index 0000000..cb9a040 --- /dev/null +++ b/internal/data/ent/hook/hook.go @@ -0,0 +1,199 @@ +// Code generated by ent, DO NOT EDIT. + +package hook + +import ( + "context" + "fmt" + + "kra/internal/data/ent" +) + +// The AdminFunc type is an adapter to allow the use of ordinary +// function as Admin mutator. +type AdminFunc func(context.Context, *ent.AdminMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f AdminFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.AdminMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AdminMutation", m) +} + +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. +// +// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) +func If(hk ent.Hook, cond Condition) ent.Hook { + return func(next ent.Mutator) ent.Mutator { + return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if cond(ctx, m) { + return hk(next).Mutate(ctx, m) + } + return next.Mutate(ctx, m) + }) + } +} + +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + +// Unless skips the given hook only for the given operation. +// +// hook.Unless(Log, ent.Update|ent.UpdateOne) +func Unless(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, Not(HasOp(op))) +} + +// FixedError is a hook returning a fixed error. +func FixedError(err error) ent.Hook { + return func(ent.Mutator) ent.Mutator { + return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) { + return nil, err + }) + } +} + +// Reject returns a hook that rejects all operations that match op. +// +// func (T) Hooks() []ent.Hook { +// return []ent.Hook{ +// Reject(ent.Delete|ent.Update), +// } +// } +func Reject(op ent.Op) ent.Hook { + hk := FixedError(fmt.Errorf("%s operation is not allowed", op)) + return On(hk, op) +} + +// Chain acts as a list of hooks and is effectively immutable. +// Once created, it will always hold the same set of hooks in the same order. +type Chain struct { + hooks []ent.Hook +} + +// NewChain creates a new chain of hooks. +func NewChain(hooks ...ent.Hook) Chain { + return Chain{append([]ent.Hook(nil), hooks...)} +} + +// Hook chains the list of hooks and returns the final hook. +func (c Chain) Hook() ent.Hook { + return func(mutator ent.Mutator) ent.Mutator { + for i := len(c.hooks) - 1; i >= 0; i-- { + mutator = c.hooks[i](mutator) + } + return mutator + } +} + +// Append extends a chain, adding the specified hook +// as the last ones in the mutation flow. +func (c Chain) Append(hooks ...ent.Hook) Chain { + newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks)) + newHooks = append(newHooks, c.hooks...) + newHooks = append(newHooks, hooks...) + return Chain{newHooks} +} + +// Extend extends a chain, adding the specified chain +// as the last ones in the mutation flow. +func (c Chain) Extend(chain Chain) Chain { + return c.Append(chain.hooks...) +} diff --git a/internal/data/ent/migrate/migrate.go b/internal/data/ent/migrate/migrate.go new file mode 100644 index 0000000..1956a6b --- /dev/null +++ b/internal/data/ent/migrate/migrate.go @@ -0,0 +1,64 @@ +// Code generated by ent, DO NOT EDIT. + +package migrate + +import ( + "context" + "fmt" + "io" + + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql/schema" +) + +var ( + // WithGlobalUniqueID sets the universal ids options to the migration. + // If this option is enabled, ent migration will allocate a 1<<32 range + // for the ids of each entity (table). + // Note that this option cannot be applied on tables that already exist. + WithGlobalUniqueID = schema.WithGlobalUniqueID + // WithDropColumn sets the drop column option to the migration. + // If this option is enabled, ent migration will drop old columns + // that were used for both fields and edges. This defaults to false. + WithDropColumn = schema.WithDropColumn + // WithDropIndex sets the drop index option to the migration. + // If this option is enabled, ent migration will drop old indexes + // that were defined in the schema. This defaults to false. + // Note that unique constraints are defined using `UNIQUE INDEX`, + // and therefore, it's recommended to enable this option to get more + // flexibility in the schema changes. + WithDropIndex = schema.WithDropIndex + // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. + WithForeignKeys = schema.WithForeignKeys +) + +// Schema is the API for creating, migrating and dropping a schema. +type Schema struct { + drv dialect.Driver +} + +// NewSchema creates a new schema client. +func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } + +// Create creates all schema resources. +func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { + return Create(ctx, s, Tables, opts...) +} + +// Create creates all table resources using the given schema driver. +func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error { + migrate, err := schema.NewMigrate(s.drv, opts...) + if err != nil { + return fmt.Errorf("ent/migrate: %w", err) + } + return migrate.Create(ctx, tables...) +} + +// WriteTo writes the schema changes to w instead of running them against the database. +// +// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { +// log.Fatal(err) +// } +func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { + return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...) +} diff --git a/internal/data/ent/migrate/schema.go b/internal/data/ent/migrate/schema.go new file mode 100644 index 0000000..c140ea5 --- /dev/null +++ b/internal/data/ent/migrate/schema.go @@ -0,0 +1,35 @@ +// Code generated by ent, DO NOT EDIT. + +package migrate + +import ( + "entgo.io/ent/dialect/sql/schema" + "entgo.io/ent/schema/field" +) + +var ( + // AdminsColumns holds the columns for the "admins" table. + AdminsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "name", Type: field.TypeString, Default: ""}, + {Name: "email", Type: field.TypeString, Default: ""}, + {Name: "avatar", Type: field.TypeString, Default: ""}, + {Name: "access", Type: field.TypeString, Default: ""}, + {Name: "password", Type: field.TypeString, Default: ""}, + {Name: "create_time", Type: field.TypeTime}, + {Name: "update_time", Type: field.TypeTime}, + } + // AdminsTable holds the schema information for the "admins" table. + AdminsTable = &schema.Table{ + Name: "admins", + Columns: AdminsColumns, + PrimaryKey: []*schema.Column{AdminsColumns[0]}, + } + // Tables holds all the tables in the schema. + Tables = []*schema.Table{ + AdminsTable, + } +) + +func init() { +} diff --git a/internal/data/ent/mutation.go b/internal/data/ent/mutation.go new file mode 100644 index 0000000..9ee90fa --- /dev/null +++ b/internal/data/ent/mutation.go @@ -0,0 +1,684 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "kra/internal/data/ent/admin" + "kra/internal/data/ent/predicate" +) + +const ( + // Operation types. + OpCreate = ent.OpCreate + OpDelete = ent.OpDelete + OpDeleteOne = ent.OpDeleteOne + OpUpdate = ent.OpUpdate + OpUpdateOne = ent.OpUpdateOne + + // Node types. + TypeAdmin = "Admin" +) + +// AdminMutation represents an operation that mutates the Admin nodes in the graph. +type AdminMutation struct { + config + op Op + typ string + id *int64 + name *string + email *string + avatar *string + access *string + password *string + create_time *time.Time + update_time *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*Admin, error) + predicates []predicate.Admin +} + +var _ ent.Mutation = (*AdminMutation)(nil) + +// adminOption allows management of the mutation configuration using functional options. +type adminOption func(*AdminMutation) + +// newAdminMutation creates new mutation for the Admin entity. +func newAdminMutation(c config, op Op, opts ...adminOption) *AdminMutation { + m := &AdminMutation{ + config: c, + op: op, + typ: TypeAdmin, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withAdminID sets the ID field of the mutation. +func withAdminID(id int64) adminOption { + return func(m *AdminMutation) { + var ( + err error + once sync.Once + value *Admin + ) + m.oldValue = func(ctx context.Context) (*Admin, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Admin.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withAdmin sets the old Admin of the mutation. +func withAdmin(node *Admin) adminOption { + return func(m *AdminMutation) { + m.oldValue = func(context.Context) (*Admin, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m AdminMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m AdminMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of Admin entities. +func (m *AdminMutation) SetID(id int64) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *AdminMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *AdminMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Admin.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetName sets the "name" field. +func (m *AdminMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *AdminMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *AdminMutation) ResetName() { + m.name = nil +} + +// SetEmail sets the "email" field. +func (m *AdminMutation) SetEmail(s string) { + m.email = &s +} + +// Email returns the value of the "email" field in the mutation. +func (m *AdminMutation) Email() (r string, exists bool) { + v := m.email + if v == nil { + return + } + return *v, true +} + +// OldEmail returns the old "email" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldEmail(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEmail is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEmail requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEmail: %w", err) + } + return oldValue.Email, nil +} + +// ResetEmail resets all changes to the "email" field. +func (m *AdminMutation) ResetEmail() { + m.email = nil +} + +// SetAvatar sets the "avatar" field. +func (m *AdminMutation) SetAvatar(s string) { + m.avatar = &s +} + +// Avatar returns the value of the "avatar" field in the mutation. +func (m *AdminMutation) Avatar() (r string, exists bool) { + v := m.avatar + if v == nil { + return + } + return *v, true +} + +// OldAvatar returns the old "avatar" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldAvatar(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAvatar is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAvatar requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAvatar: %w", err) + } + return oldValue.Avatar, nil +} + +// ResetAvatar resets all changes to the "avatar" field. +func (m *AdminMutation) ResetAvatar() { + m.avatar = nil +} + +// SetAccess sets the "access" field. +func (m *AdminMutation) SetAccess(s string) { + m.access = &s +} + +// Access returns the value of the "access" field in the mutation. +func (m *AdminMutation) Access() (r string, exists bool) { + v := m.access + if v == nil { + return + } + return *v, true +} + +// OldAccess returns the old "access" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldAccess(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAccess is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAccess requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAccess: %w", err) + } + return oldValue.Access, nil +} + +// ResetAccess resets all changes to the "access" field. +func (m *AdminMutation) ResetAccess() { + m.access = nil +} + +// SetPassword sets the "password" field. +func (m *AdminMutation) SetPassword(s string) { + m.password = &s +} + +// Password returns the value of the "password" field in the mutation. +func (m *AdminMutation) Password() (r string, exists bool) { + v := m.password + if v == nil { + return + } + return *v, true +} + +// OldPassword returns the old "password" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldPassword(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPassword is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPassword requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPassword: %w", err) + } + return oldValue.Password, nil +} + +// ResetPassword resets all changes to the "password" field. +func (m *AdminMutation) ResetPassword() { + m.password = nil +} + +// SetCreateTime sets the "create_time" field. +func (m *AdminMutation) SetCreateTime(t time.Time) { + m.create_time = &t +} + +// CreateTime returns the value of the "create_time" field in the mutation. +func (m *AdminMutation) CreateTime() (r time.Time, exists bool) { + v := m.create_time + if v == nil { + return + } + return *v, true +} + +// OldCreateTime returns the old "create_time" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldCreateTime(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreateTime is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreateTime requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreateTime: %w", err) + } + return oldValue.CreateTime, nil +} + +// ResetCreateTime resets all changes to the "create_time" field. +func (m *AdminMutation) ResetCreateTime() { + m.create_time = nil +} + +// SetUpdateTime sets the "update_time" field. +func (m *AdminMutation) SetUpdateTime(t time.Time) { + m.update_time = &t +} + +// UpdateTime returns the value of the "update_time" field in the mutation. +func (m *AdminMutation) UpdateTime() (r time.Time, exists bool) { + v := m.update_time + if v == nil { + return + } + return *v, true +} + +// OldUpdateTime returns the old "update_time" field's value of the Admin entity. +// If the Admin object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AdminMutation) OldUpdateTime(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdateTime is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdateTime requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdateTime: %w", err) + } + return oldValue.UpdateTime, nil +} + +// ResetUpdateTime resets all changes to the "update_time" field. +func (m *AdminMutation) ResetUpdateTime() { + m.update_time = nil +} + +// Where appends a list predicates to the AdminMutation builder. +func (m *AdminMutation) Where(ps ...predicate.Admin) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the AdminMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *AdminMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Admin, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *AdminMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *AdminMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Admin). +func (m *AdminMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *AdminMutation) Fields() []string { + fields := make([]string, 0, 7) + if m.name != nil { + fields = append(fields, admin.FieldName) + } + if m.email != nil { + fields = append(fields, admin.FieldEmail) + } + if m.avatar != nil { + fields = append(fields, admin.FieldAvatar) + } + if m.access != nil { + fields = append(fields, admin.FieldAccess) + } + if m.password != nil { + fields = append(fields, admin.FieldPassword) + } + if m.create_time != nil { + fields = append(fields, admin.FieldCreateTime) + } + if m.update_time != nil { + fields = append(fields, admin.FieldUpdateTime) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *AdminMutation) Field(name string) (ent.Value, bool) { + switch name { + case admin.FieldName: + return m.Name() + case admin.FieldEmail: + return m.Email() + case admin.FieldAvatar: + return m.Avatar() + case admin.FieldAccess: + return m.Access() + case admin.FieldPassword: + return m.Password() + case admin.FieldCreateTime: + return m.CreateTime() + case admin.FieldUpdateTime: + return m.UpdateTime() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *AdminMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case admin.FieldName: + return m.OldName(ctx) + case admin.FieldEmail: + return m.OldEmail(ctx) + case admin.FieldAvatar: + return m.OldAvatar(ctx) + case admin.FieldAccess: + return m.OldAccess(ctx) + case admin.FieldPassword: + return m.OldPassword(ctx) + case admin.FieldCreateTime: + return m.OldCreateTime(ctx) + case admin.FieldUpdateTime: + return m.OldUpdateTime(ctx) + } + return nil, fmt.Errorf("unknown Admin field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *AdminMutation) SetField(name string, value ent.Value) error { + switch name { + case admin.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case admin.FieldEmail: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEmail(v) + return nil + case admin.FieldAvatar: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAvatar(v) + return nil + case admin.FieldAccess: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAccess(v) + return nil + case admin.FieldPassword: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPassword(v) + return nil + case admin.FieldCreateTime: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreateTime(v) + return nil + case admin.FieldUpdateTime: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdateTime(v) + return nil + } + return fmt.Errorf("unknown Admin field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *AdminMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *AdminMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *AdminMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown Admin numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *AdminMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *AdminMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *AdminMutation) ClearField(name string) error { + return fmt.Errorf("unknown Admin nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *AdminMutation) ResetField(name string) error { + switch name { + case admin.FieldName: + m.ResetName() + return nil + case admin.FieldEmail: + m.ResetEmail() + return nil + case admin.FieldAvatar: + m.ResetAvatar() + return nil + case admin.FieldAccess: + m.ResetAccess() + return nil + case admin.FieldPassword: + m.ResetPassword() + return nil + case admin.FieldCreateTime: + m.ResetCreateTime() + return nil + case admin.FieldUpdateTime: + m.ResetUpdateTime() + return nil + } + return fmt.Errorf("unknown Admin field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *AdminMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *AdminMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *AdminMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *AdminMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *AdminMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *AdminMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *AdminMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown Admin unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *AdminMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown Admin edge %s", name) +} diff --git a/internal/data/ent/predicate/predicate.go b/internal/data/ent/predicate/predicate.go new file mode 100644 index 0000000..1c3f480 --- /dev/null +++ b/internal/data/ent/predicate/predicate.go @@ -0,0 +1,10 @@ +// Code generated by ent, DO NOT EDIT. + +package predicate + +import ( + "entgo.io/ent/dialect/sql" +) + +// Admin is the predicate function for admin builders. +type Admin func(*sql.Selector) diff --git a/internal/data/ent/runtime.go b/internal/data/ent/runtime.go new file mode 100644 index 0000000..82d5dc5 --- /dev/null +++ b/internal/data/ent/runtime.go @@ -0,0 +1,48 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "time" + + "kra/internal/data/ent/admin" + "kra/internal/data/ent/schema" +) + +// The init function reads all schema descriptors with runtime code +// (default values, validators, hooks and policies) and stitches it +// to their package variables. +func init() { + adminFields := schema.Admin{}.Fields() + _ = adminFields + // adminDescName is the schema descriptor for name field. + adminDescName := adminFields[1].Descriptor() + // admin.DefaultName holds the default value on creation for the name field. + admin.DefaultName = adminDescName.Default.(string) + // adminDescEmail is the schema descriptor for email field. + adminDescEmail := adminFields[2].Descriptor() + // admin.DefaultEmail holds the default value on creation for the email field. + admin.DefaultEmail = adminDescEmail.Default.(string) + // adminDescAvatar is the schema descriptor for avatar field. + adminDescAvatar := adminFields[3].Descriptor() + // admin.DefaultAvatar holds the default value on creation for the avatar field. + admin.DefaultAvatar = adminDescAvatar.Default.(string) + // adminDescAccess is the schema descriptor for access field. + adminDescAccess := adminFields[4].Descriptor() + // admin.DefaultAccess holds the default value on creation for the access field. + admin.DefaultAccess = adminDescAccess.Default.(string) + // adminDescPassword is the schema descriptor for password field. + adminDescPassword := adminFields[5].Descriptor() + // admin.DefaultPassword holds the default value on creation for the password field. + admin.DefaultPassword = adminDescPassword.Default.(string) + // adminDescCreateTime is the schema descriptor for create_time field. + adminDescCreateTime := adminFields[6].Descriptor() + // admin.DefaultCreateTime holds the default value on creation for the create_time field. + admin.DefaultCreateTime = adminDescCreateTime.Default.(func() time.Time) + // adminDescUpdateTime is the schema descriptor for update_time field. + adminDescUpdateTime := adminFields[7].Descriptor() + // admin.DefaultUpdateTime holds the default value on creation for the update_time field. + admin.DefaultUpdateTime = adminDescUpdateTime.Default.(func() time.Time) + // admin.UpdateDefaultUpdateTime holds the default value on update for the update_time field. + admin.UpdateDefaultUpdateTime = adminDescUpdateTime.UpdateDefault.(func() time.Time) +} diff --git a/internal/data/ent/runtime/runtime.go b/internal/data/ent/runtime/runtime.go new file mode 100644 index 0000000..3f91d65 --- /dev/null +++ b/internal/data/ent/runtime/runtime.go @@ -0,0 +1,10 @@ +// Code generated by ent, DO NOT EDIT. + +package runtime + +// The schema-stitching logic is generated in kra/internal/data/ent/runtime.go + +const ( + Version = "v0.14.5" // Version of ent codegen. + Sum = "h1:Rj2WOYJtCkWyFo6a+5wB3EfBRP0rnx1fMk6gGA0UUe4=" // Sum of ent codegen. +) diff --git a/internal/data/ent/schema/admin.go b/internal/data/ent/schema/admin.go new file mode 100644 index 0000000..ad07e95 --- /dev/null +++ b/internal/data/ent/schema/admin.go @@ -0,0 +1,27 @@ +package schema + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/schema/field" +) + +// Admin holds the schema definition for the Admin entity. +type Admin struct { + ent.Schema +} + +// Fields of the Admin. +func (Admin) Fields() []ent.Field { + return []ent.Field{ + field.Int64("id").Unique().Immutable(), + field.String("name").Default(""), + field.String("email").Default(""), + field.String("avatar").Default(""), + field.String("access").Default(""), + field.String("password").Default(""), + field.Time("create_time").Default(time.Now).Immutable(), + field.Time("update_time").Default(time.Now).UpdateDefault(time.Now), + } +} diff --git a/internal/data/ent/tx.go b/internal/data/ent/tx.go new file mode 100644 index 0000000..2789ff3 --- /dev/null +++ b/internal/data/ent/tx.go @@ -0,0 +1,236 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + stdsql "database/sql" + "fmt" + "sync" + + "entgo.io/ent/dialect" +) + +// Tx is a transactional client that is created by calling Client.Tx(). +type Tx struct { + config + // Admin is the client for interacting with the Admin builders. + Admin *AdminClient + + // lazily loaded. + client *Client + clientOnce sync.Once + // ctx lives for the life of the transaction. It is + // the same context used by the underlying connection. + ctx context.Context +} + +type ( + // Committer is the interface that wraps the Commit method. + Committer interface { + Commit(context.Context, *Tx) error + } + + // The CommitFunc type is an adapter to allow the use of ordinary + // function as a Committer. If f is a function with the appropriate + // signature, CommitFunc(f) is a Committer that calls f. + CommitFunc func(context.Context, *Tx) error + + // CommitHook defines the "commit middleware". A function that gets a Committer + // and returns a Committer. For example: + // + // hook := func(next ent.Committer) ent.Committer { + // return ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error { + // // Do some stuff before. + // if err := next.Commit(ctx, tx); err != nil { + // return err + // } + // // Do some stuff after. + // return nil + // }) + // } + // + CommitHook func(Committer) Committer +) + +// Commit calls f(ctx, m). +func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error { + return f(ctx, tx) +} + +// Commit commits the transaction. +func (tx *Tx) Commit() error { + txDriver := tx.config.driver.(*txDriver) + var fn Committer = CommitFunc(func(context.Context, *Tx) error { + return txDriver.tx.Commit() + }) + txDriver.mu.Lock() + hooks := append([]CommitHook(nil), txDriver.onCommit...) + txDriver.mu.Unlock() + for i := len(hooks) - 1; i >= 0; i-- { + fn = hooks[i](fn) + } + return fn.Commit(tx.ctx, tx) +} + +// OnCommit adds a hook to call on commit. +func (tx *Tx) OnCommit(f CommitHook) { + txDriver := tx.config.driver.(*txDriver) + txDriver.mu.Lock() + txDriver.onCommit = append(txDriver.onCommit, f) + txDriver.mu.Unlock() +} + +type ( + // Rollbacker is the interface that wraps the Rollback method. + Rollbacker interface { + Rollback(context.Context, *Tx) error + } + + // The RollbackFunc type is an adapter to allow the use of ordinary + // function as a Rollbacker. If f is a function with the appropriate + // signature, RollbackFunc(f) is a Rollbacker that calls f. + RollbackFunc func(context.Context, *Tx) error + + // RollbackHook defines the "rollback middleware". A function that gets a Rollbacker + // and returns a Rollbacker. For example: + // + // hook := func(next ent.Rollbacker) ent.Rollbacker { + // return ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error { + // // Do some stuff before. + // if err := next.Rollback(ctx, tx); err != nil { + // return err + // } + // // Do some stuff after. + // return nil + // }) + // } + // + RollbackHook func(Rollbacker) Rollbacker +) + +// Rollback calls f(ctx, m). +func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error { + return f(ctx, tx) +} + +// Rollback rollbacks the transaction. +func (tx *Tx) Rollback() error { + txDriver := tx.config.driver.(*txDriver) + var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error { + return txDriver.tx.Rollback() + }) + txDriver.mu.Lock() + hooks := append([]RollbackHook(nil), txDriver.onRollback...) + txDriver.mu.Unlock() + for i := len(hooks) - 1; i >= 0; i-- { + fn = hooks[i](fn) + } + return fn.Rollback(tx.ctx, tx) +} + +// OnRollback adds a hook to call on rollback. +func (tx *Tx) OnRollback(f RollbackHook) { + txDriver := tx.config.driver.(*txDriver) + txDriver.mu.Lock() + txDriver.onRollback = append(txDriver.onRollback, f) + txDriver.mu.Unlock() +} + +// Client returns a Client that binds to current transaction. +func (tx *Tx) Client() *Client { + tx.clientOnce.Do(func() { + tx.client = &Client{config: tx.config} + tx.client.init() + }) + return tx.client +} + +func (tx *Tx) init() { + tx.Admin = NewAdminClient(tx.config) +} + +// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. +// The idea is to support transactions without adding any extra code to the builders. +// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance. +// Commit and Rollback are nop for the internal builders and the user must call one +// of them in order to commit or rollback the transaction. +// +// If a closed transaction is embedded in one of the generated entities, and the entity +// applies a query, for example: Admin.QueryXXX(), the query will be executed +// through the driver which created this transaction. +// +// Note that txDriver is not goroutine safe. +type txDriver struct { + // the driver we started the transaction from. + drv dialect.Driver + // tx is the underlying transaction. + tx dialect.Tx + // completion hooks. + mu sync.Mutex + onCommit []CommitHook + onRollback []RollbackHook +} + +// newTx creates a new transactional driver. +func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) { + tx, err := drv.Tx(ctx) + if err != nil { + return nil, err + } + return &txDriver{tx: tx, drv: drv}, nil +} + +// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls +// from the internal builders. Should be called only by the internal builders. +func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil } + +// Dialect returns the dialect of the driver we started the transaction from. +func (tx *txDriver) Dialect() string { return tx.drv.Dialect() } + +// Close is a nop close. +func (*txDriver) Close() error { return nil } + +// Commit is a nop commit for the internal builders. +// User must call `Tx.Commit` in order to commit the transaction. +func (*txDriver) Commit() error { return nil } + +// Rollback is a nop rollback for the internal builders. +// User must call `Tx.Rollback` in order to rollback the transaction. +func (*txDriver) Rollback() error { return nil } + +// Exec calls tx.Exec. +func (tx *txDriver) Exec(ctx context.Context, query string, args, v any) error { + return tx.tx.Exec(ctx, query, args, v) +} + +// Query calls tx.Query. +func (tx *txDriver) Query(ctx context.Context, query string, args, v any) error { + return tx.tx.Query(ctx, query, args, v) +} + +var _ dialect.Driver = (*txDriver)(nil) + +// ExecContext allows calling the underlying ExecContext method of the transaction if it is supported by it. +// See, database/sql#Tx.ExecContext for more information. +func (tx *txDriver) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) { + ex, ok := tx.tx.(interface { + ExecContext(context.Context, string, ...any) (stdsql.Result, error) + }) + if !ok { + return nil, fmt.Errorf("Tx.ExecContext is not supported") + } + return ex.ExecContext(ctx, query, args...) +} + +// QueryContext allows calling the underlying QueryContext method of the transaction if it is supported by it. +// See, database/sql#Tx.QueryContext for more information. +func (tx *txDriver) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) { + q, ok := tx.tx.(interface { + QueryContext(context.Context, string, ...any) (*stdsql.Rows, error) + }) + if !ok { + return nil, fmt.Errorf("Tx.QueryContext is not supported") + } + return q.QueryContext(ctx, query, args...) +} diff --git a/internal/server/grpc.go b/internal/server/grpc.go new file mode 100644 index 0000000..9c76aaf --- /dev/null +++ b/internal/server/grpc.go @@ -0,0 +1,33 @@ +package server + +import ( + v1 "kra/api/kratos/admin/v1" + "kra/internal/conf" + "kra/internal/service" + "kra/pkg/validate" + + "github.com/go-kratos/kratos/v2/middleware/recovery" + "github.com/go-kratos/kratos/v2/transport/grpc" +) + +// NewGRPCServer new a gRPC server. +func NewGRPCServer(c *conf.Server, admin *service.AdminService) *grpc.Server { + var opts = []grpc.ServerOption{ + grpc.Middleware( + recovery.Recovery(), + validate.Middleware(), + ), + } + if c.Grpc.Network != "" { + opts = append(opts, grpc.Network(c.Grpc.Network)) + } + if c.Grpc.Addr != "" { + opts = append(opts, grpc.Address(c.Grpc.Addr)) + } + if c.Grpc.Timeout != nil { + opts = append(opts, grpc.Timeout(c.Grpc.Timeout.AsDuration())) + } + srv := grpc.NewServer(opts...) + v1.RegisterAdminServiceServer(srv, admin) + return srv +} diff --git a/internal/server/http.go b/internal/server/http.go new file mode 100644 index 0000000..170b8c4 --- /dev/null +++ b/internal/server/http.go @@ -0,0 +1,37 @@ +package server + +import ( + v1 "kra/api/kratos/admin/v1" + "kra/internal/conf" + "kra/internal/service" + "kra/pkg/auth" + "kra/pkg/validate" + + "github.com/go-kratos/kratos/v2/middleware/recovery" + "github.com/go-kratos/kratos/v2/transport/http" +) + +// NewHTTPServer new an HTTP server. +func NewHTTPServer(c *conf.Server, admin *service.AdminService) *http.Server { + var opts = []http.ServerOption{ + http.Filter( + auth.Middleware(), + ), + http.Middleware( + recovery.Recovery(), + validate.Middleware(), + ), + } + if c.Http.Network != "" { + opts = append(opts, http.Network(c.Http.Network)) + } + if c.Http.Addr != "" { + opts = append(opts, http.Address(c.Http.Addr)) + } + if c.Http.Timeout != nil { + opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration())) + } + srv := http.NewServer(opts...) + v1.RegisterAdminServiceHTTPServer(srv, admin) + return srv +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..f389425 --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,8 @@ +package server + +import ( + "github.com/google/wire" +) + +// ProviderSet is server providers. +var ProviderSet = wire.NewSet(NewGRPCServer, NewHTTPServer) diff --git a/internal/service/README.md b/internal/service/README.md new file mode 100644 index 0000000..42321b7 --- /dev/null +++ b/internal/service/README.md @@ -0,0 +1 @@ +# Service diff --git a/internal/service/admin.go b/internal/service/admin.go new file mode 100644 index 0000000..cfa47c4 --- /dev/null +++ b/internal/service/admin.go @@ -0,0 +1,243 @@ +package service + +import ( + "context" + "crypto/md5" + "encoding/hex" + "time" + + v1 "kra/api/kratos/admin/v1" + "kra/internal/biz" + "kra/pkg/auth" + "github.com/go-kratos/kratos/v2/errors" + + "go.einride.tech/aip/fieldmask" + "go.einride.tech/aip/filtering" + "go.einride.tech/aip/ordering" + "go.einride.tech/aip/pagination" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func encodePassword(password string) string { + sum := md5.Sum([]byte(password)) + return hex.EncodeToString(sum[:]) +} + +func convertAdmin(m *biz.Admin) *v1.Admin { + return &v1.Admin{ + Id: m.ID, + Name: m.Name, + Email: m.Email, + Avatar: m.Avatar, + Access: m.Access, + CreateTime: timestamppb.New(m.CreateTime), + UpdateTime: timestamppb.New(m.UpdateTime), + } +} + +// AdminService is a greeter service. +type AdminService struct { + v1.UnimplementedAdminServiceServer + + uc *biz.AdminUsecase +} + +// NewAdminService new a greeter service. +func NewAdminService(uc *biz.AdminUsecase) *AdminService { + return &AdminService{uc: uc} +} + +// Current implements auth current admin retrieval. +func (s *AdminService) Current(ctx context.Context, req *emptypb.Empty) (*v1.Admin, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + admin, err := s.uc.GetAdmin(ctx, a.UserID) + if err != nil { + return nil, err + } + return convertAdmin(admin), nil +} + +// Login implements auth login. +func (s *AdminService) Login(ctx context.Context, req *v1.LoginRequest) (*v1.Admin, error) { + var ( + err error + admin *biz.Admin + ) + switch v := req.Identity.(type) { + case *v1.LoginRequest_Username: + admin, err = s.uc.LoginByUsername(ctx, v.Username, encodePassword(req.Password)) + if err != nil { + return nil, err + } + case *v1.LoginRequest_Email: + admin, err = s.uc.LoginByEmail(ctx, v.Email, encodePassword(req.Password)) + if err != nil { + return nil, err + } + default: + return nil, errors.BadRequest("AUTH", "unsupported identity type") + } + if err := auth.SetCookie(ctx, admin.ID, admin.Access, time.Now().Add(7*24*time.Hour)); err != nil { + return nil, err + } + return convertAdmin(admin), nil +} + +// Logout implements auth logout. +func (s *AdminService) Logout(ctx context.Context, req *emptypb.Empty) (*emptypb.Empty, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + if err := s.uc.Logout(ctx, a.UserID); err != nil { + return nil, err + } + if err := auth.DeleteCookie(ctx); err != nil { + return nil, err + } + return &emptypb.Empty{}, nil +} + +// CreateAdmin implements admin creation. +func (s *AdminService) CreateAdmin(ctx context.Context, req *v1.CreateAdminRequest) (*v1.Admin, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + if !a.HasAdminAccess() { + return nil, auth.ErrForbidden + } + admin, err := s.uc.CreateAdmin(ctx, &biz.Admin{ + Name: req.Admin.Name, + Email: req.Admin.Email, + Password: req.Admin.Password, + Avatar: req.Admin.Avatar, + Access: req.Admin.Access, + }) + if err != nil { + return nil, err + } + return convertAdmin(admin), nil +} + +// UpdateAdmin implements admin update. +func (s *AdminService) UpdateAdmin(ctx context.Context, req *v1.UpdateAdminRequest) (*v1.Admin, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + if !a.HasAdminAccess() { + return nil, auth.ErrForbidden + } + // Encode password if it's not empty + if req.Admin.Password != "" { + req.Admin.Password = encodePassword(req.Admin.Password) + } + admin, err := s.GetAdmin(ctx, &v1.GetAdminRequest{Id: req.Admin.Id}) + if err != nil { + return nil, err + } + fieldmask.Update(req.UpdateMask, admin, req.Admin) + updated, err := s.uc.UpdateAdmin(ctx, &biz.Admin{ + ID: admin.Id, + Name: admin.Name, + Email: admin.Email, + Password: admin.Password, + Avatar: admin.Avatar, + Access: admin.Access, + }) + if err != nil { + return nil, err + } + return convertAdmin(updated), nil +} + +// DeleteAdmin implements admin deletion. +func (s *AdminService) DeleteAdmin(ctx context.Context, req *v1.DeleteAdminRequest) (*emptypb.Empty, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + if !a.HasAdminAccess() { + return nil, auth.ErrForbidden + } + if err := s.uc.DeleteAdmin(ctx, req.Id); err != nil { + return nil, err + } + return &emptypb.Empty{}, nil +} + +// GetAdmin implements admin retrieval. +func (s *AdminService) GetAdmin(ctx context.Context, req *v1.GetAdminRequest) (*v1.Admin, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + if !a.HasAdminAccess() { + return nil, auth.ErrForbidden + } + admin, err := s.uc.GetAdmin(ctx, req.Id) + if err != nil { + return nil, err + } + return convertAdmin(admin), nil +} + +// ListAdmins implements admin listing with filtering, ordering, and pagination. +func (s *AdminService) ListAdmins(ctx context.Context, req *v1.ListAdminsRequest) (*v1.AdminSet, error) { + a, ok := auth.FromContext(ctx) + if !ok { + return nil, auth.ErrUnauthorized + } + if !a.HasAdminAccess() { + return nil, auth.ErrForbidden + } + declarations, err := filtering.NewDeclarations( + filtering.DeclareStandardFunctions(), + filtering.DeclareIdent("name", filtering.TypeString), + filtering.DeclareIdent("email", filtering.TypeString), + filtering.DeclareIdent("phone", filtering.TypeString), + filtering.DeclareIdent("create_time", filtering.TypeTimestamp), + ) + if err != nil { + return nil, err + } + filter, err := filtering.ParseFilter(req, declarations) + if err != nil { + return nil, err + } + pageToken, err := pagination.ParsePageToken(req) + if err != nil { + return nil, err + } + orderBy, err := ordering.ParseOrderBy(req) + if err != nil { + return nil, err + } + if req.PageSize <= 0 { + req.PageSize = 20 + } + admins, err := s.uc.ListAdmins(ctx, + biz.ListFilter(filter), + biz.ListOrderBy(orderBy), + biz.ListLimit(int(req.PageSize)), + biz.ListOffset(int(pageToken.Offset)), + ) + if err != nil { + return nil, err + } + adminSet := &v1.AdminSet{ + Admins: make([]*v1.Admin, 0, len(admins)), + } + if len(admins) >= int(req.PageSize) { + adminSet.NextPageToken = pageToken.Next(req).String() + } + for _, admin := range admins { + adminSet.Admins = append(adminSet.Admins, convertAdmin(admin)) + } + return adminSet, nil +} diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..d4313fb --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,6 @@ +package service + +import "github.com/google/wire" + +// ProviderSet is service providers. +var ProviderSet = wire.NewSet(NewAdminService) diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..666fb40 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,247 @@ +# Generated with protoc-gen-openapi +# https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi + +openapi: 3.0.3 +info: + title: AdminService API + description: AdminService is the admin service definition. + version: 0.0.1 +paths: + /v1/admins/create: + post: + tags: + - AdminService + description: CreateAdmin creates a new admin. + operationId: AdminService_CreateAdmin + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + /v1/admins/current: + get: + tags: + - AdminService + description: Current returns the currently logged-in user. + operationId: AdminService_Current + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + /v1/admins/list: + get: + tags: + - AdminService + description: ListAdmins returns a list of admins. + operationId: AdminService_ListAdmins + parameters: + - name: pageSize + in: query + description: Optional. The number of admins per page. + schema: + type: integer + format: int32 + - name: pageToken + in: query + description: Optional. The page token. + schema: + type: string + - name: filter + in: query + description: |- + Optional. The standard list filter. + Supported fields: + * `name` (i.e. `name="John Doe"`) + * `create_time` range (i.e. `timestamp>="2025-01-31T11:30:00-04:00"` where + the timestamp is in RFC 3339 format) + + More detail in [AIP-160](https://google.aip.dev/160). + schema: + type: string + - name: orderBy + in: query + description: |- + Optional. A comma-separated list of fields to order by, sorted in ascending + order. Use "desc" after a field name for descending. Supported fields: + - `create_time` + + Example: `create_time desc`. + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.AdminSet' + /v1/admins/login: + post: + tags: + - AdminService + description: Login a user and return the username. + operationId: AdminService_Login + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.LoginRequest' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + /v1/admins/logout: + post: + tags: + - AdminService + description: Logout the currently logged-in user. + operationId: AdminService_Logout + requestBody: + content: + application/json: {} + required: true + responses: + "200": + description: OK + content: {} + /v1/admins/update: + put: + tags: + - AdminService + description: UpdateAdmin updates an existing admin. + operationId: AdminService_UpdateAdmin + parameters: + - name: updateMask + in: query + description: Required. Mask of fields to update. + schema: + type: string + format: field-mask + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + required: true + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + /v1/admins/{id}: + get: + tags: + - AdminService + description: GetAdmin retrieves an admin by ID. + operationId: AdminService_GetAdmin + parameters: + - name: id + in: path + description: The ID of the admin to retrieve. + required: true + schema: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + delete: + tags: + - AdminService + description: DeleteAdmin deletes an admin by ID. + operationId: AdminService_DeleteAdmin + parameters: + - name: id + in: path + description: Required. The ID of the admin to delete. + required: true + schema: + type: string + responses: + "200": + description: OK + content: {} +components: + schemas: + kratos.admin.v1.Admin: + type: object + properties: + id: + type: string + description: The unique ID of the user. + name: + type: string + description: The name of the user. + email: + type: string + description: The email of the user. + phone: + type: string + description: The phone number of the user. + avatar: + type: string + description: The avatar URL of the user. + access: + type: string + description: |- + The access level of the user. + Possible values are: "admin", "user", etc. + password: + type: string + description: The password of the user. + createTime: + type: string + description: The timestamp at which the user was created. + format: date-time + updateTime: + type: string + description: The latest timestamp at which the user was updated. + format: date-time + description: Admin is the admin message. + kratos.admin.v1.AdminSet: + type: object + properties: + admins: + type: array + items: + $ref: '#/components/schemas/kratos.admin.v1.Admin' + description: The set of admins. + nextPageToken: + type: string + description: The next page token. + description: AdminSet is the set of admins. + kratos.admin.v1.LoginRequest: + required: + - password + type: object + properties: + password: + type: string + description: Required. Password of the user. + username: + type: string + email: + type: string + description: LoginRequest is the request message for the Login method. +tags: + - name: AdminService diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go new file mode 100644 index 0000000..0d51dde --- /dev/null +++ b/pkg/auth/auth.go @@ -0,0 +1,32 @@ +package auth + +import ( + "context" + + "github.com/golang-jwt/jwt/v5" +) + +// Auth user auth. +type Auth struct { + UserID int64 `json:"id"` + Access string `json:"access"` + jwt.RegisteredClaims +} + +// HasAdminAccess checks if the user has admin access. +func (a *Auth) HasAdminAccess() bool { + return a.Access == "admin" +} + +type authKey struct{} + +// NewContext returns a new Context that carries value. +func NewContext(ctx context.Context, auth *Auth) context.Context { + return context.WithValue(ctx, authKey{}, auth) +} + +// FromContext returns the Auth value stored in ctx, if any. +func FromContext(ctx context.Context) (auth *Auth, ok bool) { + auth, ok = ctx.Value(authKey{}).(*Auth) + return +} diff --git a/pkg/auth/config.go b/pkg/auth/config.go new file mode 100644 index 0000000..1985eab --- /dev/null +++ b/pkg/auth/config.go @@ -0,0 +1,22 @@ +package auth + +import ( + "os" + "time" +) + +// authSecretFromEnv retrieves the authentication secret from the environment variable. +func authSecretFromEnv(key string) string { + if secret := os.Getenv(key); secret != "" { + return secret + } + return time.Now().Format("20060102150405") +} + +// cookieNameFromEnv retrieves the cookie name from the environment variable. +func cookieNameFromEnv(key string) string { + if name := os.Getenv(key); name != "" { + return name + } + return "access_token" +} diff --git a/pkg/auth/middleware.go b/pkg/auth/middleware.go new file mode 100644 index 0000000..0995834 --- /dev/null +++ b/pkg/auth/middleware.go @@ -0,0 +1,89 @@ +package auth + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/go-kratos/kratos/v2/errors" + "github.com/go-kratos/kratos/v2/transport" + httpm "github.com/go-kratos/kratos/v2/transport/http" +) + +var ( + // noAuthPaths defines the paths that do not require authentication. + noAuthPaths = map[string]struct{}{ + "/v1/admins/login": {}, + } + // authSecretKey is the secret key used for signing JWT tokens. + authSecretKey = authSecretFromEnv("KRATOS_AUTH_SECRET") + // cookieName is the name of the cookie that stores the authorization token. + cookieName = cookieNameFromEnv("KRATOS_AUTH_COOKIE") + // ErrUnauthorized indicates that the token is invalid. + ErrUnauthorized = errors.Unauthorized("UNAUTHORIZED", "Token is invalid") + // ErrForbidden indicates that access is denied. + ErrForbidden = errors.Forbidden("FORBIDDEN", "Access denied") +) + +// Middleware is an authentication middleware for HTTP servers. +func Middleware() httpm.FilterFunc { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if _, ok := noAuthPaths[r.URL.Path]; ok { + next.ServeHTTP(w, r) + return + } + cookie, err := r.Cookie(cookieName) + if err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + auth, err := ParseToken(cookie.Value, authSecretKey) + if err != nil { + ec := errors.FromError(err) + http.Error(w, ec.Message, int(ec.Code)) + return + } + ctx := NewContext(r.Context(), auth) + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} + +// SetCookie sets the login cookie in the HTTP response. +func SetCookie(ctx context.Context, userID int64, access string, expiresAt time.Time) error { + tr, ok := transport.FromServerContext(ctx) + if !ok { + return fmt.Errorf("failed to get transport from context") + } + token, err := GenerateToken(userID, access, authSecretKey, expiresAt) + if err != nil { + return err + } + cookie := &http.Cookie{ + Name: cookieName, + Value: token, + Path: "/", + Expires: expiresAt, + } + tr.ReplyHeader().Add("Set-Cookie", cookie.String()) + return nil +} + +// DeleteCookie clears the login cookie in the HTTP response. +func DeleteCookie(ctx context.Context) error { + tr, ok := transport.FromServerContext(ctx) + if !ok { + return fmt.Errorf("failed to get transport from context") + } + expires := time.Now().AddDate(0, 0, -1) + cookie := &http.Cookie{ + Name: cookieName, + Value: "", + Path: "/", + Expires: expires, + } + tr.ReplyHeader().Add("Set-Cookie", cookie.String()) + return nil +} diff --git a/pkg/auth/token.go b/pkg/auth/token.go new file mode 100644 index 0000000..3f69c89 --- /dev/null +++ b/pkg/auth/token.go @@ -0,0 +1,45 @@ +package auth + +import ( + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/google/uuid" +) + +// GenerateToken generates a JWT token for the given username. +func GenerateToken(userID int64, access, secret string, expiresAt time.Time) (string, error) { + now := time.Now() + claims := Auth{ + UserID: userID, + Access: access, + RegisteredClaims: jwt.RegisteredClaims{ + ID: uuid.NewString(), + Issuer: "kratos", + Subject: "user", + Audience: []string{"admin"}, + IssuedAt: jwt.NewNumericDate(now), + NotBefore: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(expiresAt), + }, + } + return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret)) +} + +// ParseToken parses the JWT token string and returns the Auth claims. +func ParseToken(tokenStr, secret string) (*Auth, error) { + token, err := jwt.ParseWithClaims(tokenStr, &Auth{}, func(token *jwt.Token) (interface{}, error) { + return []byte(secret), nil + }) + if err != nil { + return nil, err + } + if !token.Valid { + return nil, ErrUnauthorized + } + auth, ok := token.Claims.(*Auth) + if !ok { + return nil, ErrUnauthorized + } + return auth, nil +} diff --git a/pkg/validate/validate.go b/pkg/validate/validate.go new file mode 100644 index 0000000..1cd50a9 --- /dev/null +++ b/pkg/validate/validate.go @@ -0,0 +1,24 @@ +package validate + +import ( + "context" + + "github.com/go-kratos/kratos/v2/errors" + "github.com/go-kratos/kratos/v2/middleware" + "go.einride.tech/aip/fieldbehavior" + "google.golang.org/protobuf/proto" +) + +// Middleware is a middleware that validates the request message with [FieldBehavior](https://google.aip.dev/203) +func Middleware() middleware.Middleware { + return func(handler middleware.Handler) middleware.Handler { + return func(ctx context.Context, req any) (reply any, err error) { + if msg, ok := req.(proto.Message); ok { + if err := fieldbehavior.ValidateRequiredFields(msg); err != nil { + return nil, errors.BadRequest("VALIDATOR", err.Error()).WithCause(err) + } + } + return handler(ctx, req) + } + } +} diff --git a/third_party/README.md b/third_party/README.md new file mode 100644 index 0000000..005faa2 --- /dev/null +++ b/third_party/README.md @@ -0,0 +1 @@ +# third_party diff --git a/third_party/errors/errors.proto b/third_party/errors/errors.proto new file mode 100644 index 0000000..0963d91 --- /dev/null +++ b/third_party/errors/errors.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package errors; + +option go_package = "github.com/go-kratos/kratos/v2/errors;errors"; +option java_multiple_files = true; +option java_package = "com.github.kratos.errors"; +option objc_class_prefix = "KratosErrors"; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.EnumOptions { + int32 default_code = 1108; +} + +extend google.protobuf.EnumValueOptions { + int32 code = 1109; +} \ No newline at end of file diff --git a/third_party/google/api/annotations.proto b/third_party/google/api/annotations.proto new file mode 100644 index 0000000..85c361b --- /dev/null +++ b/third_party/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright (c) 2015, Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/third_party/google/api/client.proto b/third_party/google/api/client.proto new file mode 100644 index 0000000..d3d1ead --- /dev/null +++ b/third_party/google/api/client.proto @@ -0,0 +1,101 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "ClientProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + + +extend google.protobuf.ServiceOptions { + // The hostname for this service. + // This should be specified with no prefix or protocol. + // + // Example: + // + // service Foo { + // option (google.api.default_host) = "foo.googleapi.com"; + // ... + // } + string default_host = 1049; + + // OAuth scopes needed for the client. + // + // Example: + // + // service Foo { + // option (google.api.oauth_scopes) = \ + // "https://www.googleapis.com/auth/cloud-platform"; + // ... + // } + // + // If there is more than one scope, use a comma-separated string: + // + // Example: + // + // service Foo { + // option (google.api.oauth_scopes) = \ + // "https://www.googleapis.com/auth/cloud-platform," + // "https://www.googleapis.com/auth/monitoring"; + // ... + // } + string oauth_scopes = 1050; +} + + +extend google.protobuf.MethodOptions { + // A definition of a client library method signature. + // + // In client libraries, each proto RPC corresponds to one or more methods + // which the end user is able to call, and calls the underlying RPC. + // Normally, this method receives a single argument (a struct or instance + // corresponding to the RPC request object). Defining this field will + // add one or more overloads providing flattened or simpler method signatures + // in some languages. + // + // The fields on the method signature are provided as a comma-separated + // string. + // + // For example, the proto RPC and annotation: + // + // rpc CreateSubscription(CreateSubscriptionRequest) + // returns (Subscription) { + // option (google.api.method_signature) = "name,topic"; + // } + // + // Would add the following Java overload (in addition to the method accepting + // the request object): + // + // public final Subscription createSubscription(String name, String topic) + // + // The following backwards-compatibility guidelines apply: + // + // * Adding this annotation to an unannotated method is backwards + // compatible. + // * Adding this annotation to a method which already has existing + // method signature annotations is backwards compatible if and only if + // the new method signature annotation is last in the sequence. + // * Modifying or removing an existing method signature annotation is + // a breaking change. + // * Re-ordering existing method signature annotations is a breaking + // change. + repeated string method_signature = 1051; +} \ No newline at end of file diff --git a/third_party/google/api/field_behavior.proto b/third_party/google/api/field_behavior.proto new file mode 100644 index 0000000..e9716a2 --- /dev/null +++ b/third_party/google/api/field_behavior.proto @@ -0,0 +1,80 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "FieldBehaviorProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + + +// An indicator of the behavior of a given field (for example, that a field +// is required in requests, or given as output but ignored as input). +// This **does not** change the behavior in protocol buffers itself; it only +// denotes the behavior and may affect how API tooling handles the field. +// +// Note: This enum **may** receive new values in the future. +enum FieldBehavior { + // Conventional default for enums. Do not use this. + FIELD_BEHAVIOR_UNSPECIFIED = 0; + + // Specifically denotes a field as optional. + // While all fields in protocol buffers are optional, this may be specified + // for emphasis if appropriate. + OPTIONAL = 1; + + // Denotes a field as required. + // This indicates that the field **must** be provided as part of the request, + // and failure to do so will cause an error (usually `INVALID_ARGUMENT`). + REQUIRED = 2; + + // Denotes a field as output only. + // This indicates that the field is provided in responses, but including the + // field in a request does nothing (the server *must* ignore it and + // *must not* throw an error as a result of the field's presence). + OUTPUT_ONLY = 3; + + // Denotes a field as input only. + // This indicates that the field is provided in requests, and the + // corresponding field is not included in output. + INPUT_ONLY = 4; + + // Denotes a field as immutable. + // This indicates that the field may be set once in a request to create a + // resource, but may not be changed thereafter. + IMMUTABLE = 5; +} + + +extend google.protobuf.FieldOptions { + // A designation of a specific field behavior (required, output only, etc.) + // in protobuf messages. + // + // Examples: + // + // string name = 1 [(google.api.field_behavior) = REQUIRED]; + // State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; + // google.protobuf.Duration ttl = 1 + // [(google.api.field_behavior) = INPUT_ONLY]; + // google.protobuf.Timestamp expire_time = 1 + // [(google.api.field_behavior) = OUTPUT_ONLY, + // (google.api.field_behavior) = IMMUTABLE]; + repeated FieldBehavior field_behavior = 1052; +} \ No newline at end of file diff --git a/third_party/google/api/http.proto b/third_party/google/api/http.proto new file mode 100644 index 0000000..69460cf --- /dev/null +++ b/third_party/google/api/http.proto @@ -0,0 +1,375 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. +message HttpRule { + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + string get = 2; + + // Maps to HTTP PUT. Used for replacing a resource. + string put = 3; + + // Maps to HTTP POST. Used for creating a resource or performing an action. + string post = 4; + + // Maps to HTTP DELETE. Used for deleting a resource. + string delete = 5; + + // Maps to HTTP PATCH. Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} diff --git a/third_party/google/api/httpbody.proto b/third_party/google/api/httpbody.proto new file mode 100644 index 0000000..1a5bb78 --- /dev/null +++ b/third_party/google/api/httpbody.proto @@ -0,0 +1,77 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; +option java_multiple_files = true; +option java_outer_classname = "HttpBodyProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Message that represents an arbitrary HTTP body. It should only be used for +// payload formats that can't be represented as JSON, such as raw binary or +// an HTML page. +// +// +// This message can be used both in streaming and non-streaming API methods in +// the request as well as the response. +// +// It can be used as a top-level request field, which is convenient if one +// wants to extract parameters from either the URL or HTTP template into the +// request fields and also want access to the raw HTTP body. +// +// Example: +// +// message GetResourceRequest { +// // A unique request id. +// string request_id = 1; +// +// // The raw HTTP body is bound to this field. +// google.api.HttpBody http_body = 2; +// } +// +// service ResourceService { +// rpc GetResource(GetResourceRequest) returns (google.api.HttpBody); +// rpc UpdateResource(google.api.HttpBody) returns +// (google.protobuf.Empty); +// } +// +// Example with streaming methods: +// +// service CaldavService { +// rpc GetCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// rpc UpdateCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// } +// +// Use of this type only changes how the request and response bodies are +// handled, all other features will continue to work unchanged. +message HttpBody { + // The HTTP Content-Type header value specifying the content type of the body. + string content_type = 1; + + // The HTTP request/response body as raw binary. + bytes data = 2; + + // Application specific response metadata. Must be set in the first response + // for streaming APIs. + repeated google.protobuf.Any extensions = 3; +} diff --git a/third_party/google/protobuf/any.proto b/third_party/google/protobuf/any.proto new file mode 100644 index 0000000..e2c2042 --- /dev/null +++ b/third_party/google/protobuf/any.proto @@ -0,0 +1,158 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/anypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/third_party/google/protobuf/api.proto b/third_party/google/protobuf/api.proto new file mode 100644 index 0000000..3d598fc --- /dev/null +++ b/third_party/google/protobuf/api.proto @@ -0,0 +1,208 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/source_context.proto"; +import "google/protobuf/type.proto"; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "ApiProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/apipb"; + +// Api is a light-weight descriptor for an API Interface. +// +// Interfaces are also described as "protocol buffer services" in some contexts, +// such as by the "service" keyword in a .proto file, but they are different +// from API Services, which represent a concrete implementation of an interface +// as opposed to simply a description of methods and bindings. They are also +// sometimes simply referred to as "APIs" in other contexts, such as the name of +// this message itself. See https://cloud.google.com/apis/design/glossary for +// detailed terminology. +message Api { + // The fully qualified name of this interface, including package name + // followed by the interface's simple name. + string name = 1; + + // The methods of this interface, in unspecified order. + repeated Method methods = 2; + + // Any metadata attached to the interface. + repeated Option options = 3; + + // A version string for this interface. If specified, must have the form + // `major-version.minor-version`, as in `1.10`. If the minor version is + // omitted, it defaults to zero. If the entire version field is empty, the + // major version is derived from the package name, as outlined below. If the + // field is not empty, the version in the package name will be verified to be + // consistent with what is provided here. + // + // The versioning schema uses [semantic + // versioning](http://semver.org) where the major version number + // indicates a breaking change and the minor version an additive, + // non-breaking change. Both version numbers are signals to users + // what to expect from different versions, and should be carefully + // chosen based on the product plan. + // + // The major version is also reflected in the package name of the + // interface, which must end in `v`, as in + // `google.feature.v1`. For major versions 0 and 1, the suffix can + // be omitted. Zero major versions must only be used for + // experimental, non-GA interfaces. + // + // + string version = 4; + + // Source context for the protocol buffer service represented by this + // message. + SourceContext source_context = 5; + + // Included interfaces. See [Mixin][]. + repeated Mixin mixins = 6; + + // The source syntax of the service. + Syntax syntax = 7; +} + +// Method represents a method of an API interface. +message Method { + // The simple name of this method. + string name = 1; + + // A URL of the input message type. + string request_type_url = 2; + + // If true, the request is streamed. + bool request_streaming = 3; + + // The URL of the output message type. + string response_type_url = 4; + + // If true, the response is streamed. + bool response_streaming = 5; + + // Any metadata attached to the method. + repeated Option options = 6; + + // The source syntax of this method. + Syntax syntax = 7; +} + +// Declares an API Interface to be included in this interface. The including +// interface must redeclare all the methods from the included interface, but +// documentation and options are inherited as follows: +// +// - If after comment and whitespace stripping, the documentation +// string of the redeclared method is empty, it will be inherited +// from the original method. +// +// - Each annotation belonging to the service config (http, +// visibility) which is not set in the redeclared method will be +// inherited. +// +// - If an http annotation is inherited, the path pattern will be +// modified as follows. Any version prefix will be replaced by the +// version of the including interface plus the [root][] path if +// specified. +// +// Example of a simple mixin: +// +// package google.acl.v1; +// service AccessControl { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v1/{resource=**}:getAcl"; +// } +// } +// +// package google.storage.v2; +// service Storage { +// rpc GetAcl(GetAclRequest) returns (Acl); +// +// // Get a data record. +// rpc GetData(GetDataRequest) returns (Data) { +// option (google.api.http).get = "/v2/{resource=**}"; +// } +// } +// +// Example of a mixin configuration: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// +// The mixin construct implies that all methods in `AccessControl` are +// also declared with same name and request/response types in +// `Storage`. A documentation generator or annotation processor will +// see the effective `Storage.GetAcl` method after inheriting +// documentation and annotations as follows: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/{resource=**}:getAcl"; +// } +// ... +// } +// +// Note how the version in the path pattern changed from `v1` to `v2`. +// +// If the `root` field in the mixin is specified, it should be a +// relative path under which inherited HTTP paths are placed. Example: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// root: acls +// +// This implies the following inherited HTTP annotation: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; +// } +// ... +// } +message Mixin { + // The fully qualified name of the interface which is included. + string name = 1; + + // If non-empty specifies a path under which inherited HTTP paths + // are rooted. + string root = 2; +} diff --git a/third_party/google/protobuf/compiler/plugin.proto b/third_party/google/protobuf/compiler/plugin.proto new file mode 100644 index 0000000..9242aac --- /dev/null +++ b/third_party/google/protobuf/compiler/plugin.proto @@ -0,0 +1,183 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to +// change. +// +// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is +// just a program that reads a CodeGeneratorRequest from stdin and writes a +// CodeGeneratorResponse to stdout. +// +// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead +// of dealing with the raw protocol defined here. +// +// A plugin executable needs only to be placed somewhere in the path. The +// plugin should be named "protoc-gen-$NAME", and will then be used when the +// flag "--${NAME}_out" is passed to protoc. + +syntax = "proto2"; + +package google.protobuf.compiler; +option java_package = "com.google.protobuf.compiler"; +option java_outer_classname = "PluginProtos"; + +option go_package = "google.golang.org/protobuf/types/pluginpb"; + +import "google/protobuf/descriptor.proto"; + +// The version number of protocol compiler. +message Version { + optional int32 major = 1; + optional int32 minor = 2; + optional int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + optional string suffix = 4; +} + +// An encoded CodeGeneratorRequest is written to the plugin's stdin. +message CodeGeneratorRequest { + // The .proto files that were explicitly listed on the command-line. The + // code generator should generate code only for these files. Each file's + // descriptor will be included in proto_file, below. + repeated string file_to_generate = 1; + + // The generator parameter passed on the command-line. + optional string parameter = 2; + + // FileDescriptorProtos for all files in files_to_generate and everything + // they import. The files will appear in topological order, so each file + // appears before any file that imports it. + // + // protoc guarantees that all proto_files will be written after + // the fields above, even though this is not technically guaranteed by the + // protobuf wire format. This theoretically could allow a plugin to stream + // in the FileDescriptorProtos and handle them one by one rather than read + // the entire set into memory at once. However, as of this writing, this + // is not similarly optimized on protoc's end -- it will store all fields in + // memory at once before sending them to the plugin. + // + // Type names of fields and extensions in the FileDescriptorProto are always + // fully qualified. + repeated FileDescriptorProto proto_file = 15; + + // The version number of protocol compiler. + optional Version compiler_version = 3; + +} + +// The plugin writes an encoded CodeGeneratorResponse to stdout. +message CodeGeneratorResponse { + // Error message. If non-empty, code generation failed. The plugin process + // should exit with status code zero even if it reports an error in this way. + // + // This should be used to indicate errors in .proto files which prevent the + // code generator from generating correct code. Errors which indicate a + // problem in protoc itself -- such as the input CodeGeneratorRequest being + // unparseable -- should be reported by writing a message to stderr and + // exiting with a non-zero status code. + optional string error = 1; + + // A bitmask of supported features that the code generator supports. + // This is a bitwise "or" of values from the Feature enum. + optional uint64 supported_features = 2; + + // Sync with code_generator.h. + enum Feature { + FEATURE_NONE = 0; + FEATURE_PROTO3_OPTIONAL = 1; + } + + // Represents a single generated file. + message File { + // The file name, relative to the output directory. The name must not + // contain "." or ".." components and must be relative, not be absolute (so, + // the file cannot lie outside the output directory). "/" must be used as + // the path separator, not "\". + // + // If the name is omitted, the content will be appended to the previous + // file. This allows the generator to break large files into small chunks, + // and allows the generated text to be streamed back to protoc so that large + // files need not reside completely in memory at one time. Note that as of + // this writing protoc does not optimize for this -- it will read the entire + // CodeGeneratorResponse before writing files to disk. + optional string name = 1; + + // If non-empty, indicates that the named file should already exist, and the + // content here is to be inserted into that file at a defined insertion + // point. This feature allows a code generator to extend the output + // produced by another code generator. The original generator may provide + // insertion points by placing special annotations in the file that look + // like: + // @@protoc_insertion_point(NAME) + // The annotation can have arbitrary text before and after it on the line, + // which allows it to be placed in a comment. NAME should be replaced with + // an identifier naming the point -- this is what other generators will use + // as the insertion_point. Code inserted at this point will be placed + // immediately above the line containing the insertion point (thus multiple + // insertions to the same point will come out in the order they were added). + // The double-@ is intended to make it unlikely that the generated code + // could contain things that look like insertion points by accident. + // + // For example, the C++ code generator places the following line in the + // .pb.h files that it generates: + // // @@protoc_insertion_point(namespace_scope) + // This line appears within the scope of the file's package namespace, but + // outside of any particular class. Another plugin can then specify the + // insertion_point "namespace_scope" to generate additional classes or + // other declarations that should be placed in this scope. + // + // Note that if the line containing the insertion point begins with + // whitespace, the same whitespace will be added to every line of the + // inserted text. This is useful for languages like Python, where + // indentation matters. In these languages, the insertion point comment + // should be indented the same amount as any inserted code will need to be + // in order to work correctly in that context. + // + // The code generator that generates the initial file and the one which + // inserts into it must both run as part of a single invocation of protoc. + // Code generators are executed in the order in which they appear on the + // command line. + // + // If |insertion_point| is present, |name| must also be present. + optional string insertion_point = 2; + + // The file contents. + optional string content = 15; + + // Information describing the file content being inserted. If an insertion + // point is used, this information will be appropriately offset and inserted + // into the code generation metadata for the generated files. + optional GeneratedCodeInfo generated_code_info = 16; + } + repeated File file = 15; +} diff --git a/third_party/google/protobuf/descriptor.proto b/third_party/google/protobuf/descriptor.proto new file mode 100644 index 0000000..49ec653 --- /dev/null +++ b/third_party/google/protobuf/descriptor.proto @@ -0,0 +1,921 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + + +syntax = "proto2"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2" and "proto3". + optional string syntax = 12; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported in proto3. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + } + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + } + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must be belong to a oneof to + // signal to old proto3 clients that presence is tracked for this field. This + // oneof is known as a "synthetic" oneof, and this field must be its sole + // member (each proto3 optional field gets its own synthetic oneof). Synthetic + // oneofs exist in the descriptor only, and do not generate any API. Synthetic + // oneofs must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default = false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default = false]; +} + + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // Controls the name of the wrapper Java class generated for the .proto file. + // That class will always contain the .proto file's getDescriptor() method as + // well as any top-level extensions defined in the .proto file. + // If java_multiple_files is disabled, then all the other classes from the + // .proto file will be nested inside the single wrapper outer class. + optional string java_outer_classname = 8; + + // If enabled, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the wrapper class + // named by java_outer_classname. However, the wrapper class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default = false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + optional bool java_string_check_utf8 = 27 [default = false]; + + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default = SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + optional bool php_generic_services = 42 [default = false]; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default = false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default = true]; + + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be + // used for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default = false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default = false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default = false]; + + reserved 4, 5, 6; + + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementations still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + // + // As of 2021, lazy does no correctness checks on the byte stream during + // parsing. This may lead to crashes if and when an invalid byte stream is + // finally parsed upon access. + // + // TODO(b/211906113): Enable validation on lazy fields. + optional bool lazy = 5 [default = false]; + + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default = false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default = false]; + + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype +} + +message OneofOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default = false]; + + reserved 5; // javanano_as_lite + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default = false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = 34 + [default = IDEMPOTENCY_UNKNOWN]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + // "foo.(bar.baz).qux". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition occurs. + // For example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed = true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed = true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to qux or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed = true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified offset. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + } +} diff --git a/third_party/google/protobuf/duration.proto b/third_party/google/protobuf/duration.proto new file mode 100644 index 0000000..81c3e36 --- /dev/null +++ b/third_party/google/protobuf/duration.proto @@ -0,0 +1,116 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/durationpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (duration.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +message Duration { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/third_party/google/protobuf/empty.proto b/third_party/google/protobuf/empty.proto new file mode 100644 index 0000000..5f992de --- /dev/null +++ b/third_party/google/protobuf/empty.proto @@ -0,0 +1,52 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/emptypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +// The JSON representation for `Empty` is empty JSON object `{}`. +message Empty {} diff --git a/third_party/google/protobuf/field_mask.proto b/third_party/google/protobuf/field_mask.proto new file mode 100644 index 0000000..6b5104f --- /dev/null +++ b/third_party/google/protobuf/field_mask.proto @@ -0,0 +1,245 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "FieldMaskProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; +option cc_enable_arenas = true; + +// `FieldMask` represents a set of symbolic field paths, for example: +// +// paths: "f.a" +// paths: "f.b.d" +// +// Here `f` represents a field in some root message, `a` and `b` +// fields in the message found in `f`, and `d` a field found in the +// message in `f.b`. +// +// Field masks are used to specify a subset of fields that should be +// returned by a get operation or modified by an update operation. +// Field masks also have a custom JSON encoding (see below). +// +// # Field Masks in Projections +// +// When used in the context of a projection, a response message or +// sub-message is filtered by the API to only contain those fields as +// specified in the mask. For example, if the mask in the previous +// example is applied to a response message as follows: +// +// f { +// a : 22 +// b { +// d : 1 +// x : 2 +// } +// y : 13 +// } +// z: 8 +// +// The result will not contain specific values for fields x,y and z +// (their value will be set to the default, and omitted in proto text +// output): +// +// +// f { +// a : 22 +// b { +// d : 1 +// } +// } +// +// A repeated field is not allowed except at the last position of a +// paths string. +// +// If a FieldMask object is not present in a get operation, the +// operation applies to all fields (as if a FieldMask of all fields +// had been specified). +// +// Note that a field mask does not necessarily apply to the +// top-level response message. In case of a REST get operation, the +// field mask applies directly to the response, but in case of a REST +// list operation, the mask instead applies to each individual message +// in the returned resource list. In case of a REST custom method, +// other definitions may be used. Where the mask applies will be +// clearly documented together with its declaration in the API. In +// any case, the effect on the returned resource/resources is required +// behavior for APIs. +// +// # Field Masks in Update Operations +// +// A field mask in update operations specifies which fields of the +// targeted resource are going to be updated. The API is required +// to only change the values of the fields as specified in the mask +// and leave the others untouched. If a resource is passed in to +// describe the updated values, the API ignores the values of all +// fields not covered by the mask. +// +// If a repeated field is specified for an update operation, new values will +// be appended to the existing repeated field in the target resource. Note that +// a repeated field is only allowed in the last position of a `paths` string. +// +// If a sub-message is specified in the last position of the field mask for an +// update operation, then new value will be merged into the existing sub-message +// in the target resource. +// +// For example, given the target message: +// +// f { +// b { +// d: 1 +// x: 2 +// } +// c: [1] +// } +// +// And an update message: +// +// f { +// b { +// d: 10 +// } +// c: [2] +// } +// +// then if the field mask is: +// +// paths: ["f.b", "f.c"] +// +// then the result will be: +// +// f { +// b { +// d: 10 +// x: 2 +// } +// c: [1, 2] +// } +// +// An implementation may provide options to override this default behavior for +// repeated and message fields. +// +// In order to reset a field's value to the default, the field must +// be in the mask and set to the default value in the provided resource. +// Hence, in order to reset all fields of a resource, provide a default +// instance of the resource and set all fields in the mask, or do +// not provide a mask as described below. +// +// If a field mask is not present on update, the operation applies to +// all fields (as if a field mask of all fields has been specified). +// Note that in the presence of schema evolution, this may mean that +// fields the client does not know and has therefore not filled into +// the request will be reset to their default. If this is unwanted +// behavior, a specific service may require a client to always specify +// a field mask, producing an error if not. +// +// As with get operations, the location of the resource which +// describes the updated values in the request message depends on the +// operation kind. In any case, the effect of the field mask is +// required to be honored by the API. +// +// ## Considerations for HTTP REST +// +// The HTTP kind of an update operation which uses a field mask must +// be set to PATCH instead of PUT in order to satisfy HTTP semantics +// (PUT must only be used for full updates). +// +// # JSON Encoding of Field Masks +// +// In JSON, a field mask is encoded as a single string where paths are +// separated by a comma. Fields name in each path are converted +// to/from lower-camel naming conventions. +// +// As an example, consider the following message declarations: +// +// message Profile { +// User user = 1; +// Photo photo = 2; +// } +// message User { +// string display_name = 1; +// string address = 2; +// } +// +// In proto a field mask for `Profile` may look as such: +// +// mask { +// paths: "user.display_name" +// paths: "photo" +// } +// +// In JSON, the same mask is represented as below: +// +// { +// mask: "user.displayName,photo" +// } +// +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. +// +// ## Field Mask Verification +// +// The implementation of any API method which has a FieldMask type field in the +// request should verify the included field paths, and return an +// `INVALID_ARGUMENT` error if any path is unmappable. +message FieldMask { + // The set of field mask paths. + repeated string paths = 1; +} diff --git a/third_party/google/protobuf/source_context.proto b/third_party/google/protobuf/source_context.proto new file mode 100644 index 0000000..06bfc43 --- /dev/null +++ b/third_party/google/protobuf/source_context.proto @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "SourceContextProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; + +// `SourceContext` represents information about the source of a +// protobuf element, like the file in which it is defined. +message SourceContext { + // The path-qualified name of the .proto file that contained the associated + // protobuf element. For example: `"google/protobuf/source_context.proto"`. + string file_name = 1; +} diff --git a/third_party/google/protobuf/struct.proto b/third_party/google/protobuf/struct.proto new file mode 100644 index 0000000..0ac843c --- /dev/null +++ b/third_party/google/protobuf/struct.proto @@ -0,0 +1,95 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/structpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "StructProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Struct` represents a structured data value, consisting of fields +// which map to dynamically typed values. In some languages, `Struct` +// might be supported by a native representation. For example, in +// scripting languages like JS a struct is represented as an +// object. The details of that representation are described together +// with the proto support for the language. +// +// The JSON representation for `Struct` is JSON object. +message Struct { + // Unordered map of dynamically typed values. + map fields = 1; +} + +// `Value` represents a dynamically typed value which can be either +// null, a number, a string, a boolean, a recursive struct value, or a +// list of values. A producer of value is expected to set one of these +// variants. Absence of any variant indicates an error. +// +// The JSON representation for `Value` is JSON value. +message Value { + // The kind of value. + oneof kind { + // Represents a null value. + NullValue null_value = 1; + // Represents a double value. + double number_value = 2; + // Represents a string value. + string string_value = 3; + // Represents a boolean value. + bool bool_value = 4; + // Represents a structured value. + Struct struct_value = 5; + // Represents a repeated `Value`. + ListValue list_value = 6; + } +} + +// `NullValue` is a singleton enumeration to represent the null value for the +// `Value` type union. +// +// The JSON representation for `NullValue` is JSON `null`. +enum NullValue { + // Null value. + NULL_VALUE = 0; +} + +// `ListValue` is a wrapper around a repeated field of values. +// +// The JSON representation for `ListValue` is JSON array. +message ListValue { + // Repeated field of dynamically typed values. + repeated Value values = 1; +} diff --git a/third_party/google/protobuf/timestamp.proto b/third_party/google/protobuf/timestamp.proto new file mode 100644 index 0000000..3b2df6d --- /dev/null +++ b/third_party/google/protobuf/timestamp.proto @@ -0,0 +1,147 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/timestamppb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from Java `Instant.now()`. +// +// Instant now = Instant.now(); +// +// Timestamp timestamp = +// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) +// .setNanos(now.getNano()).build(); +// +// +// Example 6: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required. A proto3 JSON serializer should always use UTC (as indicated by +// "Z") when printing the Timestamp type and a proto3 JSON parser should be +// able to accept both UTC and other timezones (as indicated by an offset). +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D +// ) to obtain a formatter capable of generating timestamps in this format. +// +// +message Timestamp { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/third_party/google/protobuf/type.proto b/third_party/google/protobuf/type.proto new file mode 100644 index 0000000..d3f6a68 --- /dev/null +++ b/third_party/google/protobuf/type.proto @@ -0,0 +1,187 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/any.proto"; +import "google/protobuf/source_context.proto"; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TypeProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option go_package = "google.golang.org/protobuf/types/known/typepb"; + +// A protocol buffer message type. +message Type { + // The fully qualified message name. + string name = 1; + // The list of fields. + repeated Field fields = 2; + // The list of types appearing in `oneof` definitions in this type. + repeated string oneofs = 3; + // The protocol buffer options. + repeated Option options = 4; + // The source context. + SourceContext source_context = 5; + // The source syntax. + Syntax syntax = 6; +} + +// A single field of a message type. +message Field { + // Basic field types. + enum Kind { + // Field type unknown. + TYPE_UNKNOWN = 0; + // Field type double. + TYPE_DOUBLE = 1; + // Field type float. + TYPE_FLOAT = 2; + // Field type int64. + TYPE_INT64 = 3; + // Field type uint64. + TYPE_UINT64 = 4; + // Field type int32. + TYPE_INT32 = 5; + // Field type fixed64. + TYPE_FIXED64 = 6; + // Field type fixed32. + TYPE_FIXED32 = 7; + // Field type bool. + TYPE_BOOL = 8; + // Field type string. + TYPE_STRING = 9; + // Field type group. Proto2 syntax only, and deprecated. + TYPE_GROUP = 10; + // Field type message. + TYPE_MESSAGE = 11; + // Field type bytes. + TYPE_BYTES = 12; + // Field type uint32. + TYPE_UINT32 = 13; + // Field type enum. + TYPE_ENUM = 14; + // Field type sfixed32. + TYPE_SFIXED32 = 15; + // Field type sfixed64. + TYPE_SFIXED64 = 16; + // Field type sint32. + TYPE_SINT32 = 17; + // Field type sint64. + TYPE_SINT64 = 18; + } + + // Whether a field is optional, required, or repeated. + enum Cardinality { + // For fields with unknown cardinality. + CARDINALITY_UNKNOWN = 0; + // For optional fields. + CARDINALITY_OPTIONAL = 1; + // For required fields. Proto2 syntax only. + CARDINALITY_REQUIRED = 2; + // For repeated fields. + CARDINALITY_REPEATED = 3; + } + + // The field type. + Kind kind = 1; + // The field cardinality. + Cardinality cardinality = 2; + // The field number. + int32 number = 3; + // The field name. + string name = 4; + // The field type URL, without the scheme, for message or enumeration + // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. + string type_url = 6; + // The index of the field type in `Type.oneofs`, for message or enumeration + // types. The first type has index 1; zero means the type is not in the list. + int32 oneof_index = 7; + // Whether to use alternative packed wire representation. + bool packed = 8; + // The protocol buffer options. + repeated Option options = 9; + // The field JSON name. + string json_name = 10; + // The string value of the default value of this field. Proto2 syntax only. + string default_value = 11; +} + +// Enum type definition. +message Enum { + // Enum type name. + string name = 1; + // Enum value definitions. + repeated EnumValue enumvalue = 2; + // Protocol buffer options. + repeated Option options = 3; + // The source context. + SourceContext source_context = 4; + // The source syntax. + Syntax syntax = 5; +} + +// Enum value definition. +message EnumValue { + // Enum value name. + string name = 1; + // Enum value number. + int32 number = 2; + // Protocol buffer options. + repeated Option options = 3; +} + +// A protocol buffer option, which can be attached to a message, field, +// enumeration, etc. +message Option { + // The option's name. For protobuf built-in options (options defined in + // descriptor.proto), this is the short name. For example, `"map_entry"`. + // For custom options, it should be the fully-qualified name. For example, + // `"google.api.http"`. + string name = 1; + // The option's value packed in an Any message. If the value is a primitive, + // the corresponding wrapper type defined in google/protobuf/wrappers.proto + // should be used. If the value is an enum, it should be stored as an int32 + // value using the google.protobuf.Int32Value type. + Any value = 2; +} + +// The syntax in which a protocol buffer element is defined. +enum Syntax { + // Syntax `proto2`. + SYNTAX_PROTO2 = 0; + // Syntax `proto3`. + SYNTAX_PROTO3 = 1; +} diff --git a/third_party/google/protobuf/wrappers.proto b/third_party/google/protobuf/wrappers.proto new file mode 100644 index 0000000..d49dd53 --- /dev/null +++ b/third_party/google/protobuf/wrappers.proto @@ -0,0 +1,123 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Wrappers for primitive (non-message) types. These types are useful +// for embedding primitives in the `google.protobuf.Any` type and for places +// where we need to distinguish between the absence of a primitive +// typed field and its default value. +// +// These wrappers have no meaningful use within repeated fields as they lack +// the ability to detect presence on individual elements. +// These wrappers have no meaningful use within a map or a oneof since +// individual entries of a map or fields of a oneof can already detect presence. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "WrappersProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. +message DoubleValue { + // The double value. + double value = 1; +} + +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. +message FloatValue { + // The float value. + float value = 1; +} + +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. +message Int64Value { + // The int64 value. + int64 value = 1; +} + +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. +message UInt64Value { + // The uint64 value. + uint64 value = 1; +} + +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. +message Int32Value { + // The int32 value. + int32 value = 1; +} + +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. +message UInt32Value { + // The uint32 value. + uint32 value = 1; +} + +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. +message BoolValue { + // The bool value. + bool value = 1; +} + +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. +message StringValue { + // The string value. + string value = 1; +} + +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. +message BytesValue { + // The bytes value. + bytes value = 1; +} diff --git a/third_party/openapi/v3/annotations.proto b/third_party/openapi/v3/annotations.proto new file mode 100644 index 0000000..54fe3aa --- /dev/null +++ b/third_party/openapi/v3/annotations.proto @@ -0,0 +1,60 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package openapi.v3; + +import "openapi/v3/openapi.proto"; +import "google/protobuf/descriptor.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "AnnotationsProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v3"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +// The Go package name. +option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; + +extend google.protobuf.FileOptions { + Document document = 1143; +} + +extend google.protobuf.MethodOptions { + Operation operation = 1143; +} + +extend google.protobuf.MessageOptions { + Schema schema = 1143; +} + +extend google.protobuf.FieldOptions { + Schema property = 1143; +} \ No newline at end of file diff --git a/third_party/openapi/v3/openapi.proto b/third_party/openapi/v3/openapi.proto new file mode 100644 index 0000000..7aede5e --- /dev/null +++ b/third_party/openapi/v3/openapi.proto @@ -0,0 +1,672 @@ +// Copyright 2020 Google LLC. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +syntax = "proto3"; + +package openapi.v3; + +import "google/protobuf/any.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v3"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +// The Go package name. +option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; + +message AdditionalPropertiesItem { + oneof oneof { + SchemaOrReference schema_or_reference = 1; + bool boolean = 2; + } +} + +message Any { + google.protobuf.Any value = 1; + string yaml = 2; +} + +message AnyOrExpression { + oneof oneof { + Any any = 1; + Expression expression = 2; + } +} + +// A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation. +message Callback { + repeated NamedPathItem path = 1; + repeated NamedAny specification_extension = 2; +} + +message CallbackOrReference { + oneof oneof { + Callback callback = 1; + Reference reference = 2; + } +} + +message CallbacksOrReferences { + repeated NamedCallbackOrReference additional_properties = 1; +} + +// Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object. +message Components { + SchemasOrReferences schemas = 1; + ResponsesOrReferences responses = 2; + ParametersOrReferences parameters = 3; + ExamplesOrReferences examples = 4; + RequestBodiesOrReferences request_bodies = 5; + HeadersOrReferences headers = 6; + SecuritySchemesOrReferences security_schemes = 7; + LinksOrReferences links = 8; + CallbacksOrReferences callbacks = 9; + repeated NamedAny specification_extension = 10; +} + +// Contact information for the exposed API. +message Contact { + string name = 1; + string url = 2; + string email = 3; + repeated NamedAny specification_extension = 4; +} + +message DefaultType { + oneof oneof { + double number = 1; + bool boolean = 2; + string string = 3; + } +} + +// When request bodies or response payloads may be one of a number of different schemas, a `discriminator` object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the specification of an alternative schema based on the value associated with it. When using the discriminator, _inline_ schemas will not be considered. +message Discriminator { + string property_name = 1; + Strings mapping = 2; + repeated NamedAny specification_extension = 3; +} + +message Document { + string openapi = 1; + Info info = 2; + repeated Server servers = 3; + Paths paths = 4; + Components components = 5; + repeated SecurityRequirement security = 6; + repeated Tag tags = 7; + ExternalDocs external_docs = 8; + repeated NamedAny specification_extension = 9; +} + +// A single encoding definition applied to a single schema property. +message Encoding { + string content_type = 1; + HeadersOrReferences headers = 2; + string style = 3; + bool explode = 4; + bool allow_reserved = 5; + repeated NamedAny specification_extension = 6; +} + +message Encodings { + repeated NamedEncoding additional_properties = 1; +} + +message Example { + string summary = 1; + string description = 2; + Any value = 3; + string external_value = 4; + repeated NamedAny specification_extension = 5; +} + +message ExampleOrReference { + oneof oneof { + Example example = 1; + Reference reference = 2; + } +} + +message ExamplesOrReferences { + repeated NamedExampleOrReference additional_properties = 1; +} + +message Expression { + repeated NamedAny additional_properties = 1; +} + +// Allows referencing an external resource for extended documentation. +message ExternalDocs { + string description = 1; + string url = 2; + repeated NamedAny specification_extension = 3; +} + +// The Header Object follows the structure of the Parameter Object with the following changes: 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map. 1. `in` MUST NOT be specified, it is implicitly in `header`. 1. All traits that are affected by the location MUST be applicable to a location of `header` (for example, `style`). +message Header { + string description = 1; + bool required = 2; + bool deprecated = 3; + bool allow_empty_value = 4; + string style = 5; + bool explode = 6; + bool allow_reserved = 7; + SchemaOrReference schema = 8; + Any example = 9; + ExamplesOrReferences examples = 10; + MediaTypes content = 11; + repeated NamedAny specification_extension = 12; +} + +message HeaderOrReference { + oneof oneof { + Header header = 1; + Reference reference = 2; + } +} + +message HeadersOrReferences { + repeated NamedHeaderOrReference additional_properties = 1; +} + +// The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience. +message Info { + string title = 1; + string description = 2; + string terms_of_service = 3; + Contact contact = 4; + License license = 5; + string version = 6; + repeated NamedAny specification_extension = 7; + string summary = 8; +} + +message ItemsItem { + repeated SchemaOrReference schema_or_reference = 1; +} + +// License information for the exposed API. +message License { + string name = 1; + string url = 2; + repeated NamedAny specification_extension = 3; +} + +// The `Link object` represents a possible design-time link for a response. The presence of a link does not guarantee the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. Unlike _dynamic_ links (i.e. links provided **in** the response payload), the OAS linking mechanism does not require link information in the runtime response. For computing links, and providing instructions to execute them, a runtime expression is used for accessing values in an operation and using them as parameters while invoking the linked operation. +message Link { + string operation_ref = 1; + string operation_id = 2; + AnyOrExpression parameters = 3; + AnyOrExpression request_body = 4; + string description = 5; + Server server = 6; + repeated NamedAny specification_extension = 7; +} + +message LinkOrReference { + oneof oneof { + Link link = 1; + Reference reference = 2; + } +} + +message LinksOrReferences { + repeated NamedLinkOrReference additional_properties = 1; +} + +// Each Media Type Object provides schema and examples for the media type identified by its key. +message MediaType { + SchemaOrReference schema = 1; + Any example = 2; + ExamplesOrReferences examples = 3; + Encodings encoding = 4; + repeated NamedAny specification_extension = 5; +} + +message MediaTypes { + repeated NamedMediaType additional_properties = 1; +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +message NamedAny { + // Map key + string name = 1; + // Mapped value + Any value = 2; +} + +// Automatically-generated message used to represent maps of CallbackOrReference as ordered (name,value) pairs. +message NamedCallbackOrReference { + // Map key + string name = 1; + // Mapped value + CallbackOrReference value = 2; +} + +// Automatically-generated message used to represent maps of Encoding as ordered (name,value) pairs. +message NamedEncoding { + // Map key + string name = 1; + // Mapped value + Encoding value = 2; +} + +// Automatically-generated message used to represent maps of ExampleOrReference as ordered (name,value) pairs. +message NamedExampleOrReference { + // Map key + string name = 1; + // Mapped value + ExampleOrReference value = 2; +} + +// Automatically-generated message used to represent maps of HeaderOrReference as ordered (name,value) pairs. +message NamedHeaderOrReference { + // Map key + string name = 1; + // Mapped value + HeaderOrReference value = 2; +} + +// Automatically-generated message used to represent maps of LinkOrReference as ordered (name,value) pairs. +message NamedLinkOrReference { + // Map key + string name = 1; + // Mapped value + LinkOrReference value = 2; +} + +// Automatically-generated message used to represent maps of MediaType as ordered (name,value) pairs. +message NamedMediaType { + // Map key + string name = 1; + // Mapped value + MediaType value = 2; +} + +// Automatically-generated message used to represent maps of ParameterOrReference as ordered (name,value) pairs. +message NamedParameterOrReference { + // Map key + string name = 1; + // Mapped value + ParameterOrReference value = 2; +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +message NamedPathItem { + // Map key + string name = 1; + // Mapped value + PathItem value = 2; +} + +// Automatically-generated message used to represent maps of RequestBodyOrReference as ordered (name,value) pairs. +message NamedRequestBodyOrReference { + // Map key + string name = 1; + // Mapped value + RequestBodyOrReference value = 2; +} + +// Automatically-generated message used to represent maps of ResponseOrReference as ordered (name,value) pairs. +message NamedResponseOrReference { + // Map key + string name = 1; + // Mapped value + ResponseOrReference value = 2; +} + +// Automatically-generated message used to represent maps of SchemaOrReference as ordered (name,value) pairs. +message NamedSchemaOrReference { + // Map key + string name = 1; + // Mapped value + SchemaOrReference value = 2; +} + +// Automatically-generated message used to represent maps of SecuritySchemeOrReference as ordered (name,value) pairs. +message NamedSecuritySchemeOrReference { + // Map key + string name = 1; + // Mapped value + SecuritySchemeOrReference value = 2; +} + +// Automatically-generated message used to represent maps of ServerVariable as ordered (name,value) pairs. +message NamedServerVariable { + // Map key + string name = 1; + // Mapped value + ServerVariable value = 2; +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +message NamedString { + // Map key + string name = 1; + // Mapped value + string value = 2; +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +message NamedStringArray { + // Map key + string name = 1; + // Mapped value + StringArray value = 2; +} + +// Configuration details for a supported OAuth Flow +message OauthFlow { + string authorization_url = 1; + string token_url = 2; + string refresh_url = 3; + Strings scopes = 4; + repeated NamedAny specification_extension = 5; +} + +// Allows configuration of the supported OAuth Flows. +message OauthFlows { + OauthFlow implicit = 1; + OauthFlow password = 2; + OauthFlow client_credentials = 3; + OauthFlow authorization_code = 4; + repeated NamedAny specification_extension = 5; +} + +message Object { + repeated NamedAny additional_properties = 1; +} + +// Describes a single API operation on a path. +message Operation { + repeated string tags = 1; + string summary = 2; + string description = 3; + ExternalDocs external_docs = 4; + string operation_id = 5; + repeated ParameterOrReference parameters = 6; + RequestBodyOrReference request_body = 7; + Responses responses = 8; + CallbacksOrReferences callbacks = 9; + bool deprecated = 10; + repeated SecurityRequirement security = 11; + repeated Server servers = 12; + repeated NamedAny specification_extension = 13; +} + +// Describes a single operation parameter. A unique parameter is defined by a combination of a name and location. +message Parameter { + string name = 1; + string in = 2; + string description = 3; + bool required = 4; + bool deprecated = 5; + bool allow_empty_value = 6; + string style = 7; + bool explode = 8; + bool allow_reserved = 9; + SchemaOrReference schema = 10; + Any example = 11; + ExamplesOrReferences examples = 12; + MediaTypes content = 13; + repeated NamedAny specification_extension = 14; +} + +message ParameterOrReference { + oneof oneof { + Parameter parameter = 1; + Reference reference = 2; + } +} + +message ParametersOrReferences { + repeated NamedParameterOrReference additional_properties = 1; +} + +// Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available. +message PathItem { + string _ref = 1; + string summary = 2; + string description = 3; + Operation get = 4; + Operation put = 5; + Operation post = 6; + Operation delete = 7; + Operation options = 8; + Operation head = 9; + Operation patch = 10; + Operation trace = 11; + repeated Server servers = 12; + repeated ParameterOrReference parameters = 13; + repeated NamedAny specification_extension = 14; +} + +// Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the `Server Object` in order to construct the full URL. The Paths MAY be empty, due to ACL constraints. +message Paths { + repeated NamedPathItem path = 1; + repeated NamedAny specification_extension = 2; +} + +message Properties { + repeated NamedSchemaOrReference additional_properties = 1; +} + +// A simple object to allow referencing other components in the specification, internally and externally. The Reference Object is defined by JSON Reference and follows the same structure, behavior and rules. For this specification, reference resolution is accomplished as defined by the JSON Reference specification and not by the JSON Schema specification. +message Reference { + string _ref = 1; + string summary = 2; + string description = 3; +} + +message RequestBodiesOrReferences { + repeated NamedRequestBodyOrReference additional_properties = 1; +} + +// Describes a single request body. +message RequestBody { + string description = 1; + MediaTypes content = 2; + bool required = 3; + repeated NamedAny specification_extension = 4; +} + +message RequestBodyOrReference { + oneof oneof { + RequestBody request_body = 1; + Reference reference = 2; + } +} + +// Describes a single response from an API Operation, including design-time, static `links` to operations based on the response. +message Response { + string description = 1; + HeadersOrReferences headers = 2; + MediaTypes content = 3; + LinksOrReferences links = 4; + repeated NamedAny specification_extension = 5; +} + +message ResponseOrReference { + oneof oneof { + Response response = 1; + Reference reference = 2; + } +} + +// A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. The documentation is not necessarily expected to cover all possible HTTP response codes because they may not be known in advance. However, documentation is expected to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call. +message Responses { + ResponseOrReference default = 1; + repeated NamedResponseOrReference response_or_reference = 2; + repeated NamedAny specification_extension = 3; +} + +message ResponsesOrReferences { + repeated NamedResponseOrReference additional_properties = 1; +} + +// The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00. For more information about the properties, see JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions follow the JSON Schema. +message Schema { + bool nullable = 1; + Discriminator discriminator = 2; + bool read_only = 3; + bool write_only = 4; + Xml xml = 5; + ExternalDocs external_docs = 6; + Any example = 7; + bool deprecated = 8; + string title = 9; + double multiple_of = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + int64 max_properties = 21; + int64 min_properties = 22; + repeated string required = 23; + repeated Any enum = 24; + string type = 25; + repeated SchemaOrReference all_of = 26; + repeated SchemaOrReference one_of = 27; + repeated SchemaOrReference any_of = 28; + Schema not = 29; + ItemsItem items = 30; + Properties properties = 31; + AdditionalPropertiesItem additional_properties = 32; + DefaultType default = 33; + string description = 34; + string format = 35; + repeated NamedAny specification_extension = 36; +} + +message SchemaOrReference { + oneof oneof { + Schema schema = 1; + Reference reference = 2; + } +} + +message SchemasOrReferences { + repeated NamedSchemaOrReference additional_properties = 1; +} + +// Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the Security Schemes under the Components Object. Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are required to convey security information. When a list of Security Requirement Objects is defined on the OpenAPI Object or Operation Object, only one of the Security Requirement Objects in the list needs to be satisfied to authorize the request. +message SecurityRequirement { + repeated NamedStringArray additional_properties = 1; +} + +// Defines a security scheme that can be used by the operations. Supported schemes are HTTP authentication, an API key (either as a header, a cookie parameter or as a query parameter), mutual TLS (use of a client certificate), OAuth2's common flows (implicit, password, application and access code) as defined in RFC6749, and OpenID Connect. Please note that currently (2019) the implicit flow is about to be deprecated OAuth 2.0 Security Best Current Practice. Recommended for most use case is Authorization Code Grant flow with PKCE. +message SecurityScheme { + string type = 1; + string description = 2; + string name = 3; + string in = 4; + string scheme = 5; + string bearer_format = 6; + OauthFlows flows = 7; + string open_id_connect_url = 8; + repeated NamedAny specification_extension = 9; +} + +message SecuritySchemeOrReference { + oneof oneof { + SecurityScheme security_scheme = 1; + Reference reference = 2; + } +} + +message SecuritySchemesOrReferences { + repeated NamedSecuritySchemeOrReference additional_properties = 1; +} + +// An object representing a Server. +message Server { + string url = 1; + string description = 2; + ServerVariables variables = 3; + repeated NamedAny specification_extension = 4; +} + +// An object representing a Server Variable for server URL template substitution. +message ServerVariable { + repeated string enum = 1; + string default = 2; + string description = 3; + repeated NamedAny specification_extension = 4; +} + +message ServerVariables { + repeated NamedServerVariable additional_properties = 1; +} + +// Any property starting with x- is valid. +message SpecificationExtension { + oneof oneof { + double number = 1; + bool boolean = 2; + string string = 3; + } +} + +message StringArray { + repeated string value = 1; +} + +message Strings { + repeated NamedString additional_properties = 1; +} + +// Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per tag defined in the Operation Object instances. +message Tag { + string name = 1; + string description = 2; + ExternalDocs external_docs = 3; + repeated NamedAny specification_extension = 4; +} + +// A metadata object that allows for more fine-tuned XML model definitions. When using arrays, XML element names are *not* inferred (for singular/plural forms) and the `name` property SHOULD be used to add that information. See examples for expected behavior. +message Xml { + string name = 1; + string namespace = 2; + string prefix = 3; + bool attribute = 4; + bool wrapped = 5; + repeated NamedAny specification_extension = 6; +} + diff --git a/third_party/validate/README.md b/third_party/validate/README.md new file mode 100644 index 0000000..56698db --- /dev/null +++ b/third_party/validate/README.md @@ -0,0 +1,3 @@ +# protoc-gen-validate (PGV) + +* https://github.com/envoyproxy/protoc-gen-validate diff --git a/third_party/validate/validate.proto b/third_party/validate/validate.proto new file mode 100644 index 0000000..4195ecf --- /dev/null +++ b/third_party/validate/validate.proto @@ -0,0 +1,863 @@ +syntax = "proto2"; +package validate; + +option go_package = "github.com/envoyproxy/protoc-gen-validate/validate"; +option java_package = "io.envoyproxy.pgv.validate"; + +import "google/protobuf/descriptor.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +// Validation rules applied at the message level +extend google.protobuf.MessageOptions { + // Disabled nullifies any validation rules for this message, including any + // message fields associated with it that do support validation. + optional bool disabled = 1071; + // Ignore skips generation of validation methods for this message. + optional bool ignored = 1072; +} + +// Validation rules applied at the oneof level +extend google.protobuf.OneofOptions { + // Required ensures that exactly one the field options in a oneof is set; + // validation fails if no fields in the oneof are set. + optional bool required = 1071; +} + +// Validation rules applied at the field level +extend google.protobuf.FieldOptions { + // Rules specify the validations to be performed on this field. By default, + // no validation is performed against a field. + optional FieldRules rules = 1071; +} + +// FieldRules encapsulates the rules for each type of field. Depending on the +// field, the correct set should be used to ensure proper validations. +message FieldRules { + optional MessageRules message = 17; + oneof type { + // Scalar Field Types + FloatRules float = 1; + DoubleRules double = 2; + Int32Rules int32 = 3; + Int64Rules int64 = 4; + UInt32Rules uint32 = 5; + UInt64Rules uint64 = 6; + SInt32Rules sint32 = 7; + SInt64Rules sint64 = 8; + Fixed32Rules fixed32 = 9; + Fixed64Rules fixed64 = 10; + SFixed32Rules sfixed32 = 11; + SFixed64Rules sfixed64 = 12; + BoolRules bool = 13; + StringRules string = 14; + BytesRules bytes = 15; + + // Complex Field Types + EnumRules enum = 16; + RepeatedRules repeated = 18; + MapRules map = 19; + + // Well-Known Field Types + AnyRules any = 20; + DurationRules duration = 21; + TimestampRules timestamp = 22; + } +} + +// FloatRules describes the constraints applied to `float` values +message FloatRules { + // Const specifies that this field must be exactly the specified value + optional float const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional float lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional float lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional float gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional float gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated float in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated float not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// DoubleRules describes the constraints applied to `double` values +message DoubleRules { + // Const specifies that this field must be exactly the specified value + optional double const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional double lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional double lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional double gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional double gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated double in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated double not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Int32Rules describes the constraints applied to `int32` values +message Int32Rules { + // Const specifies that this field must be exactly the specified value + optional int32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional int32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional int32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional int32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional int32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated int32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Int64Rules describes the constraints applied to `int64` values +message Int64Rules { + // Const specifies that this field must be exactly the specified value + optional int64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional int64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional int64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional int64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional int64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated int64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// UInt32Rules describes the constraints applied to `uint32` values +message UInt32Rules { + // Const specifies that this field must be exactly the specified value + optional uint32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional uint32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional uint32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional uint32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional uint32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated uint32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated uint32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// UInt64Rules describes the constraints applied to `uint64` values +message UInt64Rules { + // Const specifies that this field must be exactly the specified value + optional uint64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional uint64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional uint64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional uint64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional uint64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated uint64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated uint64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SInt32Rules describes the constraints applied to `sint32` values +message SInt32Rules { + // Const specifies that this field must be exactly the specified value + optional sint32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sint32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sint32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sint32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sint32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sint32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sint32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SInt64Rules describes the constraints applied to `sint64` values +message SInt64Rules { + // Const specifies that this field must be exactly the specified value + optional sint64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sint64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sint64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sint64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sint64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sint64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sint64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Fixed32Rules describes the constraints applied to `fixed32` values +message Fixed32Rules { + // Const specifies that this field must be exactly the specified value + optional fixed32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional fixed32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional fixed32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional fixed32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional fixed32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated fixed32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated fixed32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// Fixed64Rules describes the constraints applied to `fixed64` values +message Fixed64Rules { + // Const specifies that this field must be exactly the specified value + optional fixed64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional fixed64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional fixed64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional fixed64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional fixed64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated fixed64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated fixed64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SFixed32Rules describes the constraints applied to `sfixed32` values +message SFixed32Rules { + // Const specifies that this field must be exactly the specified value + optional sfixed32 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sfixed32 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sfixed32 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sfixed32 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sfixed32 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sfixed32 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sfixed32 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// SFixed64Rules describes the constraints applied to `sfixed64` values +message SFixed64Rules { + // Const specifies that this field must be exactly the specified value + optional sfixed64 const = 1; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional sfixed64 lt = 2; + + // Lte specifies that this field must be less than or equal to the + // specified value, inclusive + optional sfixed64 lte = 3; + + // Gt specifies that this field must be greater than the specified value, + // exclusive. If the value of Gt is larger than a specified Lt or Lte, the + // range is reversed. + optional sfixed64 gt = 4; + + // Gte specifies that this field must be greater than or equal to the + // specified value, inclusive. If the value of Gte is larger than a + // specified Lt or Lte, the range is reversed. + optional sfixed64 gte = 5; + + // In specifies that this field must be equal to one of the specified + // values + repeated sfixed64 in = 6; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated sfixed64 not_in = 7; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 8; +} + +// BoolRules describes the constraints applied to `bool` values +message BoolRules { + // Const specifies that this field must be exactly the specified value + optional bool const = 1; +} + +// StringRules describe the constraints applied to `string` values +message StringRules { + // Const specifies that this field must be exactly the specified value + optional string const = 1; + + // Len specifies that this field must be the specified number of + // characters (Unicode code points). Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 len = 19; + + // MinLen specifies that this field must be the specified number of + // characters (Unicode code points) at a minimum. Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 min_len = 2; + + // MaxLen specifies that this field must be the specified number of + // characters (Unicode code points) at a maximum. Note that the number of + // characters may differ from the number of bytes in the string. + optional uint64 max_len = 3; + + // LenBytes specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 len_bytes = 20; + + // MinBytes specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 min_bytes = 4; + + // MaxBytes specifies that this field must be the specified number of bytes + // at a maximum + optional uint64 max_bytes = 5; + + // Pattern specifes that this field must match against the specified + // regular expression (RE2 syntax). The included expression should elide + // any delimiters. + optional string pattern = 6; + + // Prefix specifies that this field must have the specified substring at + // the beginning of the string. + optional string prefix = 7; + + // Suffix specifies that this field must have the specified substring at + // the end of the string. + optional string suffix = 8; + + // Contains specifies that this field must have the specified substring + // anywhere in the string. + optional string contains = 9; + + // NotContains specifies that this field cannot have the specified substring + // anywhere in the string. + optional string not_contains = 23; + + // In specifies that this field must be equal to one of the specified + // values + repeated string in = 10; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated string not_in = 11; + + // WellKnown rules provide advanced constraints against common string + // patterns + oneof well_known { + // Email specifies that the field must be a valid email address as + // defined by RFC 5322 + bool email = 12; + + // Hostname specifies that the field must be a valid hostname as + // defined by RFC 1034. This constraint does not support + // internationalized domain names (IDNs). + bool hostname = 13; + + // Ip specifies that the field must be a valid IP (v4 or v6) address. + // Valid IPv6 addresses should not include surrounding square brackets. + bool ip = 14; + + // Ipv4 specifies that the field must be a valid IPv4 address. + bool ipv4 = 15; + + // Ipv6 specifies that the field must be a valid IPv6 address. Valid + // IPv6 addresses should not include surrounding square brackets. + bool ipv6 = 16; + + // Uri specifies that the field must be a valid, absolute URI as defined + // by RFC 3986 + bool uri = 17; + + // UriRef specifies that the field must be a valid URI as defined by RFC + // 3986 and may be relative or absolute. + bool uri_ref = 18; + + // Address specifies that the field must be either a valid hostname as + // defined by RFC 1034 (which does not support internationalized domain + // names or IDNs), or it can be a valid IP (v4 or v6). + bool address = 21; + + // Uuid specifies that the field must be a valid UUID as defined by + // RFC 4122 + bool uuid = 22; + + // WellKnownRegex specifies a common well known pattern defined as a regex. + KnownRegex well_known_regex = 24; + } + + // This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable + // strict header validation. + // By default, this is true, and HTTP header validations are RFC-compliant. + // Setting to false will enable a looser validations that only disallows + // \r\n\0 characters, which can be used to bypass header matching rules. + optional bool strict = 25 [default = true]; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 26; +} + +// WellKnownRegex contain some well-known patterns. +enum KnownRegex { + UNKNOWN = 0; + + // HTTP header name as defined by RFC 7230. + HTTP_HEADER_NAME = 1; + + // HTTP header value as defined by RFC 7230. + HTTP_HEADER_VALUE = 2; +} + +// BytesRules describe the constraints applied to `bytes` values +message BytesRules { + // Const specifies that this field must be exactly the specified value + optional bytes const = 1; + + // Len specifies that this field must be the specified number of bytes + optional uint64 len = 13; + + // MinLen specifies that this field must be the specified number of bytes + // at a minimum + optional uint64 min_len = 2; + + // MaxLen specifies that this field must be the specified number of bytes + // at a maximum + optional uint64 max_len = 3; + + // Pattern specifes that this field must match against the specified + // regular expression (RE2 syntax). The included expression should elide + // any delimiters. + optional string pattern = 4; + + // Prefix specifies that this field must have the specified bytes at the + // beginning of the string. + optional bytes prefix = 5; + + // Suffix specifies that this field must have the specified bytes at the + // end of the string. + optional bytes suffix = 6; + + // Contains specifies that this field must have the specified bytes + // anywhere in the string. + optional bytes contains = 7; + + // In specifies that this field must be equal to one of the specified + // values + repeated bytes in = 8; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated bytes not_in = 9; + + // WellKnown rules provide advanced constraints against common byte + // patterns + oneof well_known { + // Ip specifies that the field must be a valid IP (v4 or v6) address in + // byte format + bool ip = 10; + + // Ipv4 specifies that the field must be a valid IPv4 address in byte + // format + bool ipv4 = 11; + + // Ipv6 specifies that the field must be a valid IPv6 address in byte + // format + bool ipv6 = 12; + } + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 14; +} + +// EnumRules describe the constraints applied to enum values +message EnumRules { + // Const specifies that this field must be exactly the specified value + optional int32 const = 1; + + // DefinedOnly specifies that this field must be only one of the defined + // values for this enum, failing on any undefined value. + optional bool defined_only = 2; + + // In specifies that this field must be equal to one of the specified + // values + repeated int32 in = 3; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated int32 not_in = 4; +} + +// MessageRules describe the constraints applied to embedded message values. +// For message-type fields, validation is performed recursively. +message MessageRules { + // Skip specifies that the validation rules of this field should not be + // evaluated + optional bool skip = 1; + + // Required specifies that this field must be set + optional bool required = 2; +} + +// RepeatedRules describe the constraints applied to `repeated` values +message RepeatedRules { + // MinItems specifies that this field must have the specified number of + // items at a minimum + optional uint64 min_items = 1; + + // MaxItems specifies that this field must have the specified number of + // items at a maximum + optional uint64 max_items = 2; + + // Unique specifies that all elements in this field must be unique. This + // contraint is only applicable to scalar and enum types (messages are not + // supported). + optional bool unique = 3; + + // Items specifies the contraints to be applied to each item in the field. + // Repeated message fields will still execute validation against each item + // unless skip is specified here. + optional FieldRules items = 4; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 5; +} + +// MapRules describe the constraints applied to `map` values +message MapRules { + // MinPairs specifies that this field must have the specified number of + // KVs at a minimum + optional uint64 min_pairs = 1; + + // MaxPairs specifies that this field must have the specified number of + // KVs at a maximum + optional uint64 max_pairs = 2; + + // NoSparse specifies values in this field cannot be unset. This only + // applies to map's with message value types. + optional bool no_sparse = 3; + + // Keys specifies the constraints to be applied to each key in the field. + optional FieldRules keys = 4; + + // Values specifies the constraints to be applied to the value of each key + // in the field. Message values will still have their validations evaluated + // unless skip is specified here. + optional FieldRules values = 5; + + // IgnoreEmpty specifies that the validation rules of this field should be + // evaluated only if the field is not empty + optional bool ignore_empty = 6; +} + +// AnyRules describe constraints applied exclusively to the +// `google.protobuf.Any` well-known type +message AnyRules { + // Required specifies that this field must be set + optional bool required = 1; + + // In specifies that this field's `type_url` must be equal to one of the + // specified values. + repeated string in = 2; + + // NotIn specifies that this field's `type_url` must not be equal to any of + // the specified values. + repeated string not_in = 3; +} + +// DurationRules describe the constraints applied exclusively to the +// `google.protobuf.Duration` well-known type +message DurationRules { + // Required specifies that this field must be set + optional bool required = 1; + + // Const specifies that this field must be exactly the specified value + optional google.protobuf.Duration const = 2; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional google.protobuf.Duration lt = 3; + + // Lt specifies that this field must be less than the specified value, + // inclusive + optional google.protobuf.Duration lte = 4; + + // Gt specifies that this field must be greater than the specified value, + // exclusive + optional google.protobuf.Duration gt = 5; + + // Gte specifies that this field must be greater than the specified value, + // inclusive + optional google.protobuf.Duration gte = 6; + + // In specifies that this field must be equal to one of the specified + // values + repeated google.protobuf.Duration in = 7; + + // NotIn specifies that this field cannot be equal to one of the specified + // values + repeated google.protobuf.Duration not_in = 8; +} + +// TimestampRules describe the constraints applied exclusively to the +// `google.protobuf.Timestamp` well-known type +message TimestampRules { + // Required specifies that this field must be set + optional bool required = 1; + + // Const specifies that this field must be exactly the specified value + optional google.protobuf.Timestamp const = 2; + + // Lt specifies that this field must be less than the specified value, + // exclusive + optional google.protobuf.Timestamp lt = 3; + + // Lte specifies that this field must be less than the specified value, + // inclusive + optional google.protobuf.Timestamp lte = 4; + + // Gt specifies that this field must be greater than the specified value, + // exclusive + optional google.protobuf.Timestamp gt = 5; + + // Gte specifies that this field must be greater than the specified value, + // inclusive + optional google.protobuf.Timestamp gte = 6; + + // LtNow specifies that this must be less than the current time. LtNow + // can only be used with the Within rule. + optional bool lt_now = 7; + + // GtNow specifies that this must be greater than the current time. GtNow + // can only be used with the Within rule. + optional bool gt_now = 8; + + // Within specifies that this field must be within this duration of the + // current time. This constraint can be used alone or with the LtNow and + // GtNow rules. + optional google.protobuf.Duration within = 9; +} diff --git a/web/.commitlintrc.js b/web/.commitlintrc.js new file mode 100644 index 0000000..422b194 --- /dev/null +++ b/web/.commitlintrc.js @@ -0,0 +1 @@ +module.exports = { extends: ['@commitlint/config-conventional'] }; diff --git a/web/.editorconfig b/web/.editorconfig new file mode 100644 index 0000000..7e3649a --- /dev/null +++ b/web/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..7237b34 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +**/node_modules +# roadhog-api-doc ignore +/src/utils/request-temp.js +_roadhog-api-doc + +# production +/dist + +# misc +.DS_Store +npm-debug.log* +yarn-error.log + +/coverage +.idea +yarn.lock +package-lock.json +*bak +.vscode + + +# visual studio code +.history +*.log +functions/* +.temp/** + +# umi +.umi +.umi-production +.umi-test +.turbopack + +# screenshot +screenshot +.firebase + +build diff --git a/web/.husky/commit-msg b/web/.husky/commit-msg new file mode 100644 index 0000000..0a4b97d --- /dev/null +++ b/web/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit $1 diff --git a/web/.husky/pre-commit b/web/.husky/pre-commit new file mode 100644 index 0000000..c27d889 --- /dev/null +++ b/web/.husky/pre-commit @@ -0,0 +1 @@ +lint-staged diff --git a/web/.lintstagedrc b/web/.lintstagedrc new file mode 100644 index 0000000..1c2023c --- /dev/null +++ b/web/.lintstagedrc @@ -0,0 +1,5 @@ +{ + "**/*.{js,jsx,tsx,ts,md,css,less,json}": [ + "npx @biomejs/biome check --write" + ] +} diff --git a/web/.npmrc b/web/.npmrc new file mode 100644 index 0000000..521a9f7 --- /dev/null +++ b/web/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/web/CODE_OF_CONDUCT.md b/web/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..2b4571c --- /dev/null +++ b/web/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at afc163@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/web/LICENSE b/web/LICENSE new file mode 100644 index 0000000..b65958e --- /dev/null +++ b/web/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-present Alipay.inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/web/README.ar-DZ.md b/web/README.ar-DZ.md new file mode 100644 index 0000000..10976d6 --- /dev/null +++ b/web/README.ar-DZ.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +اللغة: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +حل واجهة مستخدم جاهز لتطبيقات المؤسسات مبني على React. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +معاينة السمة الفاتحة +معاينة السمة الداكنة + +
+ +- المعاينة: http://preview.pro.ant.design +- الصفحة الرئيسية: http://pro.ant.design +- التوثيق: http://pro.ant.design/docs/getting-started +- سجل التغييرات: http://pro.ant.design/docs/changelog +- الأسئلة الشائعة: http://pro.ant.design/docs/faq + +## الميزات + +- :bulb: **TypeScript**: لغة لتطبيقات JavaScript على نطاق واسع +- :scroll: **الكتل**: بناء الصفحات باستخدام قوالب الكتل +- :gem: **تصميم أنيق**: يتبع [مواصفات Ant Design](http://ant.design/) +- :triangular_ruler: **قوالب شائعة**: قوالب نموذجية لتطبيقات المؤسسات +- :rocket: **تطوير حديث**: أحدث تقنيات React/umi/dva/antd +- :iphone: **متجاوب**: مصمم لأحجام شاشات مختلفة +- :art: **تخصيص السمة**: سمة قابلة للتخصيص بإعداد بسيط +- :globe_with_meridians: **دعم اللغات**: حل i18n مدمج +- :gear: **أفضل الممارسات**: سير عمل قوي للحفاظ على صحة الكود +- :1234: **تطوير وهمي**: حل تطوير وهمي سهل الاستخدام +- :white_check_mark: **اختبار الواجهة**: أمان مع اختبارات الوحدة وe2e + +## القوالب + +``` +- لوحة القيادة + - تحليلات + - مراقبة + - مساحة العمل +- النماذج + - نموذج أساسي + - نموذج متعدد الخطوات + - نموذج متقدم +- القوائم + - جدول قياسي + - قائمة قياسية + - قائمة البطاقات + - قائمة البحث (مشروع/تطبيقات/مقال) +- الملف الشخصي + - ملف شخصي بسيط + - ملف شخصي متقدم +- الحساب + - مركز الحساب + - إعدادات الحساب +- النتائج + - نجاح + - فشل +- الاستثناءات + - 403 + - 404 + - 500 +- المستخدم + - تسجيل الدخول + - التسجيل + - نتيجة التسجيل +``` + +## الاستخدام + +### استخدام bash + +نوفر pro-cli لبدء المشروع بسرعة. + +```bash +# استخدم npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +اختر قالب pro. Simple هو القالب الأساسي الذي يوفر فقط المحتوى الأساسي لتشغيل الإطار. Complete يحتوي على جميع الكتل، وهو غير مناسب كقالب أساسي للتطوير الثانوي. + +```shell +? 🚀 مشروع كامل أم هيكل بسيط؟ (استخدم الأسهم) +➥ simple + complete +``` + +تهيئة مستودع Git: + +```shell +$ git init myapp +``` + +تثبيت التبعيات: + +```shell +$ cd myapp && tyarn +// أو +$ cd myapp && npm install +``` + +## المتصفحات المدعومة + +المتصفحات الحديثة. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | آخر إصدارين | آخر إصدارين | آخر إصدارين | آخر إصدارين | + +## المساهمة + +أي مساهمة مرحب بها. إليك بعض الطرق للمساهمة في هذا المشروع: + +- استخدم Ant Design Pro في عملك اليومي. +- أرسل [issues](http://github.com/ant-design/ant-design-pro/issues) للإبلاغ عن الأخطاء أو طرح الأسئلة. +- اقترح [pull requests](http://github.com/ant-design/ant-design-pro/pulls) لتحسين الكود الخاص بنا. diff --git a/web/README.es-ES.md b/web/README.es-ES.md new file mode 100644 index 0000000..0ec0206 --- /dev/null +++ b/web/README.es-ES.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +Idioma: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +Una solución de interfaz de usuario lista para usar para aplicaciones empresariales basada en React. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +vista previa del tema claro +vista previa del tema oscuro + +
+ +- Vista previa: http://preview.pro.ant.design +- Página principal: http://pro.ant.design +- Documentación: http://pro.ant.design/docs/getting-started +- Registro de cambios: http://pro.ant.design/docs/changelog +- Preguntas frecuentes: http://pro.ant.design/docs/faq + +## Características + +- :bulb: **TypeScript**: Un lenguaje para aplicaciones JavaScript a gran escala +- :scroll: **Bloques**: Construye páginas con plantillas de bloques +- :gem: **Diseño elegante**: Sigue la [especificación de Ant Design](http://ant.design/) +- :triangular_ruler: **Plantillas comunes**: Plantillas típicas para aplicaciones empresariales +- :rocket: **Desarrollo de vanguardia**: Stack de desarrollo más reciente con React/umi/dva/antd +- :iphone: **Responsivo**: Diseñado para diferentes tamaños de pantalla +- :art: **Tematización**: Tema personalizable con configuración sencilla +- :globe_with_meridians: **Internacionalización**: Solución i18n integrada +- :gear: **Buenas prácticas**: Flujo de trabajo sólido para mantener tu código saludable +- :1234: **Desarrollo mock**: Solución de desarrollo mock fácil de usar +- :white_check_mark: **Pruebas de UI**: Seguridad con pruebas unitarias y e2e + +## Plantillas + +``` +- Panel de control + - Analítica + - Monitorización + - Espacio de trabajo +- Formulario + - Formulario básico + - Formulario por pasos + - Formulario avanzado +- Lista + - Tabla estándar + - Lista estándar + - Lista de tarjetas + - Lista de búsqueda (Proyecto/Aplicaciones/Artículo) +- Perfil + - Perfil simple + - Perfil avanzado +- Cuenta + - Centro de cuenta + - Configuración de cuenta +- Resultado + - Éxito + - Fallo +- Excepción + - 403 + - 404 + - 500 +- Usuario + - Iniciar sesión + - Registrarse + - Resultado del registro +``` + +## Uso + +### Usar bash + +Proporcionamos pro-cli para inicializar rápidamente el proyecto. + +```bash +# usar npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +Elige la plantilla pro. Simple es la plantilla básica, que solo proporciona el contenido esencial para el funcionamiento del framework. Complete contiene todos los bloques, por lo que no es adecuada como plantilla base para desarrollo secundario. + +```shell +? 🚀 ¿Proyecto completo o un esqueleto simple? (Usa las flechas) +➥ simple + complete +``` + +Inicializa el repositorio Git: + +```shell +$ git init myapp +``` + +Instala las dependencias: + +```shell +$ cd myapp && tyarn +// o +$ cd myapp && npm install +``` + +## Navegadores soportados + +Navegadores modernos. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones | + +## Contribución + +Cualquier tipo de contribución es bienvenida. Aquí tienes algunos ejemplos de cómo puedes contribuir a este proyecto: + +- Usa Ant Design Pro en tu trabajo diario. +- Envía [issues](http://github.com/ant-design/ant-design-pro/issues) para informar de errores o hacer preguntas. +- Propón [pull requests](http://github.com/ant-design/ant-design-pro/pulls) para mejorar nuestro código. diff --git a/web/README.fr-FR.md b/web/README.fr-FR.md new file mode 100644 index 0000000..76c445a --- /dev/null +++ b/web/README.fr-FR.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +Langue : 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +Une solution d'interface utilisateur prête à l'emploi pour les applications d'entreprise, basée sur React. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +aperçu du thème clair +aperçu du thème sombre + +
+ +- Aperçu : http://preview.pro.ant.design +- Page d'accueil : http://pro.ant.design +- Documentation : http://pro.ant.design/docs/getting-started +- Journal des modifications : http://pro.ant.design/docs/changelog +- FAQ : http://pro.ant.design/docs/faq + +## Fonctionnalités + +- :bulb: **TypeScript** : Un langage pour des applications JavaScript à grande échelle +- :scroll: **Blocs** : Construisez des pages avec des modèles de blocs +- :gem: **Design soigné** : Conforme à la [spécification Ant Design](http://ant.design/) +- :triangular_ruler: **Modèles courants** : Modèles typiques pour les applications d'entreprise +- :rocket: **Développement de pointe** : Stack de développement la plus récente avec React/umi/dva/antd +- :iphone: **Responsive** : Conçu pour différentes tailles d'écran +- :art: **Thématisation** : Thème personnalisable avec une configuration simple +- :globe_with_meridians: **Internationalisation** : Solution i18n intégrée +- :gear: **Bonnes pratiques** : Workflow solide pour garder votre code sain +- :1234: **Développement mock** : Solution de développement mock facile à utiliser +- :white_check_mark: **Tests UI** : Sécurité avec des tests unitaires et e2e + +## Modèles + +``` +- Tableau de bord + - Analytique + - Surveillance + - Espace de travail +- Formulaire + - Formulaire de base + - Formulaire par étapes + - Formulaire avancé +- Liste + - Tableau standard + - Liste standard + - Liste de cartes + - Liste de recherche (Projet/Applications/Article) +- Profil + - Profil simple + - Profil avancé +- Compte + - Centre de compte + - Paramètres du compte +- Résultat + - Succès + - Échec +- Exception + - 403 + - 404 + - 500 +- Utilisateur + - Connexion + - Inscription + - Résultat d'inscription +``` + +## Utilisation + +### Utiliser bash + +Nous fournissons pro-cli pour initialiser rapidement le projet. + +```bash +# utiliser npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +Choisissez le modèle pro. Simple est le modèle de base, qui ne fournit que le contenu de base pour le fonctionnement du framework. Complete contient tous les blocs, ce qui n'est pas adapté comme modèle de base pour un développement secondaire. + +```shell +? 🚀 Un projet complet ou un simple squelette ? (Utilisez les flèches) +➥ simple + complete +``` + +Initialisez le dépôt Git : + +```shell +$ git init myapp +``` + +Installez les dépendances : + +```shell +$ cd myapp && tyarn +// ou +$ cd myapp && npm install +``` + +## Navigateurs supportés + +Navigateurs modernes. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | 2 dernières versions | 2 dernières versions | 2 dernières versions | 2 dernières versions | + +## Contribution + +Toute contribution est la bienvenue, voici quelques exemples de comment vous pouvez contribuer à ce projet : + +- Utilisez Ant Design Pro dans votre travail quotidien. +- Soumettez des [issues](http://github.com/ant-design/ant-design-pro/issues) pour signaler des bugs ou poser des questions. +- Proposez des [pull requests](http://github.com/ant-design/ant-design-pro/pulls) pour améliorer notre code. diff --git a/web/README.ja-JP.md b/web/README.ja-JP.md new file mode 100644 index 0000000..208d19e --- /dev/null +++ b/web/README.ja-JP.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +言語: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +エンタープライズアプリケーション向けの、Reactベースのすぐに使えるUIソリューション。 + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +ライトテーマのプレビュー +ダークテーマのプレビュー + +
+ +- プレビュー: http://preview.pro.ant.design +- ホームページ: http://pro.ant.design +- ドキュメント: http://pro.ant.design/docs/getting-started +- 変更履歴: http://pro.ant.design/docs/changelog +- FAQ: http://pro.ant.design/docs/faq + +## 特徴 + +- :bulb: **TypeScript**: 大規模JavaScriptアプリケーション向けの言語 +- :scroll: **ブロック**: ブロックテンプレートでページを構築 +- :gem: **洗練されたデザイン**: [Ant Design仕様](http://ant.design/)に準拠 +- :triangular_ruler: **一般的なテンプレート**: 企業向けアプリケーションの典型的なテンプレート +- :rocket: **最新の開発環境**: React/umi/dva/antdの最新スタック +- :iphone: **レスポンシブ**: 様々な画面サイズに対応 +- :art: **テーマ**: シンプルな設定でカスタマイズ可能なテーマ +- :globe_with_meridians: **国際化**: 組み込みのi18nソリューション +- :gear: **ベストプラクティス**: 健全なコードを保つためのワークフロー +- :1234: **モック開発**: 使いやすいモック開発ソリューション +- :white_check_mark: **UIテスト**: ユニットテストとE2Eテストで安全に + +## テンプレート + +``` +- ダッシュボード + - 分析 + - モニター + - ワークスペース +- フォーム + - 基本フォーム + - ステップフォーム + - 高度なフォーム +- リスト + - 標準テーブル + - 標準リスト + - カードリスト + - 検索リスト(プロジェクト/アプリケーション/記事) +- プロフィール + - シンプルプロフィール + - 高度なプロフィール +- アカウント + - アカウントセンター + - アカウント設定 +- 結果 + - 成功 + - 失敗 +- 例外 + - 403 + - 404 + - 500 +- ユーザー + - ログイン + - 登録 + - 登録結果 +``` + +## 使い方 + +### bashを使う + +pro-cliを使って素早くプロジェクトを初期化できます。 + +```bash +# npmを使用 +npm i @ant-design/pro-cli -g +pro create myapp +``` + +proテンプレートを選択します。simpleは基本テンプレートで、フレームワークの基本的な内容のみを提供します。completeはすべてのブロックを含み、二次開発のベースとしては適していません。 + +```shell +? 🚀 フル機能かシンプルなスキャフォールドか?(矢印キーで選択) +➥ simple + complete +``` + +Gitリポジトリを初期化: + +```shell +$ git init myapp +``` + +依存関係をインストール: + +```shell +$ cd myapp && tyarn +// または +$ cd myapp && npm install +``` + +## 対応ブラウザ + +モダンブラウザ対応。 + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | 最新2バージョン | 最新2バージョン | 最新2バージョン | 最新2バージョン | + +## コントリビュート + +どんな形の貢献も歓迎します。以下はこのプロジェクトに貢献する例です: + +- 日常業務でAnt Design Proを使う +- [issues](http://github.com/ant-design/ant-design-pro/issues)でバグ報告や質問を投稿する +- [pull requests](http://github.com/ant-design/ant-design-pro/pulls)でコード改善を提案する diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..2f9c625 --- /dev/null +++ b/web/README.md @@ -0,0 +1,127 @@ +Language: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇵🇹](./README.pt-BR.md) | [🇸🇦](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +An out-of-box UI solution for enterprise applications as a React boilerplate. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +light theme preview +dark theme preview + +
+ +- Preview: http://preview.pro.ant.design +- Home Page: http://pro.ant.design +- Documentation: http://pro.ant.design/docs/getting-started +- ChangeLog: http://pro.ant.design/docs/changelog +- FAQ: http://pro.ant.design/docs/faq + +## Features + +- :bulb: **TypeScript**: A language for application-scale JavaScript +- :scroll: **Blocks**: Build page with block template +- :gem: **Neat Design**: Follow [Ant Design specification](http://ant.design/) +- :triangular_ruler: **Common Templates**: Typical templates for enterprise applications +- :rocket: **State of The Art Development**: Newest development stack of React/umi/dva/antd +- :iphone: **Responsive**: Designed for variable screen sizes +- :art: **Theming**: Customizable theme with simple config +- :globe_with_meridians: **International**: Built-in i18n solution +- :gear: **Best Practices**: Solid workflow to make your code healthy +- :1234: **Mock development**: Easy to use mock development solution +- :white_check_mark: **UI Test**: Fly safely with unit and e2e tests + +## Templates + +``` +- Dashboard + - Analytic + - Monitor + - Workspace +- Form + - Basic Form + - Step Form + - Advanced From +- List + - Standard Table + - Standard List + - Card List + - Search List (Project/Applications/Article) +- Profile + - Simple Profile + - Advanced Profile +- Account + - Account Center + - Account Settings +- Result + - Success + - Failed +- Exception + - 403 + - 404 + - 500 +- User + - Login + - Register + - Register Result +``` + +## Usage + +### Use bash + +We provide pro-cli to quickly initialize scaffolding. + +```bash +# use npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +Choose the pro template. Simple is the basic template, which only provides the basic content of the framework operation. Complete contains all blocks, which is not suitable for secondary development as a basic template. + +```shell +? 🚀 Full or a simple scaffold? (Use arrow keys) +❯ simple + complete +``` + +Initialized Git repository: + +```shell +$ git init myapp +``` + +Install dependencies: + +```shell +$ cd myapp && tyarn +// or +$ cd myapp && npm install +``` + +## Browsers support + +Modern browsers. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + +## Contributing + +Any type of contribution is welcome, here are some examples of how you may contribute to this project: + +- Use Ant Design Pro in your daily work. +- Submit [issues](http://github.com/ant-design/ant-design-pro/issues) to report bugs or ask questions. +- Propose [pull requests](http://github.com/ant-design/ant-design-pro/pulls) to improve our code. + + + Contribution Leaderboard + diff --git a/web/README.pt-BR.md b/web/README.pt-BR.md new file mode 100644 index 0000000..2041969 --- /dev/null +++ b/web/README.pt-BR.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +Idioma: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +Uma solução de UI pronta para uso para aplicações empresariais baseada em React. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +visualização do tema claro +visualização do tema escuro + +
+ +- Visualizar: http://preview.pro.ant.design +- Página inicial: http://pro.ant.design +- Documentação: http://pro.ant.design/docs/getting-started +- Registro de alterações: http://pro.ant.design/docs/changelog +- FAQ: http://pro.ant.design/docs/faq + +## Funcionalidades + +- :bulb: **TypeScript**: Uma linguagem para aplicações JavaScript em larga escala +- :scroll: **Blocos**: Construa páginas com modelos de blocos +- :gem: **Design elegante**: Segue a [especificação do Ant Design](http://ant.design/) +- :triangular_ruler: **Modelos comuns**: Modelos típicos para aplicações empresariais +- :rocket: **Desenvolvimento de ponta**: Stack mais recente de React/umi/dva/antd +- :iphone: **Responsivo**: Projetado para diferentes tamanhos de tela +- :art: **Temas**: Tema personalizável com configuração simples +- :globe_with_meridians: **Internacionalização**: Solução i18n integrada +- :gear: **Boas práticas**: Workflow sólido para manter seu código saudável +- :1234: **Desenvolvimento mock**: Solução de mock fácil de usar +- :white_check_mark: **Teste de UI**: Segurança com testes unitários e e2e + +## Modelos + +``` +- Painel + - Analítico + - Monitoramento + - Espaço de trabalho +- Formulário + - Formulário básico + - Formulário em etapas + - Formulário avançado +- Lista + - Tabela padrão + - Lista padrão + - Lista de cartões + - Lista de busca (Projeto/Aplicações/Artigo) +- Perfil + - Perfil simples + - Perfil avançado +- Conta + - Central da conta + - Configurações da conta +- Resultado + - Sucesso + - Falha +- Exceção + - 403 + - 404 + - 500 +- Usuário + - Login + - Registro + - Resultado do registro +``` + +## Uso + +### Usando bash + +Fornecemos o pro-cli para inicializar rapidamente o projeto. + +```bash +# usar npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +Escolha o modelo pro. Simple é o modelo básico, que fornece apenas o conteúdo essencial para o funcionamento do framework. Complete contém todos os blocos, não sendo adequado como modelo base para desenvolvimento secundário. + +```shell +? 🚀 Projeto completo ou um esqueleto simples? (Use as setas) +➥ simple + complete +``` + +Inicialize o repositório Git: + +```shell +$ git init myapp +``` + +Instale as dependências: + +```shell +$ cd myapp && tyarn +// ou +$ cd myapp && npm install +``` + +## Navegadores suportados + +Navegadores modernos. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões | + +## Contribuindo + +Qualquer tipo de contribuição é bem-vinda. Aqui estão alguns exemplos de como você pode contribuir para este projeto: + +- Use o Ant Design Pro no seu trabalho diário. +- Envie [issues](http://github.com/ant-design/ant-design-pro/issues) para relatar bugs ou fazer perguntas. +- Proponha [pull requests](http://github.com/ant-design/ant-design-pro/pulls) para melhorar nosso código. diff --git a/web/README.ru-RU.md b/web/README.ru-RU.md new file mode 100644 index 0000000..fbca494 --- /dev/null +++ b/web/README.ru-RU.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +Язык: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +Готовое решение UI для корпоративных приложений на базе React. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +светлая тема +тёмная тема + +
+ +- Превью: http://preview.pro.ant.design +- Главная страница: http://pro.ant.design +- Документация: http://pro.ant.design/docs/getting-started +- Список изменений: http://pro.ant.design/docs/changelog +- FAQ: http://pro.ant.design/docs/faq + +## Возможности + +- :bulb: **TypeScript**: Язык для масштабируемых JavaScript-приложений +- :scroll: **Блоки**: Построение страниц с помощью шаблонов блоков +- :gem: **Элегантный дизайн**: Следует [спецификации Ant Design](http://ant.design/) +- :triangular_ruler: **Типовые шаблоны**: Типовые шаблоны для корпоративных приложений +- :rocket: **Современный стек**: Самые новые технологии React/umi/dva/antd +- :iphone: **Адаптивность**: Поддержка разных размеров экранов +- :art: **Темизация**: Кастомизация темы через простую конфигурацию +- :globe_with_meridians: **Интернационализация**: Встроенное решение i18n +- :gear: **Лучшие практики**: Надёжный workflow для поддержания качества кода +- :1234: **Мок-разработка**: Удобное решение для разработки с мок-данными +- :white_check_mark: **UI-тесты**: Безопасность с помощью unit и e2e тестов + +## Шаблоны + +``` +- Дашборд + - Аналитика + - Мониторинг + - Рабочее пространство +- Форма + - Базовая форма + - Многошаговая форма + - Продвинутая форма +- Список + - Стандартная таблица + - Стандартный список + - Список карточек + - Поисковый список (Проект/Приложения/Статья) +- Профиль + - Простой профиль + - Продвинутый профиль +- Аккаунт + - Центр аккаунта + - Настройки аккаунта +- Результат + - Успех + - Ошибка +- Исключения + - 403 + - 404 + - 500 +- Пользователь + - Вход + - Регистрация + - Результат регистрации +``` + +## Использование + +### Использование bash + +Мы предоставляем pro-cli для быстрой инициализации проекта. + +```bash +# использовать npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +Выберите шаблон pro. Simple — это базовый шаблон, который содержит только необходимый минимум для работы фреймворка. Complete включает все блоки и не подходит для вторичной разработки как базовый шаблон. + +```shell +? 🚀 Полный или простой шаблон? (Используйте стрелки) +➥ simple + complete +``` + +Инициализация репозитория Git: + +```shell +$ git init myapp +``` + +Установка зависимостей: + +```shell +$ cd myapp && tyarn +// или +$ cd myapp && npm install +``` + +## Поддержка браузеров + +Современные браузеры. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | последние 2 версии | последние 2 версии | последние 2 версии | последние 2 версии | + +## Вклад + +Любой вклад приветствуется. Вот несколько способов, как вы можете помочь проекту: + +- Используйте Ant Design Pro в своей повседневной работе. +- Оставляйте [issues](http://github.com/ant-design/ant-design-pro/issues) для сообщений об ошибках или вопросов. +- Предлагайте [pull requests](http://github.com/ant-design/ant-design-pro/pulls) для улучшения кода. diff --git a/web/README.tr-TR.md b/web/README.tr-TR.md new file mode 100644 index 0000000..2cb2191 --- /dev/null +++ b/web/README.tr-TR.md @@ -0,0 +1,125 @@ +# Ant Design Pro + +Dil: 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇧🇷](./README.pt-BR.md) | [🇩🇿](./README.ar-DZ.md) | [🇪🇸](./README.es-ES.md) + +

Ant Design Pro

+ +
+ +React tabanlı kurumsal uygulamalar için kutudan çıkan bir UI çözümü. + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +[![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)](https://ant.design/) + +açık tema önizlemesi +koyu tema önizlemesi + +
+ +- Önizleme: http://preview.pro.ant.design +- Ana Sayfa: http://pro.ant.design +- Dokümantasyon: http://pro.ant.design/docs/getting-started +- Değişiklik Günlüğü: http://pro.ant.design/docs/changelog +- SSS: http://pro.ant.design/docs/faq + +## Özellikler + +- :bulb: **TypeScript**: Büyük ölçekli JavaScript uygulamaları için bir dil +- :scroll: **Bloklar**: Blok şablonlarıyla sayfa oluşturun +- :gem: **Şık Tasarım**: [Ant Design spesifikasyonuna](http://ant.design/) uygun +- :triangular_ruler: **Yaygın Şablonlar**: Kurumsal uygulamalar için tipik şablonlar +- :rocket: **En Yeni Geliştirme**: React/umi/dva/antd'nin en yeni geliştirme yığını +- :iphone: **Duyarlı**: Farklı ekran boyutları için tasarlandı +- :art: **Tema**: Basit yapılandırmayla özelleştirilebilir tema +- :globe_with_meridians: **Uluslararasılaştırma**: Dahili i18n çözümü +- :gear: **En İyi Uygulamalar**: Kodunuzu sağlıklı tutmak için sağlam iş akışı +- :1234: **Mock geliştirme**: Kullanımı kolay mock geliştirme çözümü +- :white_check_mark: **UI Testi**: Birim ve e2e testleriyle güvenli geliştirme + +## Şablonlar + +``` +- Gösterge Paneli + - Analitik + - İzleme + - Çalışma Alanı +- Form + - Temel Form + - Adım Adım Form + - Gelişmiş Form +- Liste + - Standart Tablo + - Standart Liste + - Kart Listesi + - Arama Listesi (Proje/Uygulamalar/Makale) +- Profil + - Basit Profil + - Gelişmiş Profil +- Hesap + - Hesap Merkezi + - Hesap Ayarları +- Sonuç + - Başarılı + - Başarısız +- İstisna + - 403 + - 404 + - 500 +- Kullanıcı + - Giriş + - Kayıt Ol + - Kayıt Sonucu +``` + +## Kullanım + +### Bash kullanımı + +Projeyi hızlıca başlatmak için pro-cli sağlıyoruz. + +```bash +# npm kullan +npm i @ant-design/pro-cli -g +pro create myapp +``` + +Pro şablonunu seçin. Simple, yalnızca temel framework içeriğini sağlayan temel şablondur. Complete, tüm blokları içerir ve ikincil geliştirme için temel şablon olarak uygun değildir. + +```shell +? 🚀 Tam veya basit bir iskelet mi? (Ok tuşlarını kullanın) +➥ simple + complete +``` + +Git deposunu başlatın: + +```shell +$ git init myapp +``` + +Bağımlılıkları yükleyin: + +```shell +$ cd myapp && tyarn +// veya +$ cd myapp && npm install +``` + +## Desteklenen Tarayıcılar + +Modern tarayıcılar. + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | son 2 sürüm | son 2 sürüm | son 2 sürüm | son 2 sürüm | + +## Katkı + +Her türlü katkı memnuniyetle karşılanır. Bu projeye katkıda bulunmanın bazı yolları şunlardır: + +- Ant Design Pro'yu günlük işinizde kullanın. +- Hataları bildirmek veya soru sormak için [issues](http://github.com/ant-design/ant-design-pro/issues) gönderin. +- Kodumuzu geliştirmek için [pull requests](http://github.com/ant-design/ant-design-pro/pulls) önerin. diff --git a/web/README.zh-CN.md b/web/README.zh-CN.md new file mode 100644 index 0000000..9cfd93e --- /dev/null +++ b/web/README.zh-CN.md @@ -0,0 +1,120 @@ +Language : [🇺🇸](./README.md) | 🇨🇳 | [🇷🇺](./README.ru-RU.md) | [🇹🇷](./README.tr-TR.md) | [🇯🇵](./README.ja-JP.md) | [🇫🇷](./README.fr-FR.md) | [🇵🇹](./README.pt-BR.md) | [🇸🇦](./README.ar-DZ.md) + +

Ant Design Pro

+ +
+ +开箱即用的中台前端/设计解决方案。 + +[![CI](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/ci.yml) +[![Preview Deploy](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml/badge.svg)](https://github.com/ant-design/ant-design-pro/actions/workflows/preview-deploy.yml) +[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) +[![Checked with Biome](https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev) +![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label) + +![](https://github.com/user-attachments/assets/fde29061-3d9a-4397-8ac2-397b0e033ef5) + +
+ +- 预览:http://preview.pro.ant.design +- 首页:http://pro.ant.design/index-cn +- 使用文档:http://pro.ant.design/docs/getting-started-cn +- 更新日志: http://pro.ant.design/docs/changelog-cn +- 常见问题:http://pro.ant.design/docs/faq-cn + +## 5.0 已经发布! 🎉🎉🎉 + +[Ant Design Pro 5.0](https://github.com/ant-design/ant-design-pro/issues/8656) + +## 特性 + +- :bulb: **TypeScript**: 应用程序级 JavaScript 的语言 +- :scroll: **区块**: 通过区块模板快速构建页面 +- :gem: **优雅美观**:基于 Ant Design 体系精心设计 +- :triangular_ruler: **常见设计模式**:提炼自中后台应用的典型页面和场景 +- :rocket: **最新技术栈**:使用 React/umi/dva/antd 等前端前沿技术开发 +- :iphone: **响应式**:针对不同屏幕大小设计 +- :art: **主题**:可配置的主题满足多样化的品牌诉求 +- :globe_with_meridians: **国际化**:内建业界通用的国际化方案 +- :gear: **最佳实践**:良好的工程实践助您持续产出高质量代码 +- :1234: **Mock 数据**:实用的本地数据调试方案 +- :white_check_mark: **UI 测试**:自动化测试保障前端产品质量 + +## 模板 + +``` +- Dashboard + - 分析页 + - 监控页 + - 工作台 +- 表单页 + - 基础表单页 + - 分步表单页 + - 高级表单页 +- 列表页 + - 查询表格 + - 标准列表 + - 卡片列表 + - 搜索列表(项目/应用/文章) +- 详情页 + - 基础详情页 + - 高级详情页 +- 用户 + - 用户中心页 + - 用户设置页 +- 结果 + - 成功页 + - 失败页 +- 异常 + - 403 无权限 + - 404 找不到 + - 500 服务器出错 +- 帐户 + - 登录 + - 注册 + - 注册成功 +``` + +## 使用 + +我们提供了 pro-cli 来快速的初始化脚手架。 + +```bash +# 使用 npm +npm i @ant-design/pro-cli -g +pro create myapp +``` + +选择 pro 的模板,simple 是基础模板,只提供了框架运行的基本内容,complete 包含所有区块,不太适合当基础模板来进行二次开发。 + +```shell +? 🚀 要全量的还是一个简单的脚手架? (Use arrow keys) +❯ simple + complete +``` + +安装依赖: + +```shell +$ cd myapp && tyarn +// 或 +$ cd myapp && npm install +``` + +更多信息请参考 [使用文档](http://pro.ant.design/docs/getting-started)。 + +## 支持环境 + +现代浏览器。 + +| [Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | [Opera](http://godban.github.io/browsers-support-badges/)
Opera | +| --- | --- | --- | --- | --- | +| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + +## 参与贡献 + +我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :smiley:: + +- 在你的公司或个人项目中使用 Ant Design Pro。 +- 通过 [Issue](http://github.com/ant-design/ant-design-pro/issues) 报告 bug 或进行咨询。 +- 提交 [Pull Request](http://github.com/ant-design/ant-design-pro/pulls) 改进 Pro 的代码。 diff --git a/web/biome.json b/web/biome.json new file mode 100644 index 0000000..3acf0db --- /dev/null +++ b/web/biome.json @@ -0,0 +1,49 @@ +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "files": { + "ignoreUnknown": true, + "includes": [ + "**/*", + "!**/.umi", + "!**/.umi-production", + "!**/.umi-test", + "!**/.umi-test-production", + "!**/src/services", + "!**/mock", + "!**/dist", + "!**/server", + "!**/public", + "!**/coverage", + "!**/node_modules", + "!biome.json" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "off" + }, + "correctness": { + "useUniqueElementIds": "off", + "useExhaustiveDependencies": "off" + }, + "a11y": { + "noStaticElementInteractions": "off", + "useValidAnchor": "off", + "useKeyWithClickEvents": "off" + } + } + }, + "javascript": { + "jsxRuntime": "reactClassic", + "formatter": { + "quoteStyle": "single" + } + } +} diff --git a/web/config/config.ts b/web/config/config.ts new file mode 100644 index 0000000..1a98ebe --- /dev/null +++ b/web/config/config.ts @@ -0,0 +1,177 @@ +// https://umijs.org/config/ + +import { defineConfig } from "@umijs/max"; +import { join } from "node:path"; +import defaultSettings from "./defaultSettings"; +import proxy from "./proxy"; + +import routes from "./routes"; + +const { UMI_ENV = "dev" } = process.env; + +/** + * @name 使用公共路径 + * @description 部署时的路径,如果部署在非根目录下,需要配置这个变量 + * @doc https://umijs.org/docs/api/config#publicpath + */ +const PUBLIC_PATH: string = "/"; + +export default defineConfig({ + /** + * @name 开启 hash 模式 + * @description 让 build 之后的产物包含 hash 后缀。通常用于增量发布和避免浏览器加载缓存。 + * @doc https://umijs.org/docs/api/config#hash + */ + hash: true, + + publicPath: PUBLIC_PATH, + + /** + * @name 兼容性设置 + * @description 设置 ie11 不一定完美兼容,需要检查自己使用的所有依赖 + * @doc https://umijs.org/docs/api/config#targets + */ + // targets: { + // ie: 11, + // }, + /** + * @name 路由的配置,不在路由中引入的文件不会编译 + * @description 只支持 path,component,routes,redirect,wrappers,title 的配置 + * @doc https://umijs.org/docs/guides/routes + */ + // umi routes: https://umijs.org/docs/routing + routes, + /** + * @name 主题的配置 + * @description 虽然叫主题,但是其实只是 less 的变量设置 + * @doc antd的主题设置 https://ant.design/docs/react/customize-theme-cn + * @doc umi 的 theme 配置 https://umijs.org/docs/api/config#theme + */ + // theme: { '@primary-color': '#1DA57A' } + /** + * @name moment 的国际化配置 + * @description 如果对国际化没有要求,打开之后能减少js的包大小 + * @doc https://umijs.org/docs/api/config#ignoremomentlocale + */ + ignoreMomentLocale: true, + /** + * @name 代理配置 + * @description 可以让你的本地服务器代理到你的服务器上,这样你就可以访问服务器的数据了 + * @see 要注意以下 代理只能在本地开发时使用,build 之后就无法使用了。 + * @doc 代理介绍 https://umijs.org/docs/guides/proxy + * @doc 代理配置 https://umijs.org/docs/api/config#proxy + */ + proxy: proxy[UMI_ENV as keyof typeof proxy], + /** + * @name 快速热更新配置 + * @description 一个不错的热更新组件,更新时可以保留 state + */ + fastRefresh: true, + //============== 以下都是max的插件配置 =============== + /** + * @name 数据流插件 + * @@doc https://umijs.org/docs/max/data-flow + */ + model: {}, + /** + * 一个全局的初始数据流,可以用它在插件之间共享数据 + * @description 可以用来存放一些全局的数据,比如用户信息,或者一些全局的状态,全局初始状态在整个 Umi 项目的最开始创建。 + * @doc https://umijs.org/docs/max/data-flow#%E5%85%A8%E5%B1%80%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81 + */ + initialState: {}, + /** + * @name layout 插件 + * @doc https://umijs.org/docs/max/layout-menu + */ + title: "Ant Design Pro", + layout: { + locale: true, + ...defaultSettings, + }, + /** + * @name moment2dayjs 插件 + * @description 将项目中的 moment 替换为 dayjs + * @doc https://umijs.org/docs/max/moment2dayjs + */ + moment2dayjs: { + preset: "antd", + plugins: ["duration"], + }, + /** + * @name 国际化插件 + * @doc https://umijs.org/docs/max/i18n + */ + locale: { + // default zh-CN + default: "zh-CN", + antd: true, + // default true, when it is true, will use `navigator.language` overwrite default + baseNavigator: true, + }, + /** + * @name antd 插件 + * @description 内置了 babel import 插件 + * @doc https://umijs.org/docs/max/antd#antd + */ + antd: { + appConfig: {}, + configProvider: { + theme: { + token: { + fontFamily: "AlibabaSans, sans-serif", + }, + }, + }, + }, + /** + * @name 网络请求配置 + * @description 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。 + * @doc https://umijs.org/docs/max/request + */ + request: {}, + /** + * @name 权限插件 + * @description 基于 initialState 的权限插件,必须先打开 initialState + * @doc https://umijs.org/docs/max/access + */ + access: {}, + /** + * @name 中额外的 script + * @description 配置 中额外的 script + */ + headScripts: [ + // 解决首次加载时白屏的问题 + { src: join(PUBLIC_PATH, "scripts/loading.js"), async: true }, + ], + //================ pro 插件配置 ================= + presets: ["umi-presets-pro"], + /** + * @name openAPI 插件的配置 + * @description 基于 openapi 的规范生成serve 和mock,能减少很多样板代码 + * @doc https://pro.ant.design/zh-cn/docs/openapi/ + */ + openAPI: [ + { + requestLibPath: "import { request } from '@umijs/max'", + // 或者使用在线的版本 + // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" + schemaPath: join(__dirname, "oneapi.json"), + mock: false, + }, + { + requestLibPath: "import { request } from '@umijs/max'", + schemaPath: + "https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json", + projectName: "swagger", + }, + ], + mock: { + include: ["mock/**/*", "src/pages/**/_mock.ts"], + }, + utoopack: {}, + requestRecord: {}, + exportStatic: {}, + define: { + "process.env.CI": process.env.CI, + }, +}); diff --git a/web/config/defaultSettings.ts b/web/config/defaultSettings.ts new file mode 100644 index 0000000..6710cad --- /dev/null +++ b/web/config/defaultSettings.ts @@ -0,0 +1,28 @@ +import type { ProLayoutProps } from '@ant-design/pro-components'; + +/** + * @name + */ +const Settings: ProLayoutProps & { + pwa?: boolean; + logo?: string; +} = { + navTheme: 'light', + // 拂晓蓝 + colorPrimary: '#1890ff', + layout: 'mix', + contentWidth: 'Fluid', + fixedHeader: false, + fixSiderbar: true, + colorWeak: false, + title: 'Ant Design Pro', + pwa: true, + logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', + iconfontUrl: '', + token: { + // 参见ts声明,demo 见文档,通过token 修改样式 + //https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F + }, +}; + +export default Settings; diff --git a/web/config/oneapi.json b/web/config/oneapi.json new file mode 100644 index 0000000..c77d988 --- /dev/null +++ b/web/config/oneapi.json @@ -0,0 +1,593 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Ant Design Pro", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8000/" + }, + { + "url": "https://localhost:8000/" + } + ], + "paths": { + "/api/currentUser": { + "get": { + "tags": ["api"], + "description": "获取当前的用户", + "operationId": "currentUser", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentUser" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/api/login/captcha": { + "post": { + "description": "发送验证码", + "operationId": "getFakeCaptcha", + "tags": ["login"], + "parameters": [ + { + "name": "phone", + "in": "query", + "description": "手机号", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FakeCaptcha" + } + } + } + } + } + } + }, + "/api/login/outLogin": { + "post": { + "description": "登录接口", + "operationId": "outLogin", + "tags": ["login"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/api/login/account": { + "post": { + "tags": ["login"], + "description": "登录接口", + "operationId": "login", + "requestBody": { + "description": "登录系统", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginParams" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResult" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "x-swagger-router-controller": "api" + }, + "/api/notices": { + "summary": "getNotices", + "description": "NoticeIconItem", + "get": { + "tags": ["api"], + "operationId": "getNotices", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NoticeIconList" + } + } + } + } + } + } + }, + "/api/rule": { + "get": { + "tags": ["rule"], + "description": "获取规则列表", + "operationId": "rule", + "parameters": [ + { + "name": "current", + "in": "query", + "description": "当前的页码", + "schema": { + "type": "number" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "页面的容量", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleList" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "post": { + "tags": ["rule"], + "description": "新建规则", + "operationId": "addRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "put": { + "tags": ["rule"], + "description": "新建规则", + "operationId": "updateRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": ["rule"], + "description": "删除规则", + "operationId": "removeRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/swagger": { + "x-swagger-pipe": "swagger_raw" + } + }, + "components": { + "schemas": { + "CurrentUser": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "userid": { + "type": "string" + }, + "email": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "title": { + "type": "string" + }, + "group": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "label": { + "type": "string" + } + } + } + }, + "notifyCount": { + "type": "integer", + "format": "int32" + }, + "unreadCount": { + "type": "integer", + "format": "int32" + }, + "country": { + "type": "string" + }, + "access": { + "type": "string" + }, + "geographic": { + "type": "object", + "properties": { + "province": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + } + } + }, + "city": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + } + } + } + } + }, + "address": { + "type": "string" + }, + "phone": { + "type": "string" + } + } + }, + "LoginResult": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "currentAuthority": { + "type": "string" + } + } + }, + "PageParams": { + "type": "object", + "properties": { + "current": { + "type": "number" + }, + "pageSize": { + "type": "number" + } + } + }, + "RuleListItem": { + "type": "object", + "properties": { + "key": { + "type": "integer", + "format": "int32" + }, + "disabled": { + "type": "boolean" + }, + "href": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "callNo": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "integer", + "format": "int32" + }, + "updatedAt": { + "type": "string", + "format": "datetime" + }, + "createdAt": { + "type": "string", + "format": "datetime" + }, + "progress": { + "type": "integer", + "format": "int32" + } + } + }, + "RuleList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RuleListItem" + } + }, + "total": { + "type": "integer", + "description": "列表的内容总数", + "format": "int32" + }, + "success": { + "type": "boolean" + } + } + }, + "FakeCaptcha": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + } + } + }, + "LoginParams": { + "type": "object", + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "autoLogin": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "ErrorResponse": { + "required": ["errorCode"], + "type": "object", + "properties": { + "errorCode": { + "type": "string", + "description": "业务约定的错误码" + }, + "errorMessage": { + "type": "string", + "description": "业务上的错误信息" + }, + "success": { + "type": "boolean", + "description": "业务上的请求是否成功" + } + } + }, + "NoticeIconList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NoticeIconItem" + } + }, + "total": { + "type": "integer", + "description": "列表的内容总数", + "format": "int32" + }, + "success": { + "type": "boolean" + } + } + }, + "NoticeIconItemType": { + "title": "NoticeIconItemType", + "description": "已读未读列表的枚举", + "type": "string", + "properties": {}, + "enum": ["notification", "message", "event"] + }, + "NoticeIconItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "extra": { + "type": "string", + "format": "any" + }, + "key": { "type": "string" }, + "read": { + "type": "boolean" + }, + "avatar": { + "type": "string" + }, + "title": { + "type": "string" + }, + "status": { + "type": "string" + }, + "datetime": { + "type": "string", + "format": "date" + }, + "description": { + "type": "string" + }, + "type": { + "extensions": { + "x-is-enum": true + }, + "$ref": "#/components/schemas/NoticeIconItemType" + } + } + } + } + } +} diff --git a/web/config/proxy.ts b/web/config/proxy.ts new file mode 100644 index 0000000..c7ddc88 --- /dev/null +++ b/web/config/proxy.ts @@ -0,0 +1,23 @@ +/** + * @name 代理的配置 + * @see 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 + * ------------------------------- + * The agent cannot take effect in the production environment + * so there is no configuration of the production environment + * For details, please see + * https://pro.ant.design/docs/deploy + * + * @doc https://umijs.org/docs/guides/proxy + */ +export default { + /** + * @name 详细的代理配置 + * @doc https://github.com/chimurai/http-proxy-middleware + */ + dev: { + "/v1/": { + target: "http://localhost:8000", + changeOrigin: true, + }, + }, +}; diff --git a/web/config/routes.ts b/web/config/routes.ts new file mode 100644 index 0000000..c8fbf91 --- /dev/null +++ b/web/config/routes.ts @@ -0,0 +1,47 @@ +/** + * @name umi 的路由配置 + * @description 只支持 path,component,routes,redirect,wrappers,name,icon 的配置 + * @param path path 只支持两种占位符配置,第一种是动态参数 :id 的形式,第二种是 * 通配符,通配符只能出现路由字符串的最后。 + * @param component 配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 src/pages 开始找起。 + * @param routes 配置子路由,通常在需要为多个路径增加 layout 组件时使用。 + * @param redirect 配置路由跳转 + * @param wrappers 配置路由组件的包装组件,通过包装组件可以为当前的路由组件组合进更多的功能。 比如,可以用于路由级别的权限校验 + * @param name 配置路由的标题,默认读取国际化文件 menu.ts 中 menu.xxxx 的值,如配置 name 为 login,则读取 menu.ts 中 menu.login 的取值作为标题 + * @param icon 配置路由的图标,取值参考 https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 则取值应为 user 或者 User + * @doc https://umijs.org/docs/guides/routes + */ +export default [ + { + path: "/user", + layout: false, + routes: [ + { + name: "login", + path: "/user/login", + component: "./user/login", + }, + ], + }, + { + path: "/welcome", + name: "welcome", + icon: "smile", + component: "./Welcome", + }, + { + name: "admin", + icon: "crown", + path: "/admins", + access: "canAdmin", + component: "./admins", + }, + { + path: "/", + redirect: "/welcome", + }, + { + component: "404", + layout: false, + path: "./*", + }, +]; diff --git a/web/jest.config.ts b/web/jest.config.ts new file mode 100644 index 0000000..99051c4 --- /dev/null +++ b/web/jest.config.ts @@ -0,0 +1,21 @@ +import { configUmiAlias, createConfig } from '@umijs/max/test'; + +export default async (): Promise => { + const config = await configUmiAlias({ + ...createConfig({ + target: 'browser', + }), + }); + return { + ...config, + testEnvironmentOptions: { + ...(config?.testEnvironmentOptions || {}), + url: 'http://localhost:8000', + }, + setupFiles: [...(config.setupFiles || []), './tests/setupTests.jsx'], + globals: { + ...config.globals, + localStorage: null, + }, + }; +}; diff --git a/web/mock/listTableList.ts b/web/mock/listTableList.ts new file mode 100644 index 0000000..dd88bf9 --- /dev/null +++ b/web/mock/listTableList.ts @@ -0,0 +1,187 @@ +import { parse } from 'node:url'; +import dayjs from 'dayjs'; +import type { Request, Response } from 'express'; + +// mock tableListDataSource +const genList = (current: number, pageSize: number) => { + const tableListDataSource: API.RuleListItem[] = []; + + for (let i = 0; i < pageSize; i += 1) { + const index = (current - 1) * 10 + i; + tableListDataSource.push({ + key: index, + disabled: i % 6 === 0, + href: 'https://ant.design', + avatar: [ + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + ][i % 2], + name: `TradeCode ${index}`, + owner: '曲丽丽', + desc: '这是一段描述', + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 4, + updatedAt: dayjs().format('YYYY-MM-DD'), + createdAt: dayjs().format('YYYY-MM-DD'), + progress: Math.ceil(Math.random() * 100), + }); + } + tableListDataSource.reverse(); + return tableListDataSource; +}; + +let tableListDataSource = genList(1, 100); + +function getRule(req: Request, res: Response, u: string) { + let realUrl = u; + if ( + !realUrl || + Object.prototype.toString.call(realUrl) !== '[object String]' + ) { + realUrl = req.url; + } + const { current = 1, pageSize = 10 } = req.query; + const params = parse(realUrl, true).query as unknown as API.PageParams & + API.RuleListItem & { + sorter: any; + filter: any; + }; + + let dataSource = [...tableListDataSource].slice( + ((current as number) - 1) * (pageSize as number), + (current as number) * (pageSize as number), + ); + if (params.sorter) { + const sorter = JSON.parse(params.sorter); + dataSource = dataSource.sort((prev, next) => { + let sortNumber = 0; + (Object.keys(sorter) as Array).forEach((key) => { + const nextSort = next?.[key] as number; + const preSort = prev?.[key] as number; + if (sorter[key] === 'descend') { + if (preSort - nextSort > 0) { + sortNumber += -1; + } else { + sortNumber += 1; + } + return; + } + if (preSort - nextSort > 0) { + sortNumber += 1; + } else { + sortNumber += -1; + } + }); + return sortNumber; + }); + } + if (params.filter) { + const filter = JSON.parse(params.filter as any) as { + [key: string]: string[]; + }; + if (Object.keys(filter).length > 0) { + dataSource = dataSource.filter((item) => { + return (Object.keys(filter) as Array).some( + (key) => { + if (!filter[key]) { + return true; + } + if (filter[key].includes(`${item[key]}`)) { + return true; + } + return false; + }, + ); + }); + } + } + + if (params.name) { + dataSource = dataSource.filter((data) => + data?.name?.includes(params.name || ''), + ); + } + const result = { + data: dataSource, + total: tableListDataSource.length, + success: true, + pageSize, + current: parseInt(`${params.current}`, 10) || 1, + }; + + return res.json(result); +} + +function postRule(req: Request, res: Response, u: string, b: Request) { + let realUrl = u; + if ( + !realUrl || + Object.prototype.toString.call(realUrl) !== '[object String]' + ) { + realUrl = req.url; + } + + const body = b?.body || req.body; + const { method, name, desc, key } = body; + + switch (method) { + case 'delete': + tableListDataSource = tableListDataSource.filter( + (item) => key.indexOf(item.key) === -1, + ); + break; + case 'post': + (() => { + const i = Math.ceil(Math.random() * 10000); + const newRule: API.RuleListItem = { + key: tableListDataSource.length, + href: 'https://ant.design', + avatar: [ + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + ][i % 2], + name, + owner: '曲丽丽', + desc, + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 2, + updatedAt: dayjs().format('YYYY-MM-DD'), + createdAt: dayjs().format('YYYY-MM-DD'), + progress: Math.ceil(Math.random() * 100), + }; + tableListDataSource.unshift(newRule); + return res.json(newRule); + })(); + return; + + case 'update': + (() => { + let newRule = {}; + tableListDataSource = tableListDataSource.map((item) => { + if (item.key === key) { + newRule = { ...item, desc, name }; + return { ...item, desc, name }; + } + return item; + }); + return res.json(newRule); + })(); + return; + default: + break; + } + + const result = { + list: tableListDataSource, + pagination: { + total: tableListDataSource.length, + }, + }; + + res.json(result); +} + +export default { + 'GET /api/rule': getRule, + 'POST /api/rule': postRule, +}; diff --git a/web/mock/monitor.mock.ts b/web/mock/monitor.mock.ts new file mode 100644 index 0000000..dcd1b17 --- /dev/null +++ b/web/mock/monitor.mock.ts @@ -0,0 +1,14 @@ +import type { Request, Response } from 'express'; +import mockjs from 'mockjs'; + +const getTags = (_: Request, res: Response) => { + return res.json({ + data: mockjs.mock({ + 'list|100': [{ name: '@city', 'value|1-100': 150, 'type|0-2': 1 }], + }), + }); +}; + +export default { + 'GET /api/tags': getTags, +}; diff --git a/web/mock/notices.ts b/web/mock/notices.ts new file mode 100644 index 0000000..d896311 --- /dev/null +++ b/web/mock/notices.ts @@ -0,0 +1,117 @@ +import type { Request, Response } from 'express'; + +const getNotices = (_req: Request, res: Response) => { + res.json({ + data: [ + { + id: '000000001', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/MSbDR4FR2MUAAAAAAAAAAAAAFl94AQBr', + title: '你收到了 14 份新周报', + datetime: '2017-08-09', + type: 'notification', + }, + { + id: '000000002', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/hX-PTavYIq4AAAAAAAAAAAAAFl94AQBr', + title: '你推荐的 曲妮妮 已通过第三轮面试', + datetime: '2017-08-08', + type: 'notification', + }, + { + id: '000000003', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/jHX5R5l3QjQAAAAAAAAAAAAAFl94AQBr', + title: '这种模板可以区分多种通知类型', + datetime: '2017-08-07', + read: true, + type: 'notification', + }, + { + id: '000000004', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/Wr4mQqx6jfwAAAAAAAAAAAAAFl94AQBr', + title: '左侧图标用于区分不同的类型', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000005', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/Mzj_TbcWUj4AAAAAAAAAAAAAFl94AQBr', + title: '内容不要超过两行字,超出时自动截断', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000006', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/eXLzRbPqQE4AAAAAAAAAAAAAFl94AQBr', + title: '曲丽丽 评论了你', + description: '描述信息描述信息描述信息', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000007', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/w5mRQY2AmEEAAAAAAAAAAAAAFl94AQBr', + title: '朱偏右 回复了你', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000008', + avatar: + 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/wPadR5M9918AAAAAAAAAAAAAFl94AQBr', + title: '标题', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000009', + title: '任务名称', + description: '任务需要在 2017-01-12 20:00 前启动', + extra: '未开始', + status: 'todo', + type: 'event', + }, + { + id: '000000010', + title: '第三方紧急代码变更', + description: + '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '马上到期', + status: 'urgent', + type: 'event', + }, + { + id: '000000011', + title: '信息安全考试', + description: '指派竹尔于 2017-01-09 前完成更新并发布', + extra: '已耗时 8 天', + status: 'doing', + type: 'event', + }, + { + id: '000000012', + title: 'ABCD 版本发布', + description: + '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '进行中', + status: 'processing', + type: 'event', + }, + ], + }); +}; + +export default { + 'GET /api/notices': getNotices, +}; diff --git a/web/mock/requestRecord.mock.js b/web/mock/requestRecord.mock.js new file mode 100644 index 0000000..7c8f0de --- /dev/null +++ b/web/mock/requestRecord.mock.js @@ -0,0 +1,345 @@ +module.exports = { + 'GET /api/currentUser': { + data: { + name: 'Serati Ma', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png', + userid: '00000001', + email: 'antdesign@alipay.com', + signature: '海纳百川,有容乃大', + title: '交互专家', + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED', + tags: [ + { key: '0', label: '很有想法的' }, + { key: '1', label: '专注设计' }, + { key: '2', label: '辣~' }, + { key: '3', label: '大长腿' }, + { key: '4', label: '川妹子' }, + { key: '5', label: '海纳百川' }, + ], + notifyCount: 12, + unreadCount: 11, + country: 'China', + geographic: { + province: { label: '浙江省', key: '330000' }, + city: { label: '杭州市', key: '330100' }, + }, + address: '西湖区工专路 77 号', + phone: '0752-268888888', + }, + }, + 'GET /api/rule': { + data: [ + { + key: 99, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 99', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 503, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 81, + }, + { + key: 98, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 98', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 164, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 12, + }, + { + key: 97, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 97', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 174, + status: '1', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 81, + }, + { + key: 96, + disabled: true, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 96', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 914, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 7, + }, + { + key: 95, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 95', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 698, + status: '2', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 82, + }, + { + key: 94, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 94', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 488, + status: '1', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 14, + }, + { + key: 93, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 93', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 580, + status: '2', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 77, + }, + { + key: 92, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 92', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 244, + status: '3', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 58, + }, + { + key: 91, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 91', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 959, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 66, + }, + { + key: 90, + disabled: true, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 90', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 958, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 72, + }, + { + key: 89, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 89', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 301, + status: '2', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 2, + }, + { + key: 88, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 88', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 277, + status: '1', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 12, + }, + { + key: 87, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 87', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 810, + status: '1', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 82, + }, + { + key: 86, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 86', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 780, + status: '3', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 22, + }, + { + key: 85, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 85', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 705, + status: '3', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 12, + }, + { + key: 84, + disabled: true, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 84', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 203, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 79, + }, + { + key: 83, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 83', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 491, + status: '2', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 59, + }, + { + key: 82, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 82', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 73, + status: '0', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 100, + }, + { + key: 81, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + name: 'TradeCode 81', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 406, + status: '3', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 61, + }, + { + key: 80, + disabled: false, + href: 'https://ant.design', + avatar: + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + name: 'TradeCode 80', + owner: '曲丽丽', + desc: '这是一段描述', + callNo: 112, + status: '2', + updatedAt: '2022-12-06T05:00:57.040Z', + createdAt: '2022-12-06T05:00:57.040Z', + progress: 20, + }, + ], + total: 100, + success: true, + pageSize: 20, + current: 1, + }, + 'POST /api/login/outLogin': { data: {}, success: true }, + 'POST /api/login/account': { + status: 'ok', + type: 'account', + currentAuthority: 'admin', + }, +}; diff --git a/web/mock/route.ts b/web/mock/route.ts new file mode 100644 index 0000000..418d10f --- /dev/null +++ b/web/mock/route.ts @@ -0,0 +1,5 @@ +export default { + '/api/auth_routes': { + '/form/advanced-form': { authority: ['admin', 'user'] }, + }, +}; diff --git a/web/mock/user.ts b/web/mock/user.ts new file mode 100644 index 0000000..06125bf --- /dev/null +++ b/web/mock/user.ts @@ -0,0 +1,205 @@ +import type { Request, Response } from 'express'; + +const waitTime = (time: number = 100) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, time); + }); +}; + +async function getFakeCaptcha(_req: Request, res: Response) { + await waitTime(2000); + return res.json('captcha-xxx'); +} + +const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env; + +/** + * 当前用户的权限,如果为空代表没登录 + * current user access, if is '', user need login + * 如果是 pro 的预览,默认是有权限的 + */ +let access = + ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ? 'admin' : ''; + +const getAccess = () => { + return access; +}; + +// 代码中会兼容本地 service mock 以及部署站点的静态数据 +export default { + // 支持值为 Object 和 Array + 'GET /api/currentUser': (_req: Request, res: Response) => { + if (!getAccess()) { + res.status(401).send({ + data: { + isLogin: false, + }, + errorCode: '401', + errorMessage: '请先登录!', + success: true, + }); + return; + } + res.send({ + success: true, + data: { + name: 'Serati Ma', + avatar: + 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', + userid: '00000001', + email: 'antdesign@alipay.com', + signature: '海纳百川,有容乃大', + title: '交互专家', + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED', + tags: [ + { + key: '0', + label: '很有想法的', + }, + { + key: '1', + label: '专注设计', + }, + { + key: '2', + label: '辣~', + }, + { + key: '3', + label: '大长腿', + }, + { + key: '4', + label: '川妹子', + }, + { + key: '5', + label: '海纳百川', + }, + ], + notifyCount: 12, + unreadCount: 11, + country: 'China', + access: getAccess(), + geographic: { + province: { + label: '浙江省', + key: '330000', + }, + city: { + label: '杭州市', + key: '330100', + }, + }, + address: '西湖区工专路 77 号', + phone: '0752-268888888', + }, + }); + }, + // GET POST 可省略 + 'GET /api/users': [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + }, + ], + 'POST /api/login/account': async (req: Request, res: Response) => { + const { password, username, type } = req.body; + await waitTime(2000); + if (password === 'ant.design' && username === 'admin') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin', + }); + access = 'admin'; + return; + } + if (password === 'ant.design' && username === 'user') { + res.send({ + status: 'ok', + type, + currentAuthority: 'user', + }); + access = 'user'; + return; + } + if (type === 'mobile') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin', + }); + access = 'admin'; + return; + } + + res.send({ + status: 'error', + type, + currentAuthority: 'guest', + }); + access = 'guest'; + }, + 'POST /api/login/outLogin': (_req: Request, res: Response) => { + access = ''; + res.send({ data: {}, success: true }); + }, + 'POST /api/register': (_req: Request, res: Response) => { + res.send({ status: 'ok', currentAuthority: 'user', success: true }); + }, + 'GET /api/500': (_req: Request, res: Response) => { + res.status(500).send({ + timestamp: 1513932555104, + status: 500, + error: 'error', + message: 'error', + path: '/base/category/list', + }); + }, + 'GET /api/404': (_req: Request, res: Response) => { + res.status(404).send({ + timestamp: 1513932643431, + status: 404, + error: 'Not Found', + message: 'No message available', + path: '/base/category/list/2121212', + }); + }, + 'GET /api/403': (_req: Request, res: Response) => { + res.status(403).send({ + timestamp: 1513932555104, + status: 403, + error: 'Forbidden', + message: 'Forbidden', + path: '/base/category/list', + }); + }, + 'GET /api/401': (_req: Request, res: Response) => { + res.status(401).send({ + timestamp: 1513932555104, + status: 401, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list', + }); + }, + + 'GET /api/login/captcha': getFakeCaptcha, +}; diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..a0450ab --- /dev/null +++ b/web/package.json @@ -0,0 +1,97 @@ +{ + "name": "ant-design-pro", + "version": "6.0.0", + "private": true, + "description": "An out-of-box UI solution for enterprise applications", + "repository": "git@github.com:ant-design/ant-design-pro.git", + "scripts": { + "analyze": "cross-env ANALYZE=1 max build", + "build": "max build", + "deploy": "npm run build && npm run gh-pages", + "dev": "npm run start:dev", + "gh-pages": "gh-pages -d dist", + "i18n-remove": "pro i18n-remove --locale=zh-CN --write", + "postinstall": "max setup", + "jest": "jest", + "lint": "npm run biome:lint && npm run tsc", + "lint-staged": "lint-staged", + "biome:lint": "npx @biomejs/biome lint", + "openapi": "max openapi", + "prepare": "husky", + "preview": "npm run build && max preview --port 8000", + "record": "cross-env NODE_ENV=development UMI_ENV=test max record --scene=login", + "serve": "umi-serve", + "start": "cross-env UMI_ENV=dev max dev", + "start:dev": "cross-env UMI_ENV=dev PORT=3000 MOCK=none max dev", + "start:no-mock": "cross-env MOCK=none max dev", + "start:pre": "cross-env UMI_ENV=pre MOCK=none max dev", + "start:test": "cross-env UMI_ENV=test MOCK=none max dev", + "test": "jest", + "test:coverage": "npm run jest -- --coverage", + "test:update": "npm run jest -- -u", + "tsc": "tsc --noEmit" + }, + "browserslist": ["defaults"], + "dependencies": { + "@ant-design/icons": "^6.1.0", + "@ant-design/pro-components": "^2.8.9", + "antd": "^6.0.0", + "antd-style": "^3.7.0", + "classnames": "^2.5.1", + "dayjs": "^1.11.13", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@ant-design/pro-cli": "^3.3.0", + "@commitlint/cli": "^20.1.0", + "@commitlint/config-conventional": "^20.0.0", + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.3.0", + "@types/express": "^5.0.3", + "@types/jest": "^30.0.0", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@types/react-helmet": "^6.1.11", + "@umijs/lint": "^4.6.1", + "@umijs/max": "^4.6.2", + "cross-env": "^10.0.0", + "express": "^5.2.0", + "gh-pages": "^6.1.1", + "husky": "^9.1.7", + "jest": "^30.0.4", + "jest-environment-jsdom": "^30.0.5", + "lint-staged": "^16.1.2", + "mockjs": "^1.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.6.3", + "umi-presets-pro": "^2.0.3", + "umi-serve": "^1.9.11", + "@biomejs/biome": "^2.1.1", + "@types/node": "^24.0.13" + }, + "engines": { + "node": ">=20.0.0" + }, + "create-umi": { + "ignoreScript": ["docker*", "functions*", "site", "generateMock"], + "ignoreDependencies": ["netlify*", "serverless"], + "ignore": [ + ".dockerignore", + ".git", + ".github", + ".gitpod.yml", + "CODE_OF_CONDUCT.md", + "Dockerfile", + "Dockerfile.*", + "lambda", + "LICENSE", + "netlify.toml", + "README.*.md", + "azure-pipelines.yml", + "docker", + "CNAME", + "create-umi" + ] + } +} diff --git a/web/public/CNAME b/web/public/CNAME new file mode 100644 index 0000000..30c2d4d --- /dev/null +++ b/web/public/CNAME @@ -0,0 +1 @@ +preview.pro.ant.design \ No newline at end of file diff --git a/web/public/favicon.ico b/web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e2e93252988b5bed120ddeb168eb577bf0caa881 GIT binary patch literal 4286 zcmeHLO(?8k6#ga#Gs=ufvobTd=q@y~nOLdYlqL%nQY4WqC`)z}3y~cqOAAF4VkQd~ z^3$wrC}~D1l%!eMp!|gA&U5sN?~b{2>)yNg-s#Lc-+9k_p7Y<=XqqYcDJs(Vt%dBG z=F~Lpdy*pd!Y zozZT}udJ-#| zqiAVq0sT@kAMMobbULxOw+F6{j*egO8CQ?TgTuo^+}_@zrlv;l$*-)e#PRVl?(Xgo zi9`?zg>ZFsh0DuJ)Ya9!von7LPN@OfP9IfH_4tet&&I~a#O{TK1<3*LO-xJ( zZ*Fc5%v&m4#Z&mZySs8{XJ-fV^Yh@{p`ju8d_J)w6+U%`!(qAC+uJK~qg_o+O|QC` zTVg0Y{jSHqzP^^&G0t4^cwF+$`egj?@9$AtTMLuPB>7!lUKY8&zP?xd=H_PM(U;HS ztNi!(_oJes0<5X6tu4{BxVR{FO)_x3UauFkv$I%RTSHe@7dAIHF+4mhc?|>t(!XbCXVQZk z8yje7Xh2R*&WCwdw&?N4$H!4$Uyq)i9_;V$3;y)^-LKhmkv{Z#(CP^-7Wn# zI5-H>z`y`nTU%u=f7Tbh-mg5fPT0G8`Wx6^vD1(>-r0;AFlyjWYC!!D@UQlt)%}4^ literal 0 HcmV?d00001 diff --git a/web/public/icons/icon-128x128.png b/web/public/icons/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..48d0e2339a60a637b94319c65e8654289b4f4b6c GIT binary patch literal 1329 zcmV-11C0002qP)t-s01zMl z|Nj6D8~_Fu01Fxg6ePmN$p8o!Wo~x>2^n*Hg!uURG(b#MUupdO{0J2!4IC;FATIs> z{@dN(0umtr1r+b_@!;a*CNn?_87S=S?pR`MN>yMYFg?=M*UQe)wYk2qw7Hs~re<$= zUubdX=<2(_!=9w6l9``_ijrw^dn`Fc6(TV7_4V=c^R2SBrmV4+ouiMHoQsl~euj;D zf{I&ZZXPQ+87DQ^+ugv!$3;(CLQPmWL{HY)+rGlaqNuHRe}`^&fKXdyK1x+FK1#;P z&4`be_4fDTmuWjt2mKnbI+d3dfa z_PK3Vs;zn;Ot~u#==o*X;a^nmOa{(_o(tmupuw*`!> z#lUp|BbBD0;J$!S0To9DO4Z9XkCjq#?=s{WNE{XLCFmLibLLfxLm3nt7Wj-&k{L;X zo_Y$L6(Ax^@lhJo2uNHK09we3_>jt`DV`HX8L^}WDJO|ULbS4T1b_}iycq`oGqNH4 zQJi@^@H`%ly#;k8%FIH(J#9^VH>(ITJX3)9M7)?mVD;pNM){2bV!rABC{yFeZXJ$q ztx`Yw*~Rj#FGR_Att-g zD?cOlXM^rD8S|s+a(LB7MePP8cKc zywqQW@o0gm8Qu`-)UW-9#K*uQ5WQT5&CGnc%phPyF4p1{wj=@#5xikX3uI#(QrZ2A z66>Nxz+a;r*Km#iEGXxR4BFJu%9#^UG{?XqFlA~7sH!J&2X_C6*P7#50#^tYfm`)p zW2Pupno-5;QoKQ)pCj;SS_MKc4Ai#W7h-YyLi$8b7l@8b3KjwX8wCk}6<4mh7hj6_ z@bnBUa)|InAVBSV)+C{3Cf$?e`b2@nQysp0$(swOoN^Eg(SO9p-Q1JJAAwzQCMaKm&bGV`U^9&pp0Gf^+nkRf5 zTo3@>xi{%p{gIpTF5iJBic@aIws^IC=-v{M~W@Y%aj8G0o!r2b|HdROb8D$LP+n;FWCW`~3a=G(k;6PFes57kh(>00a~S6Cwx} zCE()Z^7Hf|E zp{K0H$jr97ziM-QXK;BCA1!ozgl>0$_4f8XNmSCn^FkCmKwfQVshbU{p46e2L| z?Ct65?BnI;*4f+4&(glZ#fXoVgo~3^UusNOVjC$ov9`LWtg%K>TsK2c$;{8e#mKwA z!>qBksjjnFVr-b6q?4MUQCw!>t&JT300tCEL_t(|+U?tESK2@nfZ>~&tE5s!683!u zK~Xjr+;FLD`~QDWsaSMof{9Cdrsv$}Q$GacB{NB8tUw4Mgb+dqA%qY@2qA(L2bqdsgXsNTkuvsd$l2J=n5?~ND zV51VpX8=z3{QjGMB}&;~4lO{w(%Zazp$0@daWIEhfP~dcYQd#z&@Au`02`W0K*FSZ zfqww-)R9s!Ht2yOKmf3z60nW%2IP#}oH2Xl0XAm~+{S+rP&t$X9^nbbm-x&1;@!yj zY%9B7sWA>ZWO1jKtCah(e))TD=Eenv9so{D4rn_thqYd2VK|ELzaOufx!t$^NZw>p z+Iyj>U-gQu^kN;GPyD#d{Hh5IJ3uJYc+Z77Ufo$Ggo+WA3Y*@1Ky13)LZP31QSeOBPQ+XWH1FRE< znBBKzO$T4zWLDa@R>>EuJj^qYQEmht0qwfj(!SqQ@iKSEQ|m2>2OGl+_^GUFJOcJ= zXWHkFZpC2%v9sp4{dDSJXp{It8QP8>kQnV+s>T(A1*ey{eEoDWoB-?=l!qbE1M&?^ zlg>TQVZNQW0vG^>5+Gs?WoT;w-lorADbq%mw`k7}=L`%i*#i$2a3L12&mCI9?2mZ} z0W6}7?qr1p3pjZ?4xKwIs2_Fw@&LQuwzS(*uz)OwIWgMMHdb!T{tPE4SL`S{H8xBn!v4)5iQu&kynG zu&g>v%A749U2|<^9&fVG1>_^~CFZ7LP5t_J?7+%^=uNif%+;?)oeFwB$`&F5UWnO^ z@}M}gKew%NvbE6ZWlDEPmWMOGGN93O87@!W;veOx{0)tnve;1G63u~Z#6xV7>iY035`Xj%Y> z^Q5IJ+!Y6p_dlYRYQ(^}0Dwm;s0$Yi48Tdj3g$4vO$-3uKeU2KKGd0O0O0VXbm7s4;+l9&n%p_`cvI z?LB&meH%ahXIS9}0Jn2n$9YS(u{W#$gO9RPz0KE#GlYO}vMs$dg#n^%CpUU*6%xDq zjs0(lqaT-@s*4=qi*zHU+H4m-VgiXywKHFAtzxV0RWJzsovKI0FJxD0TBWR9R(cUae(Kj zsHF%%MItH28Xp(4*{bSm0T9Fm0Q3xia~uV&0pKeFz=jn7(rEx(_sVL}lf@aG=xQ21 z0F-Q4EcX2Td}n9x&+_W8>Dj@bW1Zc-_04UCC6!U}srDWLO4_FE!gBaD92g8{VR7ke zeM?AW92o=O(D2yXclnR)y=d4(E-o&bT05P*g06FjUtV6efBWI#2OS@uWaJd^OFd|4 zX;(M2f>E+f{F>2!?AX@%T}(mq>gp=@<7Y-5siUJ~-_R&H)yX)dzBXt+ zw3(irC-{#uAUx*V_rCAF0|y6(^qk`23R+NfVtI9aeo@&CE(t4VpY6XpJmUB8uHDiy zwv9=Ab9i`ka&k&{ODsM)GxBB9kG{dJ?Y|`SJP2xb|L_=>Cn3tZ=GbsG#NjrD{p8lZ+I*;#ZnN-&`)3V#iUD zMPI6J3dwTaR#efm@D7ZSx~Kc$)0fQLLZ9GgMwTwT5=zbJZ|@6AUcO3G4f|Pz+YOkF zhRS^y7A`o43kXqaS`P?+li?F^ab$DRnFBz%pmtx;FkotX)-fdI0SkIBo$3`kjGW}D zZoDeqLtS3Q2M@@N^6~Cb6R{D+s3aFqxA6=o*eHod92P`F`24wEin51>RC@xG+Cw7; zO)`T9mP{{KyOZ{F0<#_c5Bhd4GTu4*uXH<{{3_)6x4r)lr){`JohSKG%?$A}zhMc= zW|@O)q8WsJQ6EdzmKROG;U@_#(HhDuk8bo;Ho`*6l-2u9HLE*dOv$E=6gvnZLNCqP zprds6w}?9hZO+b`b-ggB&>$s;nRQSt|AE@)FA7Ls_I33&;P}~m=VyWbcR}f(OIN21 zGvpB_DYkJ<3MQsNhOEYodj;5({(pE0$4P!F$)xqVIwo83~69g=48RK+49na7Q(C zC7>Jw*DbzEje?QUe|LGt3nX|7Uz)%oP2zR&b4Op@R)(SMB<|5c3@$a63w&>G*}*

*C7T$?5!b= z&nPVm(<;~Sw_*kJlio|*qhI8#F?9y#@jvQ4Y?j2~r_a^)YoQ-co4WFOwF)i5mFnrV zp3rz^`K|nrI`guQ$X^%JuCI5qSS(}Tc|%+~o}P6dC={o1Q&<)3lnFnXE=l2Po$K4W zYZ0|2<3Cp|&)NE>;p=Muwg#BLXuboTJ(mwtjLbtdOE_A4n^}l29p9@>4vpS+t*^qG zb2Uo-W$@vKeR}iztf6tJTUh8=^kh_EBe^3f?1b(p_oBq&dpqW$pAyBB**bIt4BhwK zX02JE@mc}FExq0q+5_8B#EP&@;6-lx4t~)@$HBEBXnIqX0E$mhb$(} zt|vYUzekLn0SQ;Cd)J1 zXF3gv$u52+$>oQVvh7DxPpKeWD4yJgdWQQ`D#($Z=j%Df!iAxvR)-y7Ie5nI39+zG z4a3_4mE;SBh@MK8p%(n|yGj>Ao>j51ETLI#vuUt#g|%FDZG}&kbEb(|*9!RyL&U?| zvNnv+oEL_*R{Mw_;x+O`vNWUXL6>@M)sQr_lmlng7?sCaDH0YaGf%+R1ZM}9#$j$3 zi}N01^7uoRgvG74Fxi{415}={tg=gDHuqwR$1?9qlK<#~ zLG@an>_SlEY6+k8PD+S)C&NU7!~`$+Sin{JS2aLn_Jm#q|8H%OnLqt&n-f~C7KW9K z>QxTE1D!cV+(E>-8N#r>Aw98T*8=odDM_y2&?=ag7-=Rj&p%xvU zq=o{%T2@T(b@VqinV#`~IN4t3^z$HE=3~ZiDQ=xP6Gt)g;q1Wv2N&CBx=Ndw5 z6U*fS@;@VBF^MGsyag~+Eq&2UZ@5SG$!SM2ckBL!E1lBg>*t^{Lqn=cK^-Rhc#S(% zuAqbI(^+PqN#)t&5xr~v&*Y$qZ$3Yz)nRe`ZZcJUU8hd=)9$7 z6n-k7p||Esq}igp(IoxtD&_5A!OwcTvM3p-HHJGcVh|>N13O;!W%RXd{Y6@BEp1Jz zHCH!~H~lR%<3E0b>}>_dD6Ef8r_)LSp}O5L`DerkKk|Jc@n6*BmU&r@TKhG$-x=>`wv*Vj%M=6<7!P7~3+)?^D>AA~&^F+{mzBAMLh zuTiItS}IqcPpj-t;W15ahnBV9rHnrShN-@GCY+EyXV6Gass&4cM~^;F?z{3+SXKe7 zX8rBU7Fc!Kr5M!K@lDd)Bl)VMR)yb6;AHxpH?Q1Bx14XQy~`&ggyC$4u>az;q|C7G ziTI-A3y9BZbxP7rW4_G!ju{^(NOZstl}tvVR+j8_B`~)2cWn2~;amI9u@_9oSC+Xc z_+DcYbc7S~MIl7Fjk6qEWXDo6>n5U0O4P_k15Z^c%P@0?*Oaj8%BIU*uy|Vgi@eqH zPKZqrW$wXWQ9=QoQrY4VBCFzACRJhEv+U(FOmx1_uwVirtukLVbyF&%?xKU6D>Yot zj6ZW-1$@|ASwJlAu1;!K9!5uPdov-?7RK^;L%bs%6z9abcvP!i20^{1|g}`{&O=}R+#D;J+z#Fj(x6k%xY0!5_DrzSsTCn;pu^6 zIZV~_c4b?yxFutJZTc`BT4+(N21dx%Bxx5_=*+^Gl`PCmvS7QnNZUr>RqS>smtAo7 z%1fV4h6YI+Y2X$?ZuQmeFj!XWfPJxAc1<0;;3C|?V?=BITB{AnSkYW;+Vbas9ODwo zC?uf|l|KjLdt@iP*&!CGbh&OT1l3&s3RD|7knGOc{T%o)WLqmqSnTE5-M^OKN+8ct1C(XwQJJg%OozV)cJ^w# zVxbg~z7OMwn+eEPaBRR0KIDX14Kb^G-Strc8r6QmoINnF;F1;|U5n3%rdT9(U0dcP zI*}ZU>2wFp1u1KmK2cwSwk|=oZ8?l*@yIPBD3BPN(BINzFh#VAKBpVxZ71*JgwpWXLZfS%KkGa_tQn0bX5)h8 z6Q7LGdb=)NQ}a}>SD{8~!ga|bE*aS_Nxg_+ojhQ1{b@sVzaX)Z{rV-1%Qa*ioSy65 zb4ke$#&Mf>xuBg{&aCGNbhbOGbN4XT4?qQpRW^!2z;9eCH6fH7)+qpWe;n~*tCIq= z&w&jc@_tBWRiS3IyovPwt~fl#1Z-%o%T_B%)sO*FrOIkz-1r$#mr+&N2J06a?u1<~QB}EoR?wnU)c32Ew0(EP^w=K@< zM;7MeoWTwa-$09MwD#{-p5K@kGTM6q@*9`~NBz#snAQt$W%fZr`qk|A%IEM4|B(?x zOpx+g1-*Q?a%JHpKf|Cs>MCBj^^EmKDb?*U1(_uF({whek67oi^wL)^XH3=`&u$U^ z*K&AEIc$ISs)O2r7emK9XW_i^6Jxw-Ug6tIn{3gqAYG+j_U1<)>HovW7l7Z>STIh4 z7OH$pfQM^<6ZPN`%FY^PFKzq89tYsIi0BGroup 28 Copy 5Created with Sketch. \ No newline at end of file diff --git a/web/public/pro_icon.svg b/web/public/pro_icon.svg new file mode 100644 index 0000000..e075b78 --- /dev/null +++ b/web/public/pro_icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/web/public/scripts/loading.js b/web/public/scripts/loading.js new file mode 100644 index 0000000..a4fdb3d --- /dev/null +++ b/web/public/scripts/loading.js @@ -0,0 +1,202 @@ +/** + * loading 占位 + * 解决首次加载时白屏的问题 + */ +(function () { + const _root = document.querySelector('#root'); + if (_root && _root.innerHTML === '') { + _root.innerHTML = ` + + +

+
+
+ + + + + + +
+
+
+ 正在加载资源 +
+
+ 初次加载资源可能需要较多时间 请耐心等待 +
+
+ `; + } +})(); diff --git a/web/src/access.ts b/web/src/access.ts new file mode 100644 index 0000000..373d9fa --- /dev/null +++ b/web/src/access.ts @@ -0,0 +1,11 @@ +/** + * @see https://umijs.org/docs/max/access#access + * */ +export default function access( + initialState: { currentUser?: API.CurrentUser } | undefined, +) { + const { currentUser } = initialState ?? {}; + return { + canAdmin: currentUser && currentUser.access === 'admin', + }; +} diff --git a/web/src/app.tsx b/web/src/app.tsx new file mode 100644 index 0000000..2c1dd16 --- /dev/null +++ b/web/src/app.tsx @@ -0,0 +1,154 @@ +import { + AvatarDropdown, + AvatarName, + Footer, + Question, + SelectLang, +} from "@/components"; +import { createAdminService } from "@/services/index"; +import { Admin } from "@/services/kratos/admin/v1/index"; +import { LinkOutlined } from "@ant-design/icons"; +import type { Settings as LayoutSettings } from "@ant-design/pro-components"; +import { SettingDrawer } from "@ant-design/pro-components"; +import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max"; +import { history, Link } from "@umijs/max"; +import defaultSettings from "../config/defaultSettings"; +import { errorConfig } from "./requestErrorConfig"; + +const isDev = process.env.NODE_ENV === "development"; +const isDevOrTest = isDev || process.env.CI; +const loginPath = "/user/login"; + +const adminService = createAdminService(); + +/** + * @see https://umijs.org/docs/api/runtime-config#getinitialstate + * */ +export async function getInitialState(): Promise<{ + settings?: Partial; + currentUser?: API.CurrentUser; + loading?: boolean; + fetchUserInfo?: () => Promise; +}> { + const fetchUserInfo = async () => { + try { + return await adminService.Current({}); + } catch (error) { + history.push(loginPath); + } + return undefined; + }; + // 如果不是登录页面,执行 + const { location } = history; + if ( + ![loginPath, "/user/register", "/user/register-result"].includes( + location.pathname + ) + ) { + const currentUser = await fetchUserInfo(); + return { + fetchUserInfo, + currentUser, + settings: defaultSettings as Partial, + }; + } + return { + fetchUserInfo, + settings: defaultSettings as Partial, + }; +} + +// ProLayout 支持的api https://procomponents.ant.design/components/layout +export const layout: RunTimeLayoutConfig = ({ + initialState, + setInitialState, +}) => { + return { + actionsRender: () => [ + , + , + ], + avatarProps: { + src: initialState?.currentUser?.avatar, + title: , + render: (_, avatarChildren) => ( + {avatarChildren} + ), + }, + waterMarkProps: { + content: initialState?.currentUser?.name, + }, + footerRender: () =>