From c42f3d59281ba65edc85873e6ff3a9d551968410 Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 15 Jun 2022 18:07:23 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E9=82=80?= =?UTF-8?q?=E8=AF=B7=E7=94=A8=E6=88=B7=E9=93=BE=E6=8E=A5=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project_invite_links_controller.rb | 36 +++++++++ .../project_invite_links/create_form.rb | 8 ++ app/models/applied_project.rb | 21 ++--- app/models/project.rb | 1 + app/models/project_invite_link.rb | 57 ++++++++++++++ app/services/projects/link_join_service.rb | 76 +++++++++++++++++++ app/views/projects/_detail.json.jbuilder | 8 ++ .../_detail.json.jbuilder | 12 +++ .../current_link.json.jbuilder | 1 + config/routes.rb | 7 ++ ...20614070028_create_project_invite_links.rb | 16 ++++ ...project_invite_link_to_applied_projects.rb | 6 ++ spec/models/project_invite_link_spec.rb | 5 ++ 13 files changed, 245 insertions(+), 9 deletions(-) create mode 100644 app/controllers/projects/project_invite_links_controller.rb create mode 100644 app/forms/projects/project_invite_links/create_form.rb create mode 100644 app/models/project_invite_link.rb create mode 100644 app/services/projects/link_join_service.rb create mode 100644 app/views/projects/_detail.json.jbuilder create mode 100644 app/views/projects/project_invite_links/_detail.json.jbuilder create mode 100644 app/views/projects/project_invite_links/current_link.json.jbuilder create mode 100644 db/migrate/20220614070028_create_project_invite_links.rb create mode 100644 db/migrate/20220614081950_add_project_invite_link_to_applied_projects.rb create mode 100644 spec/models/project_invite_link_spec.rb diff --git a/app/controllers/projects/project_invite_links_controller.rb b/app/controllers/projects/project_invite_links_controller.rb new file mode 100644 index 000000000..59f618fc0 --- /dev/null +++ b/app/controllers/projects/project_invite_links_controller.rb @@ -0,0 +1,36 @@ +class Projects::ProjectInviteLinksController < Projects::BaseController + before_action :require_manager!, except: [:redirect_link] + before_action :require_login + + def current_link + @project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id) + @project_invite_link = ProjectInviteLink.build!(@project, current_user) unless @project_invite_link.present? + end + + def generate_link + ActiveRecord::Base.transaction do + params_data = link_params.merge({user_id: current_user.id, project_id: @project.id}) + puts params_data + Projects::ProjectInviteLinks::CreateForm.new(params_data).validate! + @project_invite_link = ProjectInviteLink.create!(params_data.merge(sign: ProjectInviteLink.random_hex_sign)) + render_ok + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def redirect_link + Projects::LinkJoinService.call(current_user, @project, params[:invite_sign]) + render_ok + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + + private + def link_params + params.require(:project_invite_link).permit(:role, :is_apply) + end +end diff --git a/app/forms/projects/project_invite_links/create_form.rb b/app/forms/projects/project_invite_links/create_form.rb new file mode 100644 index 000000000..701625c0a --- /dev/null +++ b/app/forms/projects/project_invite_links/create_form.rb @@ -0,0 +1,8 @@ +class Projects::ProjectInviteLinks::CreateForm < BaseForm + attr_accessor :user_id, :project_id, :role, :is_apply + + validates :user_id, :project_id, :role, presence: true + validates :role, inclusion: { in: %w(manager developer reporter), message: "请输入正确的权限." } + validates :is_apply, inclusion: {in: [true, false], message: "请输入是否需要管理员审核."} +end + \ No newline at end of file diff --git a/app/models/applied_project.rb b/app/models/applied_project.rb index ea7ca6eee..2b18d4d82 100644 --- a/app/models/applied_project.rb +++ b/app/models/applied_project.rb @@ -2,24 +2,27 @@ # # Table name: forge_applied_projects # -# id :integer not null, primary key -# project_id :integer -# user_id :integer -# role :integer default("0") -# status :integer default("0") -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# project_id :integer +# user_id :integer +# role :integer default("0") +# status :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# project_invite_link_id :integer # # Indexes # -# index_forge_applied_projects_on_project_id (project_id) -# index_forge_applied_projects_on_user_id (user_id) +# index_forge_applied_projects_on_project_id (project_id) +# index_forge_applied_projects_on_project_invite_link_id (project_invite_link_id) +# index_forge_applied_projects_on_user_id (user_id) # class AppliedProject < ApplicationRecord self.table_name = "forge_applied_projects" belongs_to :user belongs_to :project + belongs_to :project_invite_link, optional: true has_many :applied_messages, as: :applied, dependent: :destroy # has_many :forge_activities, as: :forge_act, dependent: :destroy diff --git a/app/models/project.rb b/app/models/project.rb index edaa00eb5..92e1bac77 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -128,6 +128,7 @@ class Project < ApplicationRecord has_many :pinned_projects, dependent: :destroy has_many :has_pinned_users, through: :pinned_projects, source: :user has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id + has_many :project_invite_links, dependent: :destroy after_create :incre_user_statistic, :incre_platform_statistic after_save :check_project_members before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data diff --git a/app/models/project_invite_link.rb b/app/models/project_invite_link.rb new file mode 100644 index 000000000..fa5c0c440 --- /dev/null +++ b/app/models/project_invite_link.rb @@ -0,0 +1,57 @@ +# == Schema Information +# +# Table name: project_invite_links +# +# id :integer not null, primary key +# project_id :integer +# user_id :integer +# role :integer default("4") +# is_apply :boolean default("1") +# sign :string(255) +# expired_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_project_invite_links_on_project_id (project_id) +# index_project_invite_links_on_sign (sign) +# index_project_invite_links_on_user_id (user_id) +# + +class ProjectInviteLink < ApplicationRecord + + default_scope { where("expired_at > ?", Time.now).or(where(expired_at: nil)) } + + belongs_to :project + belongs_to :user + has_many :applied_projects + + scope :with_project_id, -> (project_id) {where(project_id: project_id)} + scope :with_user_id, -> (user_id) {where(user_id: user_id)} + + enum role: {manager: 3, developer: 4, reporter: 5} + + before_create :set_old_data_expired_at + + def self.random_hex_sign + SecureRandom.hex + end + + def self.build!(project, user, role="developer", is_apply=true) + self.create!( + project_id: project&.id, + user_id: user&.id, + role: role, + is_apply: is_apply, + sign: random_hex_sign + ) + end + + private + def set_old_data_expired_at + ProjectInviteLink.where(user_id: self.user_id, project_id: self.project).update_all(expired_at: Time.now) + end + + +end diff --git a/app/services/projects/link_join_service.rb b/app/services/projects/link_join_service.rb new file mode 100644 index 000000000..c42376ef2 --- /dev/null +++ b/app/services/projects/link_join_service.rb @@ -0,0 +1,76 @@ +class Projects::LinkJoinService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user, :project, :invite_sign, :params + + def initialize(user, project, invite_sign, params={}) + @user = user + @project = project + @invite_sign = invite_sign + @params = params + end + + def call + ActiveRecord::Base.transaction do + validate! + if invite_link.is_apply + # 如果需要申请才能加入,创建一条申请记录 + create_applied_project! + else + # 如果不需要申请,直接为项目添加该成员 + create_member! + end + end + end + + private + def validate! + raise Error, 'invite_sign必须存在!' if invite_sign.blank? + raise Error, '邀请链接不存在!' unless invite_link.present? + raise Error, '邀请链接已失效!' unless invite_user_in_project + raise Error, '用户已加入该项目!' if project.member?(user.id) + end + + def create_applied_project! + user.applied_projects.create!(project: project, role: role_value) + end + + def create_member! + Projects::AddMemberInteractor.call(project.owner, project, user, permission) + end + + def invite_link + ProjectInviteLink.find_by(project_id: project.id, sign: invite_sign) + end + + def invite_user_in_project + in_project = project.member?(invite_link.user) + invite_link.update_column(:expired_at, Time.now) unless in_project + in_project + end + + def role_value + @_role ||= + case invite_link&.role + when 'manager' then 3 + when 'developer' then 4 + when 'reporter' then 5 + else + 5 + end + end + + def permission + case invite_link&.role + when 'manager' + 'admin' + when 'developer' + 'write' + when 'reporter' + 'read' + else + 'read' + end + end + +end \ No newline at end of file diff --git a/app/views/projects/_detail.json.jbuilder b/app/views/projects/_detail.json.jbuilder new file mode 100644 index 000000000..ed23fdef2 --- /dev/null +++ b/app/views/projects/_detail.json.jbuilder @@ -0,0 +1,8 @@ +json.id project.id +json.identifier project.identifier +json.name project.name +json.description project.description +json.is_public project.is_public +json.owner do + json.partial! "/users/user_simple", locals: {user: project.owner} +end \ No newline at end of file diff --git a/app/views/projects/project_invite_links/_detail.json.jbuilder b/app/views/projects/project_invite_links/_detail.json.jbuilder new file mode 100644 index 000000000..7c9f78ddf --- /dev/null +++ b/app/views/projects/project_invite_links/_detail.json.jbuilder @@ -0,0 +1,12 @@ +json.(project_invite_link, :id, :role, :is_apply, :sign) + +json.user do + json.partial! "/users/user_simple", locals: {user: project_invite_link.user} +end +if project_invite_link&.project.present? + json.project do + json.partial! "/projects/detail", locals: {project: project_invite_link.project} + end +else + json.project nil +end diff --git a/app/views/projects/project_invite_links/current_link.json.jbuilder b/app/views/projects/project_invite_links/current_link.json.jbuilder new file mode 100644 index 000000000..1903e10a9 --- /dev/null +++ b/app/views/projects/project_invite_links/current_link.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'detail', locals: { project_invite_link: @project_invite_link } diff --git a/config/routes.rb b/config/routes.rb index b585f0775..ed28b5ba2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -603,6 +603,13 @@ Rails.application.routes.draw do post :cancel end end + resources :project_invite_links, only: [:index] do + collection do + get :current_link + post :generate_link + post :redirect_link + end + end resources :webhooks, except: [:show, :new] do member do get :tasks diff --git a/db/migrate/20220614070028_create_project_invite_links.rb b/db/migrate/20220614070028_create_project_invite_links.rb new file mode 100644 index 000000000..5b482967f --- /dev/null +++ b/db/migrate/20220614070028_create_project_invite_links.rb @@ -0,0 +1,16 @@ +class CreateProjectInviteLinks < ActiveRecord::Migration[5.2] + def change + create_table :project_invite_links do |t| + t.references :project + t.references :user + t.integer :role, default: 4 + t.boolean :is_apply, default: true + t.string :sign + t.datetime :expired_at + + t.timestamps + end + + add_index :project_invite_links, :sign + end +end diff --git a/db/migrate/20220614081950_add_project_invite_link_to_applied_projects.rb b/db/migrate/20220614081950_add_project_invite_link_to_applied_projects.rb new file mode 100644 index 000000000..31cbd9512 --- /dev/null +++ b/db/migrate/20220614081950_add_project_invite_link_to_applied_projects.rb @@ -0,0 +1,6 @@ +class AddProjectInviteLinkToAppliedProjects < ActiveRecord::Migration[5.2] + def change + add_column :forge_applied_projects, :project_invite_link_id, :integer + add_index :forge_applied_projects, :project_invite_link_id + end +end diff --git a/spec/models/project_invite_link_spec.rb b/spec/models/project_invite_link_spec.rb new file mode 100644 index 000000000..d7c46fa5a --- /dev/null +++ b/spec/models/project_invite_link_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ProjectInviteLink, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From f6fb50529c9a8db640ade92c66d3ca6b5542e281 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 16 Jun 2022 11:56:09 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E9=82=80=E8=AF=B7?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=93=BE=E6=8E=A5=E6=8E=A5=E5=8F=A3=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project_invite_links_controller.rb | 1 - app/docs/slate/source/includes/_projects.md | 186 ++++++++ app/services/projects/link_join_service.rb | 2 +- .../generate_link.json.jbuilder | 1 + public/docs/api.html | 450 ++++++++++++++++-- 5 files changed, 597 insertions(+), 43 deletions(-) create mode 100644 app/views/projects/project_invite_links/generate_link.json.jbuilder diff --git a/app/controllers/projects/project_invite_links_controller.rb b/app/controllers/projects/project_invite_links_controller.rb index 59f618fc0..c177367cd 100644 --- a/app/controllers/projects/project_invite_links_controller.rb +++ b/app/controllers/projects/project_invite_links_controller.rb @@ -13,7 +13,6 @@ class Projects::ProjectInviteLinksController < Projects::BaseController puts params_data Projects::ProjectInviteLinks::CreateForm.new(params_data).validate! @project_invite_link = ProjectInviteLink.create!(params_data.merge(sign: ProjectInviteLink.random_hex_sign)) - render_ok end rescue Exception => e uid_logger_error(e.message) diff --git a/app/docs/slate/source/includes/_projects.md b/app/docs/slate/source/includes/_projects.md index e133bcdda..7e7004578 100644 --- a/app/docs/slate/source/includes/_projects.md +++ b/app/docs/slate/source/includes/_projects.md @@ -1,4 +1,190 @@ # Projects +## 获取项目邀请链接 +当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接) + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/current_link.json +``` + +```javascript +await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_link.json') +``` + +### HTTP 请求 +`GET /api/:owner/:repo/project_invite_links/current_link.json` + +### 返回字段说明 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |链接id | +|role |string |邀请角色| +|is_apply |boolean |是否需要审核 | +|sign |string |邀请标识(放在链接后面即可)| +|user.id |int |链接创建者的id | +|user.type |string |链接创建者的类型 | +|user.name |string |链接创建者的名称 | +|user.login |string |链接创建者的标识 | +|user.image_url |string |链接创建者头像 | +|project.id |int |链接关联项目的id | +|project.identifier |string |链接关联项目的标识 | +|project.name |string |链接关联项目的名称 | +|project.description |string |链接关联项目的描述 | +|project.is_public |bool |链接关联项目是否公开 | +|project.owner.id |bool |链接关联项目拥有者id | +|project.owner.type |string |链接关联项目拥有者类型 | +|project.owner.name |string |链接关联项目拥有者昵称 | +|project.owner.login |string |链接关联项目拥有者标识 | +|project.owner.image_url|string |链接关联项目拥有者头像 | + +> 返回的JSON示例: + +```json +{ + "id": 7, + "role": "developer", + "is_apply": false, + "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "user": { + "id": 2, + "type": "User", + "name": "heh", + "login": "yystopf", + "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png" + }, + "project": { + "id": 474, + "identifier": "kellect", + "name": "kellect", + "description": null, + "is_public": true, + "owner": { + "id": 2, + "type": "User", + "name": "heh", + "login": "yystopf", + "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png" + } + } +} +``` +## 生成项目邀请链接 +当前登录(管理员)用户生成的项目邀请链接,可选role和is_apply参数 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/generate_link.json +``` + +```javascript +await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_link.json') +``` + +### HTTP 请求 +`POST /api/:owner/:repo/project_invite_links/generate_link.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|role |是| |string |项目权限,reporter: 报告者, developer: 开发者,manager:管理员 | +|is_apply |是| |boolean |是否需要审核 | + + +> 请求的JSON示例 + +```json +{ + "role": "developer", + "is_apply": false +} +``` + +### 返回字段说明 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |链接id | +|role |string |邀请角色| +|is_apply |boolean |是否需要审核 | +|sign |string |邀请标识(放在链接后面即可)| +|user.id |int |链接创建者的id | +|user.type |string |链接创建者的类型 | +|user.name |string |链接创建者的名称 | +|user.login |string |链接创建者的标识 | +|user.image_url |string |链接创建者头像 | +|project.id |int |链接关联项目的id | +|project.identifier |string |链接关联项目的标识 | +|project.name |string |链接关联项目的名称 | +|project.description |string |链接关联项目的描述 | +|project.is_public |bool |链接关联项目是否公开 | +|project.owner.id |bool |链接关联项目拥有者id | +|project.owner.type |string |链接关联项目拥有者类型 | +|project.owner.name |string |链接关联项目拥有者昵称 | +|project.owner.login |string |链接关联项目拥有者标识 | +|project.owner.image_url|string |链接关联项目拥有者头像 | + +> 返回的JSON示例: + +```json +{ + "id": 7, + "role": "developer", + "is_apply": false, + "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "user": { + "id": 2, + "type": "User", + "name": "heh", + "login": "yystopf", + "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png" + }, + "project": { + "id": 474, + "identifier": "kellect", + "name": "kellect", + "description": null, + "is_public": true, + "owner": { + "id": 2, + "type": "User", + "name": "heh", + "login": "yystopf", + "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png" + } + } +} +``` + +## 请求项目邀请链接 +当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6 +``` + +```javascript +await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6') +``` + +### HTTP 请求 +`POST /api/:owner/:repo/project_invite_links/generate_link.json?invite_sign=xxx` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|invite_sign |是| |string |项目邀请链接的标识 | + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` ## 申请加入项目 申请加入项目 diff --git a/app/services/projects/link_join_service.rb b/app/services/projects/link_join_service.rb index c42376ef2..e586933f9 100644 --- a/app/services/projects/link_join_service.rb +++ b/app/services/projects/link_join_service.rb @@ -32,7 +32,7 @@ class Projects::LinkJoinService < ApplicationService end def create_applied_project! - user.applied_projects.create!(project: project, role: role_value) + user.applied_projects.create!(project: project, role: role_value, project_invite_link_id: invite_link&.id) end def create_member! diff --git a/app/views/projects/project_invite_links/generate_link.json.jbuilder b/app/views/projects/project_invite_links/generate_link.json.jbuilder new file mode 100644 index 000000000..1903e10a9 --- /dev/null +++ b/app/views/projects/project_invite_links/generate_link.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'detail', locals: { project_invite_link: @project_invite_link } diff --git a/public/docs/api.html b/public/docs/api.html index 8ef6924b9..bd3f49eb1 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -425,6 +425,15 @@
  • Projects
      +
    • + 获取项目邀请链接 +
    • +
    • + 生成项目邀请链接 +
    • +
    • + 请求项目邀请链接 +
    • 申请加入项目
    • @@ -4390,7 +4399,366 @@ Success — a happy kitten is an authenticated kitten! "created_at": "2021-06-09 16:41", "time_ago": "7分钟前" } -

      Projects

      申请加入项目

      +

      Projects

      获取项目邀请链接

      +

      当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接)

      + +
      +

      示例:

      +
      +
      curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/current_link.json
      +
      await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_link.json')
      +

      HTTP 请求

      +

      GET /api/:owner/:repo/project_invite_links/current_link.json

      +

      返回字段说明

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数类型字段说明
      idint链接id
      rolestring邀请角色
      is_applyboolean是否需要审核
      signstring邀请标识(放在链接后面即可)
      user.idint链接创建者的id
      user.typestring链接创建者的类型
      user.namestring链接创建者的名称
      user.loginstring链接创建者的标识
      user.image_urlstring链接创建者头像
      project.idint链接关联项目的id
      project.identifierstring链接关联项目的标识
      project.namestring链接关联项目的名称
      project.descriptionstring链接关联项目的描述
      project.is_publicbool链接关联项目是否公开
      project.owner.idbool链接关联项目拥有者id
      project.owner.typestring链接关联项目拥有者类型
      project.owner.namestring链接关联项目拥有者昵称
      project.owner.loginstring链接关联项目拥有者标识
      project.owner.image_urlstring链接关联项目拥有者头像
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "id": 7,
      +    "role": "developer",
      +    "is_apply": false,
      +    "sign": "6b6b454843c291d4e52e60853cb8ad9f",
      +    "user": {
      +        "id": 2,
      +        "type": "User",
      +        "name": "heh",
      +        "login": "yystopf",
      +        "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
      +    },
      +    "project": {
      +        "id": 474,
      +        "identifier": "kellect",
      +        "name": "kellect",
      +        "description": null,
      +        "is_public": true,
      +        "owner": {
      +            "id": 2,
      +            "type": "User",
      +            "name": "heh",
      +            "login": "yystopf",
      +            "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
      +        }
      +    }
      +}
      +

      生成项目邀请链接

      +

      当前登录(管理员)用户生成的项目邀请链接,可选role和is_apply参数

      + +
      +

      示例:

      +
      +
      curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/generate_link.json
      +
      await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_link.json')
      +

      HTTP 请求

      +

      POST /api/:owner/:repo/project_invite_links/generate_link.json

      +

      请求参数

      + + + + + + + + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      rolestring项目权限,reporter: 报告者, developer: 开发者,manager:管理员
      is_applyboolean是否需要审核
      + +
      +

      请求的JSON示例

      +
      +
      {
      +    "role": "developer",
      +    "is_apply": false
      +}
      +

      返回字段说明

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数类型字段说明
      idint链接id
      rolestring邀请角色
      is_applyboolean是否需要审核
      signstring邀请标识(放在链接后面即可)
      user.idint链接创建者的id
      user.typestring链接创建者的类型
      user.namestring链接创建者的名称
      user.loginstring链接创建者的标识
      user.image_urlstring链接创建者头像
      project.idint链接关联项目的id
      project.identifierstring链接关联项目的标识
      project.namestring链接关联项目的名称
      project.descriptionstring链接关联项目的描述
      project.is_publicbool链接关联项目是否公开
      project.owner.idbool链接关联项目拥有者id
      project.owner.typestring链接关联项目拥有者类型
      project.owner.namestring链接关联项目拥有者昵称
      project.owner.loginstring链接关联项目拥有者标识
      project.owner.image_urlstring链接关联项目拥有者头像
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "id": 7,
      +    "role": "developer",
      +    "is_apply": false,
      +    "sign": "6b6b454843c291d4e52e60853cb8ad9f",
      +    "user": {
      +        "id": 2,
      +        "type": "User",
      +        "name": "heh",
      +        "login": "yystopf",
      +        "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
      +    },
      +    "project": {
      +        "id": 474,
      +        "identifier": "kellect",
      +        "name": "kellect",
      +        "description": null,
      +        "is_public": true,
      +        "owner": {
      +            "id": 2,
      +            "type": "User",
      +            "name": "heh",
      +            "login": "yystopf",
      +            "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
      +        }
      +    }
      +}
      +

      请求项目邀请链接

      +

      当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核

      + +
      +

      示例:

      +
      +
      curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
      +
      await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
      +

      HTTP 请求

      +

      POST /api/:owner/:repo/project_invite_links/generate_link.json?invite_sign=xxx

      +

      请求参数

      + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      invite_signstring项目邀请链接的标识
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "status": 0,
      +    "message": "success"
      +}
      +

      申请加入项目

      申请加入项目

      @@ -4398,9 +4766,9 @@ Success — a happy kitten is an authenticated kitten!
      curl -X POST http://localhost:3000/api/applied_projects.json
       
      await octokit.request('POST /api/appliedr_projects.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/applied_projects.json

      -

      请求参数

      +

      请求参数

      @@ -4435,7 +4803,7 @@ Success — a happy kitten is an authenticated kitten! "role": "developer" } } -

      返回字段说明

      +

      返回字段说明

      参数
      @@ -4576,9 +4944,9 @@ Success — a happy kitten is an authenticated kitten! -d"limit=5"\ http://localhost:3000/api/projects | jq
      await octokit.request('GET /api/projects')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/projects

      -

      请求参数

      +

      请求参数

      参数
      @@ -4645,7 +5013,7 @@ http://localhost:3000/api/projects | jq
      参数项目类型, 取值为:common、mirror; common:开源托管项目, mirror:开源镜像项目
      -

      返回字段说明

      +

      返回字段说明

      @@ -4797,9 +5165,9 @@ Remember — a happy kitten is an authenticated kitten!
      curl -X GET \
       http://localhost:3000/api/projects/recommend  | jq
       
      await octokit.request('GET /api/projects/recommend.json')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/projects/recommend

      -

      返回字段说明

      +

      返回字段说明

      参数
      @@ -4933,9 +5301,9 @@ Remember — a happy kitten is an authenticated kitten!
      curl -X GET \
       http://localhost:3000/api/yystopf/ceshi/menu_list  | jq
       
      await octokit.request('GET /api/yystopf/ceshi/menu_list')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/:owner/:repo/menu_list

      -

      请求参数

      +

      请求参数

      参数
      @@ -4960,7 +5328,7 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5001,9 +5369,9 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq
      curl -X GET \
       http://localhost:3000/api/jasder/forgeplus/about  | jq
       
      await octokit.request('GET /api/jasder/forgeplus/about')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/:owner/:repo/about

      -

      请求参数

      +

      请求参数

      参数
      @@ -5028,7 +5396,7 @@ http://localhost:3000/api/jasder/forgeplus/about | jq
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5074,7 +5442,7 @@ Remember — a happy kitten is an authenticated kitten!
      curl -X GET \
       http://localhost:3000/api/yystopf/ceshi/project_units.json
       
      await octokit.request('GET /api/yystopf/ceshi/project_units')
      -

      HTTP 请求

      +

      HTTP 请求

      GET /api/yystopf/ceshi/project_units

      返回字段说明:

      参数
      @@ -5117,9 +5485,9 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json -d"{ \"unit_typs\": [\"code\", \"pulls\"]}"\ http://localhost:3000/api/yystopf/ceshi/project_units.json
      await octokit.request('POST /api/yystopf/ceshi/project_units')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/yystopf/ceshi/project_units

      -

      请求参数

      +

      请求参数

      @@ -5181,9 +5549,9 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json -d"license_id=1"\ http://localhost:3000/api/projects.json
      await octokit.request('GET /api/projects.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/projects

      -

      请求参数

      +

      请求参数

      参数
      @@ -5257,7 +5625,7 @@ http://localhost:3000/api/projects.json
      参数项目是否私有, true:为私有,false: 公开,默认为公开
      -

      返回字段说明

      +

      返回字段说明

      @@ -5299,9 +5667,9 @@ http://localhost:3000/api/projects.json -d"project_language_id=2"\ http://localhost:3000/api/projects/migrate.json
      await octokit.request('GET /api/projects/migrate.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/projects/migrate.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5389,7 +5757,7 @@ http://localhost:3000/api/projects/migrate.json
      参数项目是否私有, true:为私有,false: 非私有,默认为公开
      -

      返回字段说明

      +

      返回字段说明

      @@ -5424,9 +5792,9 @@ http://localhost:3000/api/projects/migrate.json
      curl -X POST http://localhost:3000/api/repositories/1244/sync_mirror.json
       
      await octokit.request('POST /api/repositories/1244/sync_mirror.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/repositories/:id/sync_mirror.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5444,7 +5812,7 @@ http://localhost:3000/api/projects/migrate.json
      参数仓库id
      -

      返回字段说明

      +

      返回字段说明

      @@ -5479,9 +5847,9 @@ http://localhost:3000/api/projects/migrate.json
      curl -X POST http://localhost:3000/api/jasder/forgeplus/forks.json
       
      await octokit.request('POST /api/jaser/jasder_test/forks.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/:owner/:repo/forks.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5506,7 +5874,7 @@ http://localhost:3000/api/projects/migrate.json
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5542,9 +5910,9 @@ http://localhost:3000/api/projects/migrate.json
      curl -X GET \
       http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizations.json  | jq
       
      await octokit.request('GET /api/:owner/:repo/applied_transfer_projects/organizations')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/:owner/:repo/applied_transfer_projects/organizations

      -

      请求参数

      +

      请求参数

      参数
      @@ -5569,7 +5937,7 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5636,9 +6004,9 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects.json
       
      await octokit.request('POST /api/:owner/:repo/applied_transfer_projects.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/:owner/:repo/applied_transfer_projects.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5670,7 +6038,7 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      参数迁移对象标识
      -

      返回字段说明

      +

      返回字段说明

      @@ -5840,9 +6208,9 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/cancel.json
       
      await octokit.request('POST /api/:owner/:repo/applied_transfer_projects/cancel.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/:owner/:repo/applied_transfer_projects/cancel.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5867,7 +6235,7 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -6037,9 +6405,9 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/quit.json
       
      await octokit.request('POST /api/:owner/:repo/quit.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/:owner/:repo/quit.json

      -

      请求参数

      +

      请求参数

      参数
      From 45b7f70d9f391a9b77ed4734ffc9d6f710fbcdce Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 20 Jun 2022 10:16:39 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E9=82=80=E8=AF=B7=E9=93=BE=E6=8E=A5=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E9=99=90=E5=88=B6=EF=BC=8C=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?show=5Flink=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project_invite_links_controller.rb | 17 +- app/docs/slate/source/includes/_projects.md | 96 +++++- app/models/project_invite_link.rb | 8 +- .../_detail.json.jbuilder | 2 +- .../show_link.json.jbuilder | 1 + config/routes.rb | 1 + public/docs/api.html | 309 +++++++++++++++--- 7 files changed, 371 insertions(+), 63 deletions(-) create mode 100644 app/views/projects/project_invite_links/show_link.json.jbuilder diff --git a/app/controllers/projects/project_invite_links_controller.rb b/app/controllers/projects/project_invite_links_controller.rb index c177367cd..14bdc959f 100644 --- a/app/controllers/projects/project_invite_links_controller.rb +++ b/app/controllers/projects/project_invite_links_controller.rb @@ -1,24 +1,31 @@ class Projects::ProjectInviteLinksController < Projects::BaseController - before_action :require_manager!, except: [:redirect_link] + before_action :require_manager!, except: [:show_link, :redirect_link] before_action :require_login def current_link - @project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id) - @project_invite_link = ProjectInviteLink.build!(@project, current_user) unless @project_invite_link.present? + role = params[:role] + is_apply = params[:is_apply] + return render_error('请输入正确的参数!') unless role.present? && is_apply.present? + @project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id, role: role, is_apply: is_apply) + @project_invite_link = ProjectInviteLink.build!(@project, current_user, role, is_apply) unless @project_invite_link.present? end def generate_link ActiveRecord::Base.transaction do params_data = link_params.merge({user_id: current_user.id, project_id: @project.id}) - puts params_data Projects::ProjectInviteLinks::CreateForm.new(params_data).validate! - @project_invite_link = ProjectInviteLink.create!(params_data.merge(sign: ProjectInviteLink.random_hex_sign)) + @project_invite_link = ProjectInviteLink.build!(project, user, params_data[:role], params_data[:is_apply]) end rescue Exception => e uid_logger_error(e.message) tip_exception(e.message) end + def show_link + @project_invite_link = ProjectInviteLink.find_by(sign: params[:invite_sign]) + return render_not_found unless @project_invite_link.present? + end + def redirect_link Projects::LinkJoinService.call(current_user, @project, params[:invite_sign]) render_ok diff --git a/app/docs/slate/source/includes/_projects.md b/app/docs/slate/source/includes/_projects.md index 7e7004578..906982b35 100644 --- a/app/docs/slate/source/includes/_projects.md +++ b/app/docs/slate/source/includes/_projects.md @@ -1,5 +1,5 @@ # Projects -## 获取项目邀请链接 +## 获取项目邀请链接(项目管理员) 当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接) > 示例: @@ -15,6 +15,12 @@ await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_lin ### HTTP 请求 `GET /api/:owner/:repo/project_invite_links/current_link.json` +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|role |是| |string |项目权限,reporter: 报告者, developer: 开发者,manager:管理员 | +|is_apply |是| |boolean |是否需要审核 | + ### 返回字段说明 参数 | 类型 | 字段说明 --------- | ----------- | ----------- @@ -22,6 +28,7 @@ await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_lin |role |string |邀请角色| |is_apply |boolean |是否需要审核 | |sign |string |邀请标识(放在链接后面即可)| +|expired_at |string |链接过期时间| |user.id |int |链接创建者的id | |user.type |string |链接创建者的类型 | |user.name |string |链接创建者的名称 | @@ -46,6 +53,7 @@ await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_lin "role": "developer", "is_apply": false, "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "expired_at": "2022-06-23 10:08", "user": { "id": 2, "type": "User", @@ -69,7 +77,7 @@ await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_lin } } ``` -## 生成项目邀请链接 +## 生成项目邀请链接(项目管理员) 当前登录(管理员)用户生成的项目邀请链接,可选role和is_apply参数 > 示例: @@ -108,6 +116,7 @@ await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_l |role |string |邀请角色| |is_apply |boolean |是否需要审核 | |sign |string |邀请标识(放在链接后面即可)| +|expired_at |string |链接过期时间| |user.id |int |链接创建者的id | |user.type |string |链接创建者的类型 | |user.name |string |链接创建者的名称 | @@ -132,6 +141,7 @@ await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_l "role": "developer", "is_apply": false, "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "expired_at": "2022-06-23 10:08", "user": { "id": 2, "type": "User", @@ -156,7 +166,85 @@ await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_l } ``` -## 请求项目邀请链接 +## 获取邀请链接信息(被邀请用户) +用户请求邀请链接时,通过该接口来获取链接的信息 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6 +``` + +```javascript +await octokit.request('POST /api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6') +``` + +### HTTP 请求 +`POST /api/:owner/:repo/project_invite_links/show_link.json?invite_sign=xxx` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|invite_sign |是| |string |项目邀请链接的标识 | + +### 返回字段说明 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |链接id | +|role |string |邀请角色| +|is_apply |boolean |是否需要审核 | +|sign |string |邀请标识(放在链接后面即可)| +|expired_at |string |链接过期时间| +|user.id |int |链接创建者的id | +|user.type |string |链接创建者的类型 | +|user.name |string |链接创建者的名称 | +|user.login |string |链接创建者的标识 | +|user.image_url |string |链接创建者头像 | +|project.id |int |链接关联项目的id | +|project.identifier |string |链接关联项目的标识 | +|project.name |string |链接关联项目的名称 | +|project.description |string |链接关联项目的描述 | +|project.is_public |bool |链接关联项目是否公开 | +|project.owner.id |bool |链接关联项目拥有者id | +|project.owner.type |string |链接关联项目拥有者类型 | +|project.owner.name |string |链接关联项目拥有者昵称 | +|project.owner.login |string |链接关联项目拥有者标识 | +|project.owner.image_url|string |链接关联项目拥有者头像 | + +> 返回的JSON示例: + +```json +{ + "id": 7, + "role": "developer", + "is_apply": false, + "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "expired_at": "2022-06-23 10:08", + "user": { + "id": 2, + "type": "User", + "name": "heh", + "login": "yystopf", + "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png" + }, + "project": { + "id": 474, + "identifier": "kellect", + "name": "kellect", + "description": null, + "is_public": true, + "owner": { + "id": 2, + "type": "User", + "name": "heh", + "login": "yystopf", + "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png" + } + } +} +``` + +## 接受项目邀请链接(被邀请用户) 当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核 > 示例: @@ -170,7 +258,7 @@ await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_l ``` ### HTTP 请求 -`POST /api/:owner/:repo/project_invite_links/generate_link.json?invite_sign=xxx` +`POST /api/:owner/:repo/project_invite_links/redirect_link.json?invite_sign=xxx` ### 请求参数 参数 | 必选 | 默认 | 类型 | 字段说明 diff --git a/app/models/project_invite_link.rb b/app/models/project_invite_link.rb index fa5c0c440..ea77b9517 100644 --- a/app/models/project_invite_link.rb +++ b/app/models/project_invite_link.rb @@ -35,7 +35,8 @@ class ProjectInviteLink < ApplicationRecord before_create :set_old_data_expired_at def self.random_hex_sign - SecureRandom.hex + hex = (SecureRandom.hex(32)) + return hex unless ProjectInviteLink.where(sign: hex).exists? end def self.build!(project, user, role="developer", is_apply=true) @@ -44,13 +45,14 @@ class ProjectInviteLink < ApplicationRecord user_id: user&.id, role: role, is_apply: is_apply, - sign: random_hex_sign + sign: random_hex_sign, + expired_at: Time.now + 3.days ) end private def set_old_data_expired_at - ProjectInviteLink.where(user_id: self.user_id, project_id: self.project).update_all(expired_at: Time.now) + ProjectInviteLink.where(user_id: self.user_id, project_id: self.project, role: self.role, is_apply: self.is_apply).update_all(expired_at: Time.now) end diff --git a/app/views/projects/project_invite_links/_detail.json.jbuilder b/app/views/projects/project_invite_links/_detail.json.jbuilder index 7c9f78ddf..c8e840d0e 100644 --- a/app/views/projects/project_invite_links/_detail.json.jbuilder +++ b/app/views/projects/project_invite_links/_detail.json.jbuilder @@ -1,5 +1,5 @@ json.(project_invite_link, :id, :role, :is_apply, :sign) - +json.expired_at format_time(project_invite_link&.expired_at) json.user do json.partial! "/users/user_simple", locals: {user: project_invite_link.user} end diff --git a/app/views/projects/project_invite_links/show_link.json.jbuilder b/app/views/projects/project_invite_links/show_link.json.jbuilder new file mode 100644 index 000000000..1903e10a9 --- /dev/null +++ b/app/views/projects/project_invite_links/show_link.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'detail', locals: { project_invite_link: @project_invite_link } diff --git a/config/routes.rb b/config/routes.rb index fd89ee08d..d3b2e7f36 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -608,6 +608,7 @@ Rails.application.routes.draw do collection do get :current_link post :generate_link + get :show_link post :redirect_link end end diff --git a/public/docs/api.html b/public/docs/api.html index bd3f49eb1..82b751e9f 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -426,13 +426,16 @@ Projects
      参数
      + + + + + + + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      rolestring项目权限,reporter: 报告者, developer: 开发者,manager:管理员
      is_applyboolean是否需要审核

      返回字段说明

      @@ -4438,6 +4466,11 @@ Success — a happy kitten is an authenticated kitten! + + + + + @@ -4522,6 +4555,7 @@ Success — a happy kitten is an authenticated kitten! "role": "developer", "is_apply": false, "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "expired_at": "2022-06-23 10:08", "user": { "id": 2, "type": "User", @@ -4544,7 +4578,7 @@ Success — a happy kitten is an authenticated kitten! } } } -

      生成项目邀请链接

      +

      生成项目邀请链接(项目管理员)

      当前登录(管理员)用户生成的项目邀请链接,可选role和is_apply参数

      @@ -4554,7 +4588,7 @@ Success — a happy kitten is an authenticated kitten!
      await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_link.json')
       

      HTTP 请求

      POST /api/:owner/:repo/project_invite_links/generate_link.json

      -

      请求参数

      +

      请求参数

      邀请标识(放在链接后面即可)
      expired_atstring链接过期时间
      user.id int 链接创建者的id
      @@ -4616,6 +4650,11 @@ Success — a happy kitten is an authenticated kitten! + + + + + @@ -4700,6 +4739,7 @@ Success — a happy kitten is an authenticated kitten! "role": "developer", "is_apply": false, "sign": "6b6b454843c291d4e52e60853cb8ad9f", + "expired_at": "2022-06-23 10:08", "user": { "id": 2, "type": "User", @@ -4722,7 +4762,176 @@ Success — a happy kitten is an authenticated kitten! } } } -

      请求项目邀请链接

      +

      获取邀请链接信息(被邀请用户)

      +

      用户请求邀请链接时,通过该接口来获取链接的信息

      + +
      +

      示例:

      +
      +
      curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
      +
      await octokit.request('POST /api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
      +

      HTTP 请求

      +

      POST /api/:owner/:repo/project_invite_links/show_link.json?invite_sign=xxx

      +

      请求参数

      +
      参数邀请标识(放在链接后面即可)
      expired_atstring链接过期时间
      user.id int 链接创建者的id
      + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      invite_signstring项目邀请链接的标识
      +

      返回字段说明

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数类型字段说明
      idint链接id
      rolestring邀请角色
      is_applyboolean是否需要审核
      signstring邀请标识(放在链接后面即可)
      expired_atstring链接过期时间
      user.idint链接创建者的id
      user.typestring链接创建者的类型
      user.namestring链接创建者的名称
      user.loginstring链接创建者的标识
      user.image_urlstring链接创建者头像
      project.idint链接关联项目的id
      project.identifierstring链接关联项目的标识
      project.namestring链接关联项目的名称
      project.descriptionstring链接关联项目的描述
      project.is_publicbool链接关联项目是否公开
      project.owner.idbool链接关联项目拥有者id
      project.owner.typestring链接关联项目拥有者类型
      project.owner.namestring链接关联项目拥有者昵称
      project.owner.loginstring链接关联项目拥有者标识
      project.owner.image_urlstring链接关联项目拥有者头像
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "id": 7,
      +    "role": "developer",
      +    "is_apply": false,
      +    "sign": "6b6b454843c291d4e52e60853cb8ad9f",
      +    "expired_at": "2022-06-23 10:08",
      +    "user": {
      +        "id": 2,
      +        "type": "User",
      +        "name": "heh",
      +        "login": "yystopf",
      +        "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
      +    },
      +    "project": {
      +        "id": 474,
      +        "identifier": "kellect",
      +        "name": "kellect",
      +        "description": null,
      +        "is_public": true,
      +        "owner": {
      +            "id": 2,
      +            "type": "User",
      +            "name": "heh",
      +            "login": "yystopf",
      +            "image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
      +        }
      +    }
      +}
      +

      接受项目邀请链接(被邀请用户)

      当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核

      @@ -4730,9 +4939,9 @@ Success — a happy kitten is an authenticated kitten!
      curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
       
      await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
      -

      HTTP 请求

      -

      POST /api/:owner/:repo/project_invite_links/generate_link.json?invite_sign=xxx

      -

      请求参数

      +

      HTTP 请求

      +

      POST /api/:owner/:repo/project_invite_links/redirect_link.json?invite_sign=xxx

      +

      请求参数

      @@ -4766,9 +4975,9 @@ Success — a happy kitten is an authenticated kitten!
      curl -X POST http://localhost:3000/api/applied_projects.json
       
      await octokit.request('POST /api/appliedr_projects.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/applied_projects.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -4803,7 +5012,7 @@ Success — a happy kitten is an authenticated kitten! "role": "developer" } } -

      返回字段说明

      +

      返回字段说明

      参数
      @@ -4944,9 +5153,9 @@ Success — a happy kitten is an authenticated kitten! -d"limit=5"\ http://localhost:3000/api/projects | jq
      await octokit.request('GET /api/projects')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/projects

      -

      请求参数

      +

      请求参数

      参数
      @@ -5013,7 +5222,7 @@ http://localhost:3000/api/projects | jq
      参数项目类型, 取值为:common、mirror; common:开源托管项目, mirror:开源镜像项目
      -

      返回字段说明

      +

      返回字段说明

      @@ -5165,9 +5374,9 @@ Remember — a happy kitten is an authenticated kitten!
      curl -X GET \
       http://localhost:3000/api/projects/recommend  | jq
       
      await octokit.request('GET /api/projects/recommend.json')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/projects/recommend

      -

      返回字段说明

      +

      返回字段说明

      参数
      @@ -5301,9 +5510,9 @@ Remember — a happy kitten is an authenticated kitten!
      curl -X GET \
       http://localhost:3000/api/yystopf/ceshi/menu_list  | jq
       
      await octokit.request('GET /api/yystopf/ceshi/menu_list')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/:owner/:repo/menu_list

      -

      请求参数

      +

      请求参数

      参数
      @@ -5328,7 +5537,7 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5369,9 +5578,9 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq
      curl -X GET \
       http://localhost:3000/api/jasder/forgeplus/about  | jq
       
      await octokit.request('GET /api/jasder/forgeplus/about')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/:owner/:repo/about

      -

      请求参数

      +

      请求参数

      参数
      @@ -5396,7 +5605,7 @@ http://localhost:3000/api/jasder/forgeplus/about | jq
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5442,7 +5651,7 @@ Remember — a happy kitten is an authenticated kitten!
      curl -X GET \
       http://localhost:3000/api/yystopf/ceshi/project_units.json
       
      await octokit.request('GET /api/yystopf/ceshi/project_units')
      -

      HTTP 请求

      +

      HTTP 请求

      GET /api/yystopf/ceshi/project_units

      返回字段说明:

      参数
      @@ -5485,9 +5694,9 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json -d"{ \"unit_typs\": [\"code\", \"pulls\"]}"\ http://localhost:3000/api/yystopf/ceshi/project_units.json
      await octokit.request('POST /api/yystopf/ceshi/project_units')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/yystopf/ceshi/project_units

      -

      请求参数

      +

      请求参数

      @@ -5549,9 +5758,9 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json -d"license_id=1"\ http://localhost:3000/api/projects.json
      await octokit.request('GET /api/projects.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/projects

      -

      请求参数

      +

      请求参数

      参数
      @@ -5625,7 +5834,7 @@ http://localhost:3000/api/projects.json
      参数项目是否私有, true:为私有,false: 公开,默认为公开
      -

      返回字段说明

      +

      返回字段说明

      @@ -5667,9 +5876,9 @@ http://localhost:3000/api/projects.json -d"project_language_id=2"\ http://localhost:3000/api/projects/migrate.json
      await octokit.request('GET /api/projects/migrate.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/projects/migrate.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5757,7 +5966,7 @@ http://localhost:3000/api/projects/migrate.json
      参数项目是否私有, true:为私有,false: 非私有,默认为公开
      -

      返回字段说明

      +

      返回字段说明

      @@ -5792,9 +6001,9 @@ http://localhost:3000/api/projects/migrate.json
      curl -X POST http://localhost:3000/api/repositories/1244/sync_mirror.json
       
      await octokit.request('POST /api/repositories/1244/sync_mirror.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/repositories/:id/sync_mirror.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5812,7 +6021,7 @@ http://localhost:3000/api/projects/migrate.json
      参数仓库id
      -

      返回字段说明

      +

      返回字段说明

      @@ -5847,9 +6056,9 @@ http://localhost:3000/api/projects/migrate.json
      curl -X POST http://localhost:3000/api/jasder/forgeplus/forks.json
       
      await octokit.request('POST /api/jaser/jasder_test/forks.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST api/:owner/:repo/forks.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -5874,7 +6083,7 @@ http://localhost:3000/api/projects/migrate.json
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -5910,9 +6119,9 @@ http://localhost:3000/api/projects/migrate.json
      curl -X GET \
       http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizations.json  | jq
       
      await octokit.request('GET /api/:owner/:repo/applied_transfer_projects/organizations')
      -

      HTTP 请求

      +

      HTTP 请求

      GET api/:owner/:repo/applied_transfer_projects/organizations

      -

      请求参数

      +

      请求参数

      参数
      @@ -5937,7 +6146,7 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -6004,9 +6213,9 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects.json
       
      await octokit.request('POST /api/:owner/:repo/applied_transfer_projects.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/:owner/:repo/applied_transfer_projects.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -6038,7 +6247,7 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      参数迁移对象标识
      -

      返回字段说明

      +

      返回字段说明

      @@ -6208,9 +6417,9 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/cancel.json
       
      await octokit.request('POST /api/:owner/:repo/applied_transfer_projects/cancel.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/:owner/:repo/applied_transfer_projects/cancel.json

      -

      请求参数

      +

      请求参数

      参数
      @@ -6235,7 +6444,7 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      参数项目标识identifier
      -

      返回字段说明

      +

      返回字段说明

      @@ -6405,9 +6614,9 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat
      curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/quit.json
       
      await octokit.request('POST /api/:owner/:repo/quit.json')
      -

      HTTP 请求

      +

      HTTP 请求

      POST /api/:owner/:repo/quit.json

      -

      请求参数

      +

      请求参数

      参数
      From bed24690145120790e0ce7aeadd7db01a36be36a Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 20 Jun 2022 10:34:25 +0800 Subject: [PATCH 4/5] fix: change error --- Gemfile.lock | 2 +- ...0617103002_change_oauth_access_tokens_token_column_length.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 99f40ad94..e27c504aa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -106,7 +106,7 @@ GEM activerecord (>= 3.1.0, < 7) diff-lcs (1.3) diffy (3.3.0) - doorkeeper (5.5.4) + doorkeeper (5.5.1) railties (>= 5) doorkeeper-jwt (0.4.1) jwt (>= 2.1) diff --git a/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb b/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb index 9c78ac285..f387e6ea7 100644 --- a/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb +++ b/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb @@ -1,5 +1,5 @@ class ChangeOauthAccessTokensTokenColumnLength < ActiveRecord::Migration[5.2] def change - change_column :oauth_access_tokens, :token, :string, limit: 500 + change_column :oauth_access_tokens, :token, :text end end From 531495429ce7ad95b91d6f758de1c133dd7aa269 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 20 Jun 2022 13:05:25 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E6=9B=B4=E6=94=B9token=E9=95=BF=E5=BA=A6?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/migrate/20220616040105_create_doorkeeper_tables.rb | 6 +++--- ...103002_change_oauth_access_tokens_token_column_length.rb | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb diff --git a/db/migrate/20220616040105_create_doorkeeper_tables.rb b/db/migrate/20220616040105_create_doorkeeper_tables.rb index b4ec636ed..890b31d80 100644 --- a/db/migrate/20220616040105_create_doorkeeper_tables.rb +++ b/db/migrate/20220616040105_create_doorkeeper_tables.rb @@ -48,8 +48,8 @@ class CreateDoorkeeperTables < ActiveRecord::Migration[5.2] # characters. More info on custom token generators in: # https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator # - # t.text :token, null: false - t.string :token, null: false + t.text :token, null: false + # t.string :token, null: false t.string :refresh_token t.integer :expires_in @@ -73,7 +73,7 @@ class CreateDoorkeeperTables < ActiveRecord::Migration[5.2] t.string :previous_refresh_token, null: false, default: "" end - add_index :oauth_access_tokens, :token, unique: true + # add_index :oauth_access_tokens, :token, unique: true add_index :oauth_access_tokens, :refresh_token, unique: true add_foreign_key( :oauth_access_tokens, diff --git a/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb b/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb deleted file mode 100644 index f387e6ea7..000000000 --- a/db/migrate/20220617103002_change_oauth_access_tokens_token_column_length.rb +++ /dev/null @@ -1,5 +0,0 @@ -class ChangeOauthAccessTokensTokenColumnLength < ActiveRecord::Migration[5.2] - def change - change_column :oauth_access_tokens, :token, :text - end -end
      参数