Merge branch 'develop' into dev_trustie_server

This commit is contained in:
jasder 2021-04-27 18:24:41 +08:00
commit ba9848ebe7
33 changed files with 2427 additions and 9 deletions

View File

@ -0,0 +1,26 @@
class Projects::AppliedTransferProjectsController < Projects::BaseController
before_action :check_auth
def organizations
@organizations = Organization.includes(:organization_extension).joins(team_users: :team).where(team_users: {user_id: current_user.id}, teams: {authorize: %w(admin owner)})
end
def create
@applied_transfer_project = Projects::ApplyTransferService.call(current_user, @project, params)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def cancel
@applied_transfer_project = Projects::CancelTransferService.call(current_user, @project)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def check_auth
return render_forbidden unless current_user.admin? ||@project.owner?(current_user)
end
end

View File

@ -0,0 +1,18 @@
class Users::AppliedMessagesController < Users::BaseController
before_action :check_auth
after_action :view_messages, only: [:index]
def index
@applied_messages = @_observed_user.applied_messages.order(viewed: :asc, created_at: :desc)
@applied_messages = paginate @applied_messages
end
private
def check_auth
return render_forbidden unless observed_logged_user?
end
def view_messages
@applied_messages.update_all(viewed: 'viewed')
end
end

View File

@ -0,0 +1,41 @@
class Users::AppliedTransferProjectsController < Users::BaseController
before_action :check_auth
before_action :find_applied_transfer_project, except: [:index]
before_action :find_project, except: [:index]
def index
user_collection_sql = AppliedTransferProject.where(owner_id: @_observed_user.id).to_sql
org_collection_sql = AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @_observed_user.id}, teams: {authorize: %w(admin owner)} )).to_sql
@applied_transfer_projects = AppliedTransferProject.from("( #{ user_collection_sql } UNION #{ org_collection_sql } ) AS applied_transfer_projects")
@applied_transfer_projects = paginate @applied_transfer_projects.order("created_at desc")
end
# 接受迁移
def accept
@applied_transfer_project = Projects::AcceptTransferService.call(current_user, @project)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
# 拒绝迁移
def refuse
@applied_transfer_project = Projects::RefuseTransferService.call(current_user, @project)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def check_auth
return render_forbidden unless observed_logged_user?
end
def find_applied_transfer_project
@applied_transfer_project = AppliedTransferProject.find_by_id params[:id]
end
def find_project
@project = @applied_transfer_project.project
end
end

View File

@ -27,11 +27,20 @@ class UsersController < ApplicationController
def show
#待办事项,现在未做
@undo_events = 0
if User.current.login == @user.login
@waiting_applied_messages = @user.applied_messages.waiting
@common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @user.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @user.id}, teams: {authorize: %w(admin owner)} )).common
@undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size
else
@waiting_applied_messages = AppliedMessage.none
@common_applied_transfer_projects = AppliedTransferProject.none
@undo_events = 0
end
#用户的组织数量
# @user_composes_count = @user.composes.size
@user_composes_count = 0
@user_org_count = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)).size + @user.organizations.with_visibility("privacy").joins(:organization_users).where(organization_users: {user_id: current_user.id}).size : @user.organizations.with_visibility("common").size
user_organizations = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)) + @user.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @user.organizations.with_visibility("common")
@user_org_count = user_organizations.size
user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? @user.projects : @user.projects.visible
@projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size

View File

@ -526,3 +526,241 @@ await octokit.request('POST /api/jaser/jasder_test/forks.json')
"identifier": "newadm"
}
```
## 用户管理的组织列表
用户管理的组织列表
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizations.json | jq
```
```javascript
await octokit.request('GET /api/:owner/:repo/applied_transfer_projects/organizations')
```
### HTTP 请求
`GET api/:owner/:repo/applied_transfer_projects/organizations`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是| |string |用户登录名
repo |是| |string |项目标识identifier
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
name |string|组织标识
nickname |string|组织名称
description|string|组织描述
avatar_url|string组织头像
> 返回的JSON示例:
```json
{
"total_count": 3,
"organizations": [
{
"id": 9,
"name": "ceshi_org",
"nickname": "测试组织",
"description": "测试组织",
"avatar_url": "images/avatars/Organization/9?t=1612706073"
},
{
"id": 51,
"name": "ceshi",
"nickname": "测试组织哈哈哈",
"description": "23212312",
"avatar_url": "images/avatars/Organization/51?t=1618800723"
},
{
"id": 52,
"name": "ceshi1",
"nickname": "身份卡手动阀",
"description": "1231手动阀是的",
"avatar_url": "images/avatars/Organization/52?t=1618805056"
}
]
}
```
## 迁移项目
迁移项目edit接口is_transfering为true表示正在迁移
> 示例:
```shell
curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects.json
```
```javascript
await octokit.request('POST /api/:owner/:repo/applied_transfer_projects.json')
```
### HTTP 请求
`POST /api/:owner/:repo/applied_transfer_projects.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
|owner_name|是| |string |迁移对象标识 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |项目id |
|status |string |项目迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |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 |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 9,
"type": "Organization",
"name": "测试组织",
"login": "ceshi_org",
"image_url": "images/avatars/Organization/9?t=1612706073"
},
"id": 4,
"status": "common",
"created_at": "2021-04-26 09:54",
"time_ago": "1分钟前"
}
```
## 取消迁移项目
迁移项目edit接口is_transfering为true表示正在迁移
> 示例:
```shell
curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/cancel.json
```
```javascript
await octokit.request('POST /api/:owner/:repo/applied_transfer_projects/cancel.json')
```
### HTTP 请求
`POST /api/:owner/:repo/applied_transfer_projects/cancel.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |迁移id |
|status |string |迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |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 |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 9,
"type": "Organization",
"name": "测试组织",
"login": "ceshi_org",
"image_url": "images/avatars/Organization/9?t=1612706073"
},
"id": 4,
"status": "common",
"created_at": "2021-04-26 09:54",
"time_ago": "1分钟前"
}
```

View File

@ -1,3 +1,9 @@
<!--
* @Date: 2021-03-01 10:35:21
* @LastEditors: viletyy
* @LastEditTime: 2021-04-26 10:47:30
* @FilePath: /forgeplus/app/docs/slate/source/includes/_users.md
-->
# Users
## 获取当前登陆用户信息
@ -40,3 +46,390 @@ await octokit.request('GET /api/users/me.json')
<aside class="success">
Success Data.
</aside>
## 待办事项-用户通知信息
待办事项-用户通知信息
> 示例:
```shell
curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
```
```javascript
await octokit.request('GET /api/users/:login/applied_messages.json')
```
### HTTP 请求
`GET /api/users/:login/applied_messages.json`
### 请求字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|login |string |用户标识 |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|applied |object |通知主体 |
|applied.id |int |通知主体的迁移id |
|applied.status |string |通知主体的迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|applied.time_ago |string |通知主体的迁移创建的时间 |
|applied.project.id |int |通知主体的迁移项目的id |
|applied.project.identifier |string |通知主体的迁移项目的标识 |
|applied.project.name |string |通知主体的迁移项目的名称 |
|applied.project.description |string |通知主体的迁移项目的描述 |
|applied.project.is_public |bool |通知主体的迁移项目是否公开 |
|applied.project.owner.id |bool |通知主体的迁移项目拥有者id |
|applied.project.owner.type |string |通知主体的迁移项目拥有者类型 |
|applied.project.owner.name |string |通知主体的迁移项目拥有者昵称 |
|applied.project.owner.login |string |通知主体的迁移项目拥有者标识 |
|applied.project.owner.image_url |string |通知主体的迁移项目拥有者头像 |
|applied.user.id |int |通知主体的迁移创建者的id |
|applied.user.type |string |通知主体的迁移创建者的类型 |
|applied.user.name |string |通知主体的迁移创建者的名称 |
|applied.user.login |string |通知主体的迁移创建者的标识 |
|applied.user.image_url |string |通知主体的迁移创建者头像 |
|applied.owner.id |int |通知主体的迁移接受者的id |
|applied.owner.type |string |通知主体的迁移接受者的类型 |
|applied.owner.name |string |通知主体的迁移接受者的名称 |
|applied.owner.login |string |通知主体的迁移接受者的标识 |
|applied.owner.image_url |string |通知主体的迁移接受者头像 |
|applied_type |string |通知类型 |
|name |string | 通知内容 |
|viewed |string|是否已读waiting:未读,viewed:已读|
|status |string|通知状态, canceled:已取消,common: 正常,successed:成功,failure:失败|
|time_ago |string|通知时间|
> 返回的JSON示例:
```json
{
"total_count": 5,
"applied_messages": [
{
"applied": {
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 9,
"type": "Organization",
"name": "测试组织",
"login": "ceshi_org",
"image_url": "images/avatars/Organization/9?t=1612706073"
},
"id": 4,
"status": "common",
"created_at": "2021-04-26 09:54",
"time_ago": "35分钟前"
},
"applied_user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"applied_type": "AppliedTransferProject",
"name": "正在将【测试项目啊1】仓库转移给【测试组织】",
"viewed": "viewed",
"status": "common",
"created_at": "2021-04-26 09:54",
"time_ago": "35分钟前"
},
...
]
}
```
## 待办事项-接受仓库
待办事项-接受仓库
> 示例:
```shell
curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
```
```javascript
await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
```
### HTTP 请求
`GET /api/users/:login/applied_transfer_projects.json`
### 请求字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|login |string |用户标识 |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |迁移id |
|status |string |迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |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 |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"total_count": 4,
"applied_transfer_projects": [
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
},
"id": 1,
"status": "canceled",
"created_at": "2021-04-25 18:06",
"time_ago": "16小时前"
},
...
]
}
```
## 用户接受迁移
用户接受迁移
> 示例:
```shell
curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
```
```javascript
await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
```
### HTTP 请求
`GET /api/users/:login/applied_transfer_projects/:id/accept.json`
### 请求字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|login |string |用户标识 |
|id |int |迁移id |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |迁移id |
|status |string |迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |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 |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
},
"id": 1,
"status": "canceled",
"created_at": "2021-04-25 18:06",
"time_ago": "16小时前"
}
```
## 用户拒绝迁移
用户拒绝迁移
> 示例:
```shell
curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
```
```javascript
await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
```
### HTTP 请求
`GET /api/users/:login/applied_transfer_projects/:id/refuse.json`
### 请求字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|login |string |用户标识 |
|id |int |迁移id |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |迁移id |
|status |string |迁移状态canceled:取消,common:正在迁移, accept:已接受,refuse:已拒绝|
|time_ago |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 |迁移项目拥有者头像 |
|user.id |int |迁移创建者的id |
|user.type |string |迁移创建者的类型 |
|user.name |string |迁移创建者的名称 |
|user.login |string |迁移创建者的标识 |
|user.image_url |string |迁移创建者头像 |
|owner.id |int |迁移接受者的id |
|owner.type |string |迁移接受者的类型 |
|owner.name |string |迁移接受者的名称 |
|owner.login |string |迁移接受者的标识 |
|owner.image_url |string |迁移接受者头像 |
> 返回的JSON示例:
```json
{
"project": {
"id": 86,
"identifier": "ceshi_repo1",
"name": "测试项目啊1",
"description": "二十多",
"is_public": true,
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
}
},
"user": {
"id": 6,
"type": "User",
"name": "yystopf",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/Y/241_125_89/120.png"
},
"owner": {
"id": 52,
"type": "Organization",
"name": "身份卡手动阀",
"login": "ceshi1",
"image_url": "images/avatars/Organization/52?t=1618805056"
},
"id": 1,
"status": "canceled",
"created_at": "2021-04-25 18:06",
"time_ago": "16小时前"
}
```

View File

@ -0,0 +1,47 @@
class SendTransferProjectAppliedMessageJob < ApplicationJob
queue_as :default
def perform(applied_transfer_project, applied_user, message_status)
project = applied_transfer_project.project
owner = project.owner
return unless project.present?
return unless owner.present?
if owner.is_a?(Organization)
receivers = project.managers + owner.team_users.joins(:team).where(teams: {authorize: %w(owner admin)})
else
receivers = project.managers
end
receivers.each do |rec|
next if applied_user.id == rec.user_id # 自己不要给自己发通知
AppliedMessage.create!(user_id: rec.user_id,
applied: applied_transfer_project,
status: message_status,
name: build_name(project.name, applied_transfer_project&.owner&.real_name, message_status, applied_user&.real_name),
applied_user_id: applied_user.id,
project_id: project.id)
end
if message_status == 'successed' # 如果转移成功,给转移发起者发通知已转移成功
AppliedMessage.find_or_create_by!(user_id: applied_transfer_project.user_id,
applied: applied_transfer_project,
status: message_status,
name: build_name(project.name, applied_transfer_project&.owner&.real_name, message_status),
applied_user_id: applied_user.id,
project_id: project.id)
end
end
private
def build_name(repo_name, owner_name, message_status, applied_name="")
case message_status
when 'canceled'
return "取消转移【#{repo_name}】仓库"
when 'common'
return "正在将【#{repo_name}】仓库转移给【#{owner_name}"
when 'successed'
return "#{repo_name}】仓库成功转移给【#{owner_name}"
when 'failure'
return "拒绝转移【#{repo_name}】仓库"
end
""
end
end

View File

@ -19,5 +19,10 @@
class AppliedMessage < ApplicationRecord
belongs_to :user
belongs_to :applied, polymorphic: true
belongs_to :project
belongs_to :applied_user, class_name: 'User'
enum viewed: {waiting: 0, viewed: 1}
enum status: {canceled: -1, common: 0, successed: 1, failure: 2} # -1 已取消 0 正在操作 1 操作成功 2 操作失败
end

View File

@ -0,0 +1,28 @@
# == Schema Information
#
# Table name: applied_transfer_projects
#
# id :integer not null, primary key
# project_id :integer
# owner_id :integer
# user_id :integer
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_applied_transfer_projects_on_owner_id (owner_id)
# index_applied_transfer_projects_on_project_id (project_id)
# index_applied_transfer_projects_on_user_id (user_id)
#
class AppliedTransferProject < ApplicationRecord
belongs_to :project
belongs_to :user # 操作者
belongs_to :owner # 接收个人或组织
has_many :applied_messages, as: :applied, dependent: :destroy
enum status: {canceled: -1, common: 0, accepted: 1, refused: 2} # -1 已取消 0 待操作 1 已接收 2 已拒绝
end

View File

@ -66,4 +66,6 @@ class Owner < ApplicationRecord
has_many :projects, foreign_key: :user_id, dependent: :destroy
has_many :repositories, foreign_key: :user_id, dependent: :destroy
has_many :applied_transfer_projects, dependent: :destroy
end

View File

@ -112,6 +112,7 @@ class Project < ApplicationRecord
has_one :project_detail, dependent: :destroy
has_many :team_projects, dependent: :destroy
has_many :project_units, dependent: :destroy
has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy
after_save :check_project_members
scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
@ -295,4 +296,7 @@ class Project < ApplicationRecord
update_column(:updated_on, time)
end
def is_transfering
applied_transfer_project&.common? ? true : false
end
end

View File

@ -148,9 +148,11 @@ class User < Owner
has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction'
# has_many :attendances
has_many :applied_messages, dependent: :destroy
has_many :operate_applied_messages, class_name: 'AppliedMessage', dependent: :destroy
# 项目
has_many :applied_projects, dependent: :destroy
has_many :operate_applied_transfer_projects, class_name: 'AppliedTransferProject', dependent: :destroy
# 教学案例
# has_many :libraries, dependent: :destroy

View File

@ -0,0 +1,49 @@
class Projects::AcceptTransferService < ApplicationService
attr_accessor :applied_transfer_project, :owner
attr_reader :user, :project
def initialize(user, project)
@user = user
@project = project
@applied_transfer_project = project.applied_transfer_project
@owner = @applied_transfer_project.owner
end
def call
Rails.logger.info("###### Project accept_transfer_service begin ######")
ActiveRecord::Base.transaction do
validate!
update_apply
operate_project
send_apply_message
end
Rails.logger.info("##### Project accept_transfer_service end ######")
return @applied_transfer_project
end
private
def validate!
raise Error, '该仓库未在迁移' unless @applied_transfer_project.present? && @project.is_transfering
raise Error, '未拥有接受转移权限' unless is_permit_operator
end
def is_permit_operator
return true if @user == @owner
return @owner.is_a?(Organization) && @owner.is_admin?(@user)
end
def update_apply
@applied_transfer_project.update!(status: 'accepted')
end
def operate_project
@project = Projects::TransferService.call(@project, @owner)
end
def send_apply_message
SendTransferProjectAppliedMessageJob.perform_now(@applied_transfer_project, @user, 'successed')
end
end

View File

@ -0,0 +1,43 @@
class Projects::ApplyTransferService < ApplicationService
attr_accessor :owner, :applied_transfer_project
attr_reader :user, :project, :params
def initialize(user, project, params)
@user = user
@project = project
@params = params
@owner = Owner.find_by(login: params[:owner_name])
end
def call
Rails.logger.info("###### Project apply_transfer_service begin ######")
validate!
create_apply
send_apply_message
Rails.logger.info("###### Project apply_transfer_service end ######")
return @applied_transfer_project
end
private
def validate!
raise Error, '仓库标识不正确' if @project.identifier != params[:identifier]
raise Error, '该仓库正在迁移' if @project.is_transfering
raise Error, '新拥有者不存在' unless @owner.present?
raise Error, '新拥有者已经存在同名仓库!' if Project.where(user_id: @owner.id, identifier: params[:identifier]).present?
raise Error, '未拥有转移权限' unless is_permit_owner
end
def is_permit_owner
return true unless @owner.is_a?(Organization)
return @owner.is_owner?(@user)
end
def create_apply
@applied_transfer_project = AppliedTransferProject.create!(user_id: user.id, project_id: project.id, owner_id: @owner.id)
end
def send_apply_message
SendTransferProjectAppliedMessageJob.perform_now(@applied_transfer_project, @user, 'common')
end
end

View File

@ -0,0 +1,33 @@
class Projects::CancelTransferService < ApplicationService
attr_accessor :applied_transfer_project
attr_reader :user, :project
def initialize(user, project)
@user = user
@project = project
@applied_transfer_project = project.applied_transfer_project
end
def call
Rails.logger.info("###### Project cancel_transfer_service begin ######")
validate!
update_apply
send_apply_message
Rails.logger.info("###### Project cancel_transfer_service end ######")
return @applied_transfer_project
end
private
def validate!
raise Error, '该仓库未在迁移' unless @applied_transfer_project.present? && @project.is_transfering
end
def update_apply
@applied_transfer_project.update!(status: 'canceled')
end
def send_apply_message
SendTransferProjectAppliedMessageJob.perform_now(@applied_transfer_project, @user, 'canceled')
end
end

View File

@ -0,0 +1,40 @@
class Projects::RefuseTransferService < ApplicationService
attr_accessor :applied_transfer_project, :owner
attr_reader :user, :project
def initialize(user, project)
@user = user
@project = project
@applied_transfer_project = project.applied_transfer_project
@owner = @applied_transfer_project.owner
end
def call
Rails.logger.info("###### Project refuse_transfer_service begin ######")
validate!
update_apply
send_apply_message
Rails.logger.info("###### Project refuse_transfer_service end ######")
return @applied_transfer_project
end
private
def validate!
raise Error, '该仓库未在迁移' unless @applied_transfer_project.present? && @project.is_transfering
raise Error, '未拥有拒绝转移权限' unless is_permit_operator
end
def is_permit_operator
return true if @user == @owner
return @owner.is_a?(Organization) && @owner.is_admin?(@user)
end
def update_apply
@applied_transfer_project.update!(status: 'refused')
end
def send_apply_message
SendTransferProjectAppliedMessageJob.perform_now(@applied_transfer_project, @user, 'failure')
end
end

View File

@ -23,6 +23,7 @@ class Projects::TransferService < ApplicationService
private
def update_owner
project.members.find_by(user_id: owner.id).destroy! if owner.is_a?(User)
project.update!(user_id: new_owner.id)
end

View File

@ -0,0 +1,5 @@
json.id organization.id
json.name organization.login
json.nickname organization.nickname.blank? ? organization.name : organization.nickname
json.description organization.description
json.avatar_url url_to_avatar(organization)

View File

@ -0,0 +1,21 @@
project = object.project
json.project do
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
end
json.user do
json.partial! "/users/user_simple", locals: {user: object.user}
end
json.owner do
json.partial! "/users/user_simple", locals: {user: object.owner}
end
json.id object.id
json.status object.status
json.created_at format_time(object.created_at)
json.time_ago time_from_now(object.created_at)

View File

@ -0,0 +1 @@
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}

View File

@ -0,0 +1 @@
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}

View File

@ -0,0 +1,4 @@
json.total_count @organizations.size
json.organizations @organizations do |org|
json.partial! "/organizations/organizations/simple", locals: {organization: org}
end

View File

@ -7,4 +7,9 @@ json.project_language_id @project.project_language_id
json.private !@project.is_public
json.website @project.website
json.project_units @project.project_units.pluck(:unit_type)
json.lesson_url @project.lesson_url
json.lesson_url @project.lesson_url
json.permission render_permission(current_user, @project)
json.is_transfering @project.is_transfering
json.transfer do
json.partial! "/users/user_simple", locals: {user: @project&.applied_transfer_project&.owner}
end

View File

@ -1,4 +1,9 @@
json.id user.id
json.name user.real_name
json.login user.login
json.image_url url_to_avatar(user)
if user.present?
json.id user.id
json.type user.type
json.name user.real_name
json.login user.login
json.image_url url_to_avatar(user)
else
json.nil!
end

View File

@ -0,0 +1,26 @@
# project = object.project
# json.project do
# 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
# end
# json.user do
# json.partial! "/users/user_simple", locals: {user: object.user}
# end
json.applied do
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: object.applied}
end
json.applied_user do
json.partial! "/users/user_simple", locals: {user: object.applied_user}
end
json.applied_type object.applied_type
json.name object.name
json.viewed object.viewed
json.status object.status
json.created_at format_time(object.created_at)
json.time_ago time_from_now(object.created_at)

View File

@ -0,0 +1,4 @@
json.total_count @applied_messages.total_count
json.applied_messages @applied_messages do |message|
json.partial! "/users/applied_messages/detail", locals: {object: message}
end

View File

@ -0,0 +1 @@
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}

View File

@ -0,0 +1,4 @@
json.total_count @applied_transfer_projects.total_count
json.applied_transfer_projects @applied_transfer_projects do |apply|
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: apply}
end

View File

@ -0,0 +1 @@
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}

View File

@ -10,6 +10,8 @@ json.user_identity @user.identity
json.is_watch current_user&.watched?(@user)
json.watched_count @user.fan_count #粉丝
json.watching_count @user.follow_count #关注数
json.undo_messages @waiting_applied_messages.size
json.undo_transfer_projects @common_applied_transfer_projects.size
json.undo_events @undo_events
json.user_composes_count @user_composes_count
json.user_org_count @user_org_count

View File

@ -257,6 +257,13 @@ Rails.application.routes.draw do
end
scope module: :users do
resources :applied_messages, only: [:index]
resources :applied_transfer_projects, only: [:index] do
member do
post :accept
post :refuse
end
end
resources :organizations, only: [:index]
# resources :projects, only: [:index]
# resources :subjects, only: [:index]
@ -533,6 +540,12 @@ Rails.application.routes.draw do
scope module: :projects do
resources :teams, only: [:index, :create, :destroy]
resources :project_units, only: [:index, :create]
resources :applied_transfer_projects, only: [:create] do
collection do
get :organizations
post :cancel
end
end
scope do
get(
'/blob/*id/diff',

View File

@ -0,0 +1,12 @@
class CreateAppliedTransferProjects < ActiveRecord::Migration[5.2]
def change
create_table :applied_transfer_projects do |t|
t.references :project
t.references :owner
t.references :user
t.integer :status, default: 0
t.timestamps
end
end
end

File diff suppressed because it is too large Load Diff