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
当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接)
@@ -4409,6 +4412,31 @@ Success — a happy kitten is an authenticated kitten!await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_link.json')
HTTP 请求
+
GET /api/:owner/:repo/project_invite_links/current_link.json
请求参数
++
+ + +参数 +必选 +默认 +类型 +字段说明 ++ +role +是 ++ string +项目权限,reporter: 报告者, developer: 开发者,manager:管理员 ++ +is_apply +是 ++ boolean +是否需要审核 +返回字段说明
@@ -4438,6 +4466,11 @@ Success — a happy kitten is an authenticated kitten! 邀请标识(放在链接后面即可) + +expired_at +string +链接过期时间 +user.id int 链接创建者的id @@ -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
请求参数
+请求参数
参数 @@ -4616,6 +4650,11 @@ Success — a happy kitten is an authenticated kitten!邀请标识(放在链接后面即可) + +expired_at +string +链接过期时间 +user.id int 链接创建者的id @@ -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
请求参数
++
++ + +参数 +必选 +默认 +类型 +字段说明 ++ +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示例:
+{ + "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 | jqawait 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 | jqcurl -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.jsonawait 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.jsonawait 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.jsoncurl -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.jsoncurl -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.jsoncurl -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/organizatcurl -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/organizatcurl -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/organizatcurl -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
请求参数
+请求参数
参数