From b36b224beab86b76aabc83bd3e052ca4e89af81e Mon Sep 17 00:00:00 2001 From: icyleaf Date: Thu, 26 Sep 2024 07:26:06 +0000 Subject: [PATCH 1/2] feat(api): add edit, destroy build of app --- app/controllers/api/releases_controller.rb | 31 ++++++++++++++++++++++ app/models/release.rb | 6 ++--- app/serializers/release_serializer.rb | 2 +- config/routes.rb | 1 + 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 app/controllers/api/releases_controller.rb diff --git a/app/controllers/api/releases_controller.rb b/app/controllers/api/releases_controller.rb new file mode 100644 index 000000000..030d18103 --- /dev/null +++ b/app/controllers/api/releases_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class Api::ReleasesController < Api::BaseController + before_action :validate_user_token + before_action :set_release + + # UPDATE /releases/:id + def update + @release.update!(release_params) + render json: @release + end + + # DELETE /releases/:id + def destroy + @release.destroy + render json: { mesage: 'OK' } + end + + protected + + def set_release + @release = Release.find(params[:id]) + end + + def release_params + params.permit( + :release_version, :build_version, :release_type, :source, :branch, :git_commit, + :ci_url, :custom_fields, :changelog + ) + end +end diff --git a/app/models/release.rb b/app/models/release.rb index afdf67295..0545ec7ae 100644 --- a/app/models/release.rb +++ b/app/models/release.rb @@ -16,10 +16,10 @@ class Release < ApplicationRecord has_one :metadata, class_name: 'Metadatum', dependent: :destroy has_and_belongs_to_many :devices, dependent: :destroy - validates :file, presence: true + validates :file, presence: true, on: :create validate :bundle_id_matched, on: :create - validate :determine_file_exist - validate :determine_disk_space + validate :determine_file_exist, on: :create + validate :determine_disk_space, on: :create before_create :auto_release_version before_create :default_source diff --git a/app/serializers/release_serializer.rb b/app/serializers/release_serializer.rb index 1213e2280..f76ff419f 100644 --- a/app/serializers/release_serializer.rb +++ b/app/serializers/release_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ReleaseSerializer < ApplicationSerializer - attributes :version, :app_name, :bundle_id, :release_version, :build_version, + attributes :id, :version, :app_name, :bundle_id, :release_version, :build_version, :source, :branch, :git_commit, :ci_url, :size, :platform, :device_type, :icon_url, :install_url, :changelog, :text_changelog, :custom_fields, :created_at diff --git a/config/routes.rb b/config/routes.rb index 441136d1b..025c07b2e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -213,6 +213,7 @@ resources :collaborators, param: :user_id, except: %i[index new edit] end + resources :releases, only: %i[update destroy] resources :debug_files, except: %i[new edit create] do collection do From 1acd74c46bac8a23f4823d6f1268350ffad9e66e Mon Sep 17 00:00:00 2001 From: icyleaf Date: Thu, 26 Sep 2024 08:54:47 +0000 Subject: [PATCH 2/2] doc: update new api to swagger and bump api v1.4 --- config/locales/zealot/api.en.yml | 31 +++ config/locales/zealot/api.zh-CN.yml | 25 ++ lib/tasks/zealot/zealot.rake | 10 +- spec/api/apps_spec.rb | 4 +- spec/api/channels_spec.rb | 4 +- spec/api/collaborators_spec.rb | 4 +- spec/api/releases_spec.rb | 44 +++ spec/api/schemes_spec.rb | 4 +- spec/api/users_spec.rb | 4 +- spec/spec_helper.rb | 6 + spec/support/swagger/shared.rb | 16 ++ spec/swagger_helper.rb | 17 +- swagger/v1/swagger_en.json | 418 +++++++++++++++++++++------- swagger/v1/swagger_zh-CN.json | 418 +++++++++++++++++++++------- 14 files changed, 794 insertions(+), 211 deletions(-) create mode 100644 spec/api/releases_spec.rb diff --git a/config/locales/zealot/api.en.yml b/config/locales/zealot/api.en.yml index 2b8c4fae8..bfd0439a1 100644 --- a/config/locales/zealot/api.en.yml +++ b/config/locales/zealot/api.en.yml @@ -123,6 +123,17 @@ en: bundle_id: identifier valid check, set `*` skip (`bundle_id` for iOS, `package name` for Android) git_url: Git repository URL password: Enable password visit + release_options: + description: App's build metadata form data + properties: + build_version: Build version + release_version: Release version + source: the source of upload (default is `api`) + changelog: Change log, accept plain text or JSON formatted data + branch: a branch name from source control tool + git_commit: Git Commit SHA value + ci_url: the build url of a CI service + custom_fields: JSON formatted custom fields, icon only accepts fontawesome. collaborator_options: description: App's collaborator form data properties: @@ -144,6 +155,7 @@ en: file: Zip arichved file (dSYM or Proguard) release_version: Release version (requires if Android's Proguard file) build_version: Build version (requires if Android's Proguard file) + apps: default: tags: Apps @@ -185,6 +197,7 @@ en: destroy: title: Destroy an App description: Destroy an App all data by ID, include schemes, channel, builds, debug files and the other related resources. + schemes: default: tags: Schemes @@ -206,6 +219,7 @@ en: destroy: title: Destroy a scheme description: Destroy a scheme from the App + channels: default: tags: Channel @@ -227,6 +241,20 @@ en: destroy: title: Destroy a channel description: Destroy a scheme's channel + + releases: + default: + tags: Release + responses: + update: Update a build + destroy: Destroy build + update: + title: Update a build metedata + description: Update a build of app verison, custom_fileds, changelog etc + destroy: + title: Destroy a build + description: Destroy a app's build + collaborators: default: tags: Collaborators @@ -248,6 +276,7 @@ en: destroy: title: Remove a collaborator from an App description: Remove a collaborator from an App + debug_files: default: tags: Debug files @@ -285,6 +314,7 @@ en: destroy: title: Destroy a debug file description: Destroy a debug file ID and all data, include dSYM or Proguard files. + users: default: tags: Users @@ -321,6 +351,7 @@ en: unlock: title: Unlock a user description: Unlock a user to enable log in + version: default: tags: Version diff --git a/config/locales/zealot/api.zh-CN.yml b/config/locales/zealot/api.zh-CN.yml index 5232e7ea8..3aa23a6d6 100644 --- a/config/locales/zealot/api.zh-CN.yml +++ b/config/locales/zealot/api.zh-CN.yml @@ -120,6 +120,18 @@ zh-CN: bundle_id: 包名校验, 默认是 `*` 不做校验 (iOS 指的是 bundle_id,Android 指的是 package name) git_url: Git 仓库地址 password: 密码访问 + release_options: + description: 应用版本元信息表单字段结构 + properties: + build_version: 构建版本 + release_version: 发布版本 + release_type: 应用类型,比如 debug, beta, adhoc, release, enterprise 等 + source: 上传渠道名称,默认是 `api` + changelog: 变更日志,接受纯文本或 JSON 格式化的数据 + branch: 代码控制软件的分支名 + git_commit: 代码控制软件提交哈希值 + ci_url: 持续构建系统构建 URL + custom_fields: 这是一个用 JSON 字符串定义的自定义字段,图标可接受 fontawesome collaborator_options: description: 应用成员表单字段结构 properties: @@ -228,6 +240,19 @@ zh-CN: title: 删除应用渠道 description: 从应用中删除指定应用渠道 + releases: + default: + tags: 应用版本 + responses: + update: 更新应用版本 + destroy: 删除应用版本 + update: + title: 更新应用版本元信息 + description: 更新应用版本的版本、自定义字段、变更日志等信息 + destroy: + title: 删除应用版本 + description: 删除应用版本 + collaborators: default: tags: 应用成员 diff --git a/lib/tasks/zealot/zealot.rake b/lib/tasks/zealot/zealot.rake index ecfae3dfe..ec30c52a4 100644 --- a/lib/tasks/zealot/zealot.rake +++ b/lib/tasks/zealot/zealot.rake @@ -109,11 +109,17 @@ namespace :zealot do task :swaggerize do ENV['RAILS_ENV'] = 'test' current_locale = ENV['DEFAULT_LOCALE'] + Rails.configuration.i18n.available_locales.each do |locale| + # reset task invoke status and execute + Rake::Task['rswag:specs:swaggerize'].reenable + + puts "Generating swagger file ... #{locale}" ENV['DEFAULT_LOCALE'] = current_locale.to_s - puts "Generating #{locale} swagger ..." - Rake::Task['rswag'].invoke + Rake::Task['rswag:specs:swaggerize'].invoke end + + # restore ENV['DEFAULT_LOCALE'] = current_locale ENV.delete('RAILS_ENV') end diff --git a/spec/api/apps_spec.rb b/spec/api/apps_spec.rb index 0c312b5b4..b36fd2e75 100644 --- a/spec/api/apps_spec.rb +++ b/spec/api/apps_spec.rb @@ -129,7 +129,7 @@ description I18n.t('api.apps.create.description') operationId 'createApp' - include_examples :request_form_body, '#/definitions/AppOptions' + include_examples :request_body, '#/definitions/AppOptions' produces 'application/json' response 201, I18n.t('api.apps.default.responses.show') do @@ -148,7 +148,7 @@ operationId 'updateApp' include_examples :primary_key_parameter - include_examples :request_form_body, '#/definitions/AppOptions' + include_examples :request_body, '#/definitions/AppOptions' produces 'application/json' response 200, I18n.t('api.apps.default.responses.show') do diff --git a/spec/api/channels_spec.rb b/spec/api/channels_spec.rb index e451252f8..548cdefcb 100644 --- a/spec/api/channels_spec.rb +++ b/spec/api/channels_spec.rb @@ -29,7 +29,7 @@ operationId 'createChannel' include_examples :primary_key_parameter, :scheme_id - include_examples :request_form_body, '#/definitions/ChannelOptions' + include_examples :request_body, '#/definitions/ChannelOptions' produces 'application/json' response 201, I18n.t('api.channels.default.responses.create') do @@ -49,7 +49,7 @@ operationId 'updateChannel' include_examples :primary_key_parameter - include_examples :request_form_body, '#/definitions/ChannelOptions' + include_examples :request_body, '#/definitions/ChannelOptions' produces 'application/json' response 200, I18n.t('api.channels.default.responses.update') do diff --git a/spec/api/collaborators_spec.rb b/spec/api/collaborators_spec.rb index 22f9a9828..8abca8c4d 100644 --- a/spec/api/collaborators_spec.rb +++ b/spec/api/collaborators_spec.rb @@ -31,7 +31,7 @@ include_examples :primary_key_parameter, :app_id include_examples :primary_key_parameter, :user_id - include_examples :request_form_body, '#/definitions/CollaboratorOptions' + include_examples :request_body, '#/definitions/CollaboratorOptions' produces 'application/json' response 201, I18n.t('api.collaborators.default.responses.create') do @@ -52,7 +52,7 @@ include_examples :primary_key_parameter, :app_id include_examples :primary_key_parameter, :user_id - include_examples :request_form_body, '#/definitions/CollaboratorOptions' + include_examples :request_body, '#/definitions/CollaboratorOptions' produces 'application/json' response 200, I18n.t('api.collaborators.default.responses.update') do diff --git a/spec/api/releases_spec.rb b/spec/api/releases_spec.rb new file mode 100644 index 000000000..455221a7b --- /dev/null +++ b/spec/api/releases_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'swagger_helper' + +RSpec.describe 'Releases API' do + path '/releases/{id}' do + put I18n.t('api.releases.update.title') do + tags I18n.t('api.releases.default.tags') + description I18n.t('api.releases.update.description') + operationId 'updateRelease' + + include_examples :primary_key_parameter + include_examples :request_body, '#/definitions/ReleaseOptions' + + produces 'application/json' + response 200, I18n.t('api.releases.default.responses.show') do + schema '$ref': '#/components/schemas/Release' + run_test! + end + + include_examples :unauthorized_response + include_examples :not_found_response + end + end + + path '/releases/{id}' do + delete I18n.t('api.releases.destroy.title') do + tags I18n.t('api.releases.default.tags') + description I18n.t('api.releases.destroy.description') + operationId 'destroyRelease' + + include_examples :primary_key_parameter + + produces 'application/json' + response 200, I18n.t('api.releases.default.responses.destroy') do + schema '$ref': '#/components/responses/Destroyed' + run_test! + end + + include_examples :unauthorized_response + include_examples :not_found_response + end + end +end diff --git a/spec/api/schemes_spec.rb b/spec/api/schemes_spec.rb index a455bfdba..52254952a 100644 --- a/spec/api/schemes_spec.rb +++ b/spec/api/schemes_spec.rb @@ -29,7 +29,7 @@ operationId 'createScheme' include_examples :primary_key_parameter, :app_id - include_examples :request_form_body, '#/definitions/SchemeOptions' + include_examples :request_body, '#/definitions/SchemeOptions' produces 'application/json' response 201, I18n.t('api.schemes.default.responses.create') do @@ -49,7 +49,7 @@ operationId 'updateScheme' include_examples :primary_key_parameter - include_examples :request_form_body, '#/definitions/SchemeOptions' + include_examples :request_body, '#/definitions/SchemeOptions' produces 'application/json' response 200, I18n.t('api.schemes.default.responses.update') do diff --git a/spec/api/users_spec.rb b/spec/api/users_spec.rb index 0ea3a2439..93053b80e 100644 --- a/spec/api/users_spec.rb +++ b/spec/api/users_spec.rb @@ -67,7 +67,7 @@ description I18n.t('api.users.create.description') operationId 'createUser' - include_examples :request_form_body, '#/definitions/UserOptions' + include_examples :request_body, '#/definitions/UserOptions' produces 'application/json' response 201, I18n.t('api.users.default.responses.create') do @@ -87,7 +87,7 @@ operationId 'updateUser' include_examples :primary_key_parameter - include_examples :request_form_body, '#/definitions/UserOptions' + include_examples :request_body, '#/definitions/UserOptions' produces 'application/json' response 200, I18n.t('api.users.default.responses.update') do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d7a7fadce..356b7c93d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -46,6 +46,12 @@ # triggering implicit auto-inclusion in groups with matching metadata. config.shared_context_metadata_behavior = :apply_to_host_groups + config.before :all do + locale = ENV['DEFAULT_LOCALE'] + puts "========= #{locale} =========" + I18n.locale = locale.to_sym if locale.present? + end + # The settings below are suggested to provide a good initial experience # with RSpec, but feel free to customize to your heart's content. =begin diff --git a/spec/support/swagger/shared.rb b/spec/support/swagger/shared.rb index aa7895b6e..4cc4db7aa 100644 --- a/spec/support/swagger/shared.rb +++ b/spec/support/swagger/shared.rb @@ -44,6 +44,22 @@ parameter name: :build_version, in: query, type: type, required: required, **options end +# workaround to request both form data and json of body +# ref: https://github.com/rswag/rswag/issues/528#issuecomment-1929012414 +shared_examples :request_body do |ref, **options| + metadata[:operation][:requestBody] = { + required: true, + content: { + 'application/json': { + schema: { '$ref': ref } + }, + 'multipart/form-data': { + schema: { '$ref': ref } + } + } + } +end + shared_examples :request_form_body do |ref, **options| consumes 'multipart/form-data' parameter name: :body, in: :body, schema: { '$ref': ref }, **options diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 4b0522496..67843d3a0 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -9,7 +9,7 @@ openapi: '3.1.0', info: { title: 'Zealot API', - version: 'v1.3', + version: 'v1.4', description: I18n.t('api.info.description') }, servers: [ @@ -339,6 +339,21 @@ password: { type: :string, description: I18n.t('api.definitions.channel_options.properties.password') } } }, + ReleaseOptions: { + description: I18n.t('api.definitions.release_options.description'), + type: :object, + properties: { + build_version: { type: :string, description: I18n.t('api.definitions.release_options.properties.build_version') }, + release_version: { type: :string, description: I18n.t('api.definitions.release_options.properties.release_version') }, + release_type: { type: :string, description: I18n.t('api.definitions.release_options.properties.release_type') }, + source: { type: :string, description: I18n.t('api.definitions.release_options.properties.source') }, + changelog: { type: :array, items: { '$ref': '#/components/schemas/ReleaseChangelog' }, description: I18n.t('api.definitions.release_options.properties.changelog')}, + branch: { type: :string, description: I18n.t('api.definitions.release_options.properties.branch') }, + git_commit: { type: :string, description: I18n.t('api.definitions.release_options.properties.git_commit') }, + ci_url: { type: :string, description: I18n.t('api.definitions.release_options.properties.ci_url') }, + custom_fields: { type: :array, items: { '$ref': '#/components/schemas/ReleaseCustomField' }, description: I18n.t('api.definitions.release_options.properties.custom_fields')}, + } + }, CollaboratorOptions: { description: I18n.t('api.definitions.collaborator_options.description'), type: :object, diff --git a/swagger/v1/swagger_en.json b/swagger/v1/swagger_en.json index c8bd7fd13..c01e8db3f 100644 --- a/swagger/v1/swagger_en.json +++ b/swagger/v1/swagger_en.json @@ -2,8 +2,8 @@ "openapi": "3.1.0", "info": { "title": "Zealot API", - "version": "v1.3", - "description": "This documentation doesn't provide a way to test our API. In order to facilitate testing, we recommend the following tools:\n\n- [cURL](https://curl.se/) (recommended, command-line)\n- [Bruno](https://www.usebruno.com/)\n- [Postman](https://www.postman.com/downloads/)\n- Your web browser, if you don't need to send headers or a request body\n\nOnce you have a working client, you can test that it works by making a GET request to {host}/version:\n\n```json\n{\n \"version\": \"5.3.6\",\n \"vcs_ref\": \"effe99c25b79fd55d3e1959ea3af0bcb6b75ba1d\",\n \"build_date\": \"2024-05-23T06:04:48.989Z\"\n}\n```\n\n## Authentication\n\nThis API only accepts one options for authentication: Personal access tokens.\nAll tokens are tied to a Zealot user and use the `token` query of the request.\n\nExample:\n\n```\nhttps://tryzealot.ews.im/api/users?token={token}\n```\n\n### Personal access tokens\n\nPersonal access tokens (PATs) can be found in from the [user settings](/docs/user-guide/user_settings).\n" + "version": "v1.4", + "description": "This documentation doesn't provide a way to test our API. In order to facilitate testing, we recommend the following tools:\n\n- [cURL](https://curl.se/) (recommended, command-line)\n- [Bruno](https://www.usebruno.com/)\n- [Postman](https://www.postman.com/downloads/)\n- Your web browser, if you don't need to send headers or a request body\n\nOnce you have a working client, you can test that it works by making a GET request to {host}/version:\n\n```json\n{\n \"version\": \"5.3.6\",\n \"vcs_ref\": \"effe99c25b79fd55d3e1959ea3af0bcb6b75ba1d\",\n \"build_date\": \"2024-05-23T06:04:48.989Z\"\n}\n```\n\n## Authentication\n\nThis API only accepts one options for authentication: Personal access tokens.\nAll tokens are tied to a Zealot user and use the `token` query of the request.\n\nExample:\n\n```\nhttps://tryzealot.ews.im/api/users?token={token}\n```\n\n### Personal access tokens\n\nPersonal access tokens (PATs) can be found in from the [user settings](https://zealot.ews.im/docs/user-guide/user_settings).\n" }, "servers": [ { @@ -61,9 +61,21 @@ ], "description": "Create an App", "operationId": "createApp", - "parameters": [ - - ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + } + } + }, "responses": { "201": { "description": "Get an App", @@ -85,15 +97,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/AppOptions" - } - } - } } } }, @@ -411,6 +414,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + } + } + }, "responses": { "200": { "description": "Get an App", @@ -442,15 +460,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/AppOptions" - } - } - } } }, "delete": { @@ -575,6 +584,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + } + } + }, "responses": { "201": { "description": "Create a channel", @@ -606,15 +630,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/ChannelOptions" - } - } - } } } }, @@ -636,6 +651,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + } + } + }, "responses": { "200": { "description": "Update a channel", @@ -667,15 +697,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/ChannelOptions" - } - } - } } }, "delete": { @@ -813,6 +834,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + } + } + }, "responses": { "201": { "description": "Create a collaborator", @@ -844,15 +880,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/CollaboratorOptions" - } - } - } } }, "put": { @@ -880,6 +907,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + } + } + }, "responses": { "200": { "description": "Update a collaborator", @@ -911,15 +953,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/CollaboratorOptions" - } - } - } } }, "delete": { @@ -1248,6 +1281,123 @@ } } }, + "/releases/{id}": { + "put": { + "summary": "Update a build metedata", + "tags": [ + "Release" + ], + "description": "Update a build of app verison, custom_fileds, changelog etc", + "operationId": "updateRelease", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/ReleaseOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/ReleaseOptions" + } + } + } + }, + "responses": { + "200": { + "description": "Translation missing: en.api.releases.default.responses.show", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Release" + } + } + } + }, + "401": { + "description": "Unauthorized Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/NotFound" + } + } + } + } + } + }, + "delete": { + "summary": "Destroy a build", + "tags": [ + "Release" + ], + "description": "Destroy a app's build", + "operationId": "destroyRelease", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Destroy build", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/Destroyed" + } + } + } + }, + "401": { + "description": "Unauthorized Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/NotFound" + } + } + } + } + } + } + }, "/apps/{app_id}/schemes": { "get": { "summary": "Get a scheme", @@ -1319,6 +1469,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + } + } + }, "responses": { "201": { "description": "Create a scheme", @@ -1350,15 +1515,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/SchemeOptions" - } - } - } } } }, @@ -1380,6 +1536,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + } + } + }, "responses": { "200": { "description": "Update a scheme", @@ -1411,15 +1582,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/SchemeOptions" - } - } - } } }, "delete": { @@ -1534,9 +1696,21 @@ ], "description": "Create an user", "operationId": "createUser", - "parameters": [ - - ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + } + } + }, "responses": { "201": { "description": "Create an user", @@ -1568,15 +1742,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/UserOptions" - } - } - } } } }, @@ -1648,6 +1813,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + } + } + }, "responses": { "200": { "description": "Update a user", @@ -1679,15 +1859,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/UserOptions" - } - } - } } }, "delete": { @@ -2763,6 +2934,7 @@ "enum": [ "ios", "android", + "harmonyos", "macos", "windows", "linux" @@ -2787,6 +2959,54 @@ } } }, + "ReleaseOptions": { + "description": "App's build metadata form data", + "type": "object", + "properties": { + "build_version": { + "type": "string", + "description": "Build version" + }, + "release_version": { + "type": "string", + "description": "Release version" + }, + "release_type": { + "type": "string", + "description": "Translation missing: en.api.definitions.release_options.properties.release_type" + }, + "source": { + "type": "string", + "description": "the source of upload (default is `api`)" + }, + "changelog": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseChangelog" + }, + "description": "Change log, accept plain text or JSON formatted data" + }, + "branch": { + "type": "string", + "description": "a branch name from source control tool" + }, + "git_commit": { + "type": "string", + "description": "Git Commit SHA value" + }, + "ci_url": { + "type": "string", + "description": "the build url of a CI service" + }, + "custom_fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseCustomField" + }, + "description": "JSON formatted custom fields, icon only accepts fontawesome." + } + } + }, "CollaboratorOptions": { "description": "App's collaborator form data", "type": "object", @@ -3024,4 +3244,4 @@ } } } -} +} \ No newline at end of file diff --git a/swagger/v1/swagger_zh-CN.json b/swagger/v1/swagger_zh-CN.json index d73ff115b..9e8b7aef0 100644 --- a/swagger/v1/swagger_zh-CN.json +++ b/swagger/v1/swagger_zh-CN.json @@ -2,8 +2,8 @@ "openapi": "3.1.0", "info": { "title": "Zealot API", - "version": "v1.3", - "description": "文档可能提供或没有提供测试接口的工具,便于快速测试,你还可以使用如下工具:\n\n- [cURL](https://curl.se/) (推荐,命令行工具)\n- [Bruno](https://www.usebruno.com/)\n- [Postman](https://www.postman.com/downloads/)\n- 任意浏览器,如果你不需要设置 headers 或请求主体\n\n准备好工具,你可以通过 `GET` 请求 {host}/version 可看到 Zealot 版本信息:\n\n```json\n{\n \"version\": \"5.3.6\",\n \"vcs_ref\": \"effe99c25b79fd55d3e1959ea3af0bcb6b75ba1d\",\n \"build_date\": \"2024-05-23T06:04:48.989Z\"\n}\n```\n\n## 接口认证\n\n接口目前仅提供在用户密钥认证方式,参数是 `token`,请求接口时可在接口 query 或表单字段中传递此字段。\n\n```\nhttps://tryzealot.ews.im/api/users?token={token}\n```\n\n### 用户密钥\n\n用户密钥在[用户详情](/docs/user-guide/user_settings)最底部找到。\n" + "version": "v1.4", + "description": "文档可能提供或没有提供测试接口的工具,便于快速测试,你还可以使用如下工具:\n\n- [cURL](https://curl.se/) (推荐,命令行工具)\n- [Bruno](https://www.usebruno.com/)\n- [Postman](https://www.postman.com/downloads/)\n- 任意浏览器,如果你不需要设置 headers 或请求主体\n\n准备好工具,你可以通过 `GET` 请求 {host}/version 可看到 Zealot 版本信息:\n\n```json\n{\n \"version\": \"5.3.6\",\n \"vcs_ref\": \"effe99c25b79fd55d3e1959ea3af0bcb6b75ba1d\",\n \"build_date\": \"2024-05-23T06:04:48.989Z\"\n}\n```\n\n## 接口认证\n\n接口目前仅提供在用户密钥认证方式,参数是 `token`,请求接口时可在接口 query 或表单字段中传递此字段。\n\n```\nhttps://tryzealot.ews.im/api/users?token={token}\n```\n\n### 用户密钥\n\n用户密钥在[用户详情](https://zealot.ews.im/zh-Hans/docs/user-guide/user_settings)最底部找到。\n" }, "servers": [ { @@ -61,9 +61,21 @@ ], "description": "根据应用名创建应用", "operationId": "createApp", - "parameters": [ - - ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + } + } + }, "responses": { "201": { "description": "应用详情", @@ -85,15 +97,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/AppOptions" - } - } - } } } }, @@ -411,6 +414,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/AppOptions" + } + } + } + }, "responses": { "200": { "description": "应用详情", @@ -442,15 +460,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/AppOptions" - } - } - } } }, "delete": { @@ -575,6 +584,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + } + } + }, "responses": { "201": { "description": "应用渠道详情", @@ -606,15 +630,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/ChannelOptions" - } - } - } } } }, @@ -636,6 +651,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/ChannelOptions" + } + } + } + }, "responses": { "200": { "description": "更新应用渠道信息", @@ -667,15 +697,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/ChannelOptions" - } - } - } } }, "delete": { @@ -813,6 +834,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + } + } + }, "responses": { "201": { "description": "应用成员详情", @@ -844,15 +880,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/CollaboratorOptions" - } - } - } } }, "put": { @@ -880,6 +907,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/CollaboratorOptions" + } + } + } + }, "responses": { "200": { "description": "更新应用成员信息", @@ -911,15 +953,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/CollaboratorOptions" - } - } - } } }, "delete": { @@ -1248,6 +1281,123 @@ } } }, + "/releases/{id}": { + "put": { + "summary": "更新应用版本元信息", + "tags": [ + "应用版本" + ], + "description": "更新应用版本的版本、自定义字段、变更日志等信息", + "operationId": "updateRelease", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/ReleaseOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/ReleaseOptions" + } + } + } + }, + "responses": { + "200": { + "description": "Translation missing: zh-CN.api.releases.default.responses.show", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Release" + } + } + } + }, + "401": { + "description": "用户密钥认证失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "404": { + "description": "资源未找到", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/NotFound" + } + } + } + } + } + }, + "delete": { + "summary": "删除应用版本", + "tags": [ + "应用版本" + ], + "description": "删除应用版本", + "operationId": "destroyRelease", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "删除应用版本", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/Destroyed" + } + } + } + }, + "401": { + "description": "用户密钥认证失败", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "404": { + "description": "资源未找到", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/responses/NotFound" + } + } + } + } + } + } + }, "/apps/{app_id}/schemes": { "get": { "summary": "获取应用类型详情", @@ -1319,6 +1469,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + } + } + }, "responses": { "201": { "description": "应用类型详情", @@ -1350,15 +1515,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/SchemeOptions" - } - } - } } } }, @@ -1380,6 +1536,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/SchemeOptions" + } + } + } + }, "responses": { "200": { "description": "更新应用类型信息", @@ -1411,15 +1582,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/SchemeOptions" - } - } - } } }, "delete": { @@ -1534,9 +1696,21 @@ ], "description": "创建用户", "operationId": "createUser", - "parameters": [ - - ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + } + } + }, "responses": { "201": { "description": "用户详情", @@ -1568,15 +1742,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/UserOptions" - } - } - } } } }, @@ -1648,6 +1813,21 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/definitions/UserOptions" + } + } + } + }, "responses": { "200": { "description": "更新用户信息", @@ -1679,15 +1859,6 @@ } } } - }, - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/definitions/UserOptions" - } - } - } } }, "delete": { @@ -2763,6 +2934,7 @@ "enum": [ "ios", "android", + "harmonyos", "macos", "windows", "linux" @@ -2787,6 +2959,54 @@ } } }, + "ReleaseOptions": { + "description": "应用版本元信息表单字段结构", + "type": "object", + "properties": { + "build_version": { + "type": "string", + "description": "构建版本" + }, + "release_version": { + "type": "string", + "description": "发布版本" + }, + "release_type": { + "type": "string", + "description": "应用类型,比如 debug, beta, adhoc, release, enterprise 等" + }, + "source": { + "type": "string", + "description": "上传渠道名称,默认是 `api`" + }, + "changelog": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseChangelog" + }, + "description": "变更日志,接受纯文本或 JSON 格式化的数据" + }, + "branch": { + "type": "string", + "description": "代码控制软件的分支名" + }, + "git_commit": { + "type": "string", + "description": "代码控制软件提交哈希值" + }, + "ci_url": { + "type": "string", + "description": "持续构建系统构建 URL" + }, + "custom_fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ReleaseCustomField" + }, + "description": "这是一个用 JSON 字符串定义的自定义字段,图标可接受 fontawesome" + } + } + }, "CollaboratorOptions": { "description": "应用成员表单字段结构", "type": "object", @@ -3024,4 +3244,4 @@ } } } -} +} \ No newline at end of file