mirror of
https://gitlink.org.cn/Gitlink/forgeplus.git
synced 2026-05-03 03:40:49 +08:00
add: applied join project
This commit is contained in:
13
app/controllers/applied_projects_controller.rb
Normal file
13
app/controllers/applied_projects_controller.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class AppliedProjectsController < ApplicationController
|
||||
before_action :require_login
|
||||
def create
|
||||
@applied_project = Projects::ApplyJoinService.call(current_user, applied_params)
|
||||
rescue Projects::ApplyJoinService::Error => ex
|
||||
render_error(ex.message)
|
||||
end
|
||||
|
||||
private
|
||||
def applied_params
|
||||
params.require(:applied_project).permit(:code, :role)
|
||||
end
|
||||
end
|
||||
@@ -9,7 +9,7 @@ class Users::AppliedMessagesController < Users::BaseController
|
||||
|
||||
private
|
||||
def check_auth
|
||||
return render_forbidden unless observed_logged_user?
|
||||
return render_forbidden unless current_user.admin? || observed_logged_user?
|
||||
end
|
||||
|
||||
def view_messages
|
||||
|
||||
39
app/controllers/users/applied_projects_controller.rb
Normal file
39
app/controllers/users/applied_projects_controller.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
class Users::AppliedProjectsController < Users::BaseController
|
||||
before_action :check_auth
|
||||
before_action :find_applied_project, except: [:index]
|
||||
before_action :find_project, except: [:index]
|
||||
|
||||
def index
|
||||
@applied_projects = AppliedProject.where(project_id: observed_user.full_admin_projects)
|
||||
@applied_projects = paginate @applied_projects.order("created_at desc")
|
||||
end
|
||||
|
||||
# 接受申请
|
||||
def accept
|
||||
@applied_project = Projects::AcceptJoinService.call(current_user, @applied_project)
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
# 拒绝申请
|
||||
def refuse
|
||||
@applied_project = Projects::RefuseJoinService.call(current_user, @applied_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? || observed_logged_user?
|
||||
end
|
||||
|
||||
def find_applied_project
|
||||
@applied_project = AppliedProject.find_by_id params[:id]
|
||||
end
|
||||
|
||||
def find_project
|
||||
@project = @applied_project.project
|
||||
end
|
||||
end
|
||||
@@ -28,7 +28,7 @@ class Users::AppliedTransferProjectsController < Users::BaseController
|
||||
|
||||
private
|
||||
def check_auth
|
||||
return render_forbidden unless observed_logged_user?
|
||||
return render_forbidden unless current_user.admin? || observed_logged_user?
|
||||
end
|
||||
|
||||
def find_applied_transfer_project
|
||||
|
||||
@@ -1,5 +1,91 @@
|
||||
# Projects
|
||||
|
||||
## 申请加入项目
|
||||
申请加入项目
|
||||
|
||||
> 示例:
|
||||
|
||||
```shell
|
||||
curl -X POST http://localhost:3000/api/applied_projects.json
|
||||
```
|
||||
|
||||
```javascript
|
||||
await octokit.request('POST /api/appliedr_projects.json')
|
||||
```
|
||||
|
||||
### HTTP 请求
|
||||
`POST /api/applied_projects.json`
|
||||
|
||||
### 请求参数
|
||||
参数 | 必选 | 默认 | 类型 | 字段说明
|
||||
--------- | ------- | ------- | -------- | ----------
|
||||
|applied_project.code |是| |string |邀请码 |
|
||||
|applied_project.role |否| |string |项目权限,reporter: 报告者, developer: 开发者,manager:管理员 |
|
||||
|
||||
> 请求的JSON示例
|
||||
|
||||
```json
|
||||
{
|
||||
"applied_project": {
|
||||
"code": "1una34",
|
||||
"role": "developer"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 返回字段说明
|
||||
参数 | 类型 | 字段说明
|
||||
--------- | ----------- | -----------
|
||||
|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 |申请创建者头像 |
|
||||
> 返回的JSON示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"project": {
|
||||
"id": 74,
|
||||
"identifier": "hehuisssjssjjsjs",
|
||||
"name": "hehuisssjssjjsjs",
|
||||
"description": "wwww",
|
||||
"is_public": false,
|
||||
"owner": {
|
||||
"id": 10,
|
||||
"type": "User",
|
||||
"name": "testforge1",
|
||||
"login": "testforge1",
|
||||
"image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": 6,
|
||||
"type": "User",
|
||||
"name": "何慧",
|
||||
"login": "yystopf",
|
||||
"image_url": "images/avatars/User/6?t=1622513134"
|
||||
},
|
||||
"id": 7,
|
||||
"status": "common",
|
||||
"created_at": "2021-06-09 16:41",
|
||||
"time_ago": "1分钟前"
|
||||
}
|
||||
```
|
||||
|
||||
## 获取项目列表
|
||||
获取项目列表,也可以更加相关条件过滤搜素
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!--
|
||||
* @Date: 2021-03-01 10:35:21
|
||||
* @LastEditors: viletyy
|
||||
* @LastEditTime: 2021-06-03 10:18:53
|
||||
* @LastEditTime: 2021-06-09 16:51:18
|
||||
* @FilePath: /forgeplus/app/docs/slate/source/includes/_users.md
|
||||
-->
|
||||
# Users
|
||||
@@ -1002,11 +1002,11 @@ await octokit.request('GET /api/users/:login/applied_messages.json')
|
||||
|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_user.id |int |通知发起者的id |
|
||||
|applied_user.type |string |通知发起者的类型 |
|
||||
|applied_user.name |string |通知发起者的名称 |
|
||||
|applied_user.login |string |通知发起者的标识 |
|
||||
|applied_user.image_url |string |通知发起者头像 |
|
||||
|applied_type |string |通知类型 |
|
||||
|name |string | 通知内容 |
|
||||
|viewed |string|是否已读,waiting:未读,viewed:已读|
|
||||
@@ -1020,6 +1020,48 @@ await octokit.request('GET /api/users/:login/applied_messages.json')
|
||||
{
|
||||
"total_count": 5,
|
||||
"applied_messages": [
|
||||
{
|
||||
"applied": {
|
||||
"project": {
|
||||
"id": 74,
|
||||
"identifier": "hehuisssjssjjsjs",
|
||||
"name": "hehuisssjssjjsjs",
|
||||
"description": "wwww",
|
||||
"is_public": false,
|
||||
"owner": {
|
||||
"id": 10,
|
||||
"type": "User",
|
||||
"name": "testforge1",
|
||||
"login": "testforge1",
|
||||
"image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": 6,
|
||||
"type": "User",
|
||||
"name": "何慧",
|
||||
"login": "yystopf",
|
||||
"image_url": "images/avatars/User/6?t=1622513134"
|
||||
},
|
||||
"id": 6,
|
||||
"status": "accepted",
|
||||
"created_at": "2021-06-09 16:34",
|
||||
"time_ago": "1分钟前"
|
||||
},
|
||||
"applied_user": {
|
||||
"id": 6,
|
||||
"type": "User",
|
||||
"name": "何慧",
|
||||
"login": "yystopf",
|
||||
"image_url": "images/avatars/User/6?t=1622513134"
|
||||
},
|
||||
"applied_type": "AppliedProject",
|
||||
"name": "已通过你加入【hehuisssjssjjsjs】仓库的申请。",
|
||||
"viewed": "waiting",
|
||||
"status": "successed",
|
||||
"created_at": "2021-06-09 16:34",
|
||||
"time_ago": "1分钟前"
|
||||
},
|
||||
{
|
||||
"applied": {
|
||||
"project": {
|
||||
@@ -1344,4 +1386,240 @@ await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refus
|
||||
"created_at": "2021-04-25 18:06",
|
||||
"time_ago": "16小时前"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 待办事项-项目申请
|
||||
待办事项-项目申请
|
||||
|
||||
> 示例:
|
||||
|
||||
```shell
|
||||
curl -X GET http://localhost:3000/api/users/yystopf/applied_projects.json
|
||||
```
|
||||
|
||||
```javascript
|
||||
await octokit.request('GET /api/users/:login/applied_projects.json')
|
||||
```
|
||||
|
||||
### HTTP 请求
|
||||
`GET /api/users/:login/applied_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 |申请创建者头像 |
|
||||
|
||||
|
||||
> 返回的JSON示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"total_count": 4,
|
||||
"applied_transfer_projects": [
|
||||
{
|
||||
"project": {
|
||||
"id": 74,
|
||||
"identifier": "hehuisssjssjjsjs",
|
||||
"name": "hehuisssjssjjsjs",
|
||||
"description": "wwww",
|
||||
"is_public": false,
|
||||
"owner": {
|
||||
"id": 10,
|
||||
"type": "User",
|
||||
"name": "testforge1",
|
||||
"login": "testforge1",
|
||||
"image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": 6,
|
||||
"type": "User",
|
||||
"name": "何慧",
|
||||
"login": "yystopf",
|
||||
"image_url": "images/avatars/User/6?t=1622513134"
|
||||
},
|
||||
"id": 7,
|
||||
"status": "common",
|
||||
"created_at": "2021-06-09 16:41",
|
||||
"time_ago": "7分钟前"
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 用户接受迁移
|
||||
用户接受迁移
|
||||
|
||||
> 示例:
|
||||
|
||||
```shell
|
||||
curl -X POST http://localhost:3000/api/users/yystopf/applied_projects/2/accept.json
|
||||
```
|
||||
|
||||
```javascript
|
||||
await octokit.request('GET /api/users/:login/applied_projects/:id/accept.json')
|
||||
```
|
||||
|
||||
### HTTP 请求
|
||||
`GET /api/users/:login/applied_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 |申请创建者头像 |
|
||||
|
||||
|
||||
> 返回的JSON示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"project": {
|
||||
"id": 74,
|
||||
"identifier": "hehuisssjssjjsjs",
|
||||
"name": "hehuisssjssjjsjs",
|
||||
"description": "wwww",
|
||||
"is_public": false,
|
||||
"owner": {
|
||||
"id": 10,
|
||||
"type": "User",
|
||||
"name": "testforge1",
|
||||
"login": "testforge1",
|
||||
"image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": 6,
|
||||
"type": "User",
|
||||
"name": "何慧",
|
||||
"login": "yystopf",
|
||||
"image_url": "images/avatars/User/6?t=1622513134"
|
||||
},
|
||||
"id": 7,
|
||||
"status": "accept",
|
||||
"created_at": "2021-06-09 16:41",
|
||||
"time_ago": "7分钟前"
|
||||
}
|
||||
```
|
||||
|
||||
## 用户拒绝迁移
|
||||
用户拒绝迁移
|
||||
|
||||
> 示例:
|
||||
|
||||
```shell
|
||||
curl -X POST http://localhost:3000/api/users/yystopf/applied_projects/2/refuse.json
|
||||
```
|
||||
|
||||
```javascript
|
||||
await octokit.request('GET /api/users/:login/applied_projects/:id/refuse.json')
|
||||
```
|
||||
|
||||
### HTTP 请求
|
||||
`GET /api/users/:login/applied_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 |申请创建者头像 |
|
||||
|
||||
> 返回的JSON示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"project": {
|
||||
"id": 74,
|
||||
"identifier": "hehuisssjssjjsjs",
|
||||
"name": "hehuisssjssjjsjs",
|
||||
"description": "wwww",
|
||||
"is_public": false,
|
||||
"owner": {
|
||||
"id": 10,
|
||||
"type": "User",
|
||||
"name": "testforge1",
|
||||
"login": "testforge1",
|
||||
"image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": 6,
|
||||
"type": "User",
|
||||
"name": "何慧",
|
||||
"login": "yystopf",
|
||||
"image_url": "images/avatars/User/6?t=1622513134"
|
||||
},
|
||||
"id": 7,
|
||||
"status": "accept",
|
||||
"created_at": "2021-06-09 16:41",
|
||||
"time_ago": "7分钟前"
|
||||
}
|
||||
```
|
||||
@@ -23,7 +23,7 @@ module Projects
|
||||
ActiveRecord::Base.transaction do
|
||||
gitea_result = Gitea::Repository::Members::AddService.new(owner, project.identifier, collaborator.login, permission).call
|
||||
if gitea_result.status == 204
|
||||
project.add_member!(collaborator.id)
|
||||
project.add_member!(collaborator.id, role_name)
|
||||
end
|
||||
fail!(nil)
|
||||
end
|
||||
@@ -38,5 +38,20 @@ module Projects
|
||||
@error = error
|
||||
end
|
||||
|
||||
def role_name
|
||||
case permission
|
||||
when 'read'
|
||||
'Reporter'
|
||||
when 'write'
|
||||
'Developer'
|
||||
when 'admin'
|
||||
'Manager'
|
||||
when 'owner'
|
||||
'Manager'
|
||||
else
|
||||
'Reporter'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
27
app/jobs/send_join_project_applied_message_job.rb
Normal file
27
app/jobs/send_join_project_applied_message_job.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
class SendJoinProjectAppliedMessageJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(applied_project, applied_user, message_status)
|
||||
project = applied_project.project
|
||||
return unless project.present?
|
||||
return unless applied_user.present?
|
||||
return unless applied_project.user.present?
|
||||
AppliedMessage.find_or_create_by!(user_id: applied_project.user_id,
|
||||
applied: applied_project,
|
||||
status: message_status,
|
||||
name: build_name(project.name, message_status),
|
||||
applied_user_id: applied_user.id,
|
||||
project_id: project.id)
|
||||
end
|
||||
|
||||
private
|
||||
def build_name(repo_name, message_status, applied_name="")
|
||||
case message_status
|
||||
when 'successed'
|
||||
return "已通过你加入【#{repo_name}】仓库的申请。"
|
||||
when 'failure'
|
||||
return "已拒绝你加入【#{repo_name}】仓库的申请。"
|
||||
end
|
||||
""
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,8 @@
|
||||
# user_id :integer not null
|
||||
# role :integer default("0")
|
||||
# status :integer default("0")
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class AppliedProject < ApplicationRecord
|
||||
@@ -16,6 +18,7 @@ class AppliedProject < ApplicationRecord
|
||||
has_many :applied_messages, as: :applied, dependent: :destroy
|
||||
# has_many :forge_activities, as: :forge_act, dependent: :destroy
|
||||
|
||||
enum role: {manager: 3, developer: 4, reporter: 5}
|
||||
enum status: {canceled: -1, common: 0, accepted: 1, refused: 2} # -1 已取消 0 待操作 1 已接收 2 已拒绝
|
||||
|
||||
end
|
||||
|
||||
@@ -1,41 +1,42 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: attachments
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# container_id :integer
|
||||
# container_type :string(30)
|
||||
# filename :string(255) default(""), not null
|
||||
# disk_filename :string(255) default(""), not null
|
||||
# filesize :integer default("0"), not null
|
||||
# content_type :string(255) default("")
|
||||
# digest :string(60) default(""), not null
|
||||
# downloads :integer default("0"), not null
|
||||
# author_id :integer default("0"), not null
|
||||
# created_on :datetime
|
||||
# description :text(65535)
|
||||
# disk_directory :string(255)
|
||||
# attachtype :integer default("1")
|
||||
# is_public :integer default("1")
|
||||
# copy_from :integer
|
||||
# quotes :integer default("0")
|
||||
# is_publish :integer default("1")
|
||||
# publish_time :datetime
|
||||
# resource_bank_id :integer
|
||||
# unified_setting :boolean default("1")
|
||||
# cloud_url :string(255) default("")
|
||||
# course_second_category_id :integer default("0")
|
||||
# delay_publish :boolean default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_attachments_on_author_id (author_id)
|
||||
# index_attachments_on_container_id_and_container_type (container_id,container_type)
|
||||
# index_attachments_on_course_second_category_id (course_second_category_id)
|
||||
# index_attachments_on_created_on (created_on)
|
||||
# index_attachments_on_is_public (is_public)
|
||||
# index_attachments_on_quotes (quotes)
|
||||
#
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: attachments
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# container_id :integer
|
||||
# container_type :string(30)
|
||||
# filename :string(255) default(""), not null
|
||||
# disk_filename :string(255) default(""), not null
|
||||
# filesize :integer default("0"), not null
|
||||
# content_type :string(255) default("")
|
||||
# digest :string(60) default(""), not null
|
||||
# downloads :integer default("0"), not null
|
||||
# author_id :integer default("0"), not null
|
||||
# created_on :datetime
|
||||
# description :text(65535)
|
||||
# disk_directory :string(255)
|
||||
# attachtype :integer default("1")
|
||||
# is_public :integer default("1")
|
||||
# copy_from :integer
|
||||
# quotes :integer default("0")
|
||||
# is_publish :integer default("1")
|
||||
# publish_time :datetime
|
||||
# resource_bank_id :integer
|
||||
# unified_setting :boolean default("1")
|
||||
# cloud_url :string(255) default("")
|
||||
# course_second_category_id :integer default("0")
|
||||
# delay_publish :boolean default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_attachments_on_author_id (author_id)
|
||||
# index_attachments_on_container_id_and_container_type (container_id,container_type)
|
||||
# index_attachments_on_course_second_category_id (course_second_category_id)
|
||||
# index_attachments_on_created_on (created_on)
|
||||
# index_attachments_on_is_public (is_public)
|
||||
# index_attachments_on_quotes (quotes)
|
||||
#
|
||||
|
||||
|
||||
class Attachment < ApplicationRecord
|
||||
include BaseModel
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
# is_sync_pwd :boolean default("1")
|
||||
# watchers_count :integer default("0")
|
||||
# devops_step :integer default("0")
|
||||
# sponsor_certification :integer default("0")
|
||||
# sponsor_num :integer default("0")
|
||||
# sponsored_num :integer default("0")
|
||||
# award_time :datetime
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
||||
@@ -65,7 +65,7 @@ module ProjectOperable
|
||||
if owner.is_a?(User)
|
||||
managers.exists?(user_id: user.id)
|
||||
elsif owner.is_a?(Organization)
|
||||
managers.exists?(user_id: user.id) || owner.is_admin?(user.id)
|
||||
managers.exists?(user_id: user.id) || owner.is_only_admin?(user.id)
|
||||
else
|
||||
false
|
||||
end
|
||||
@@ -76,7 +76,7 @@ module ProjectOperable
|
||||
if owner.is_a?(User)
|
||||
developers.exists?(user_id: user.id)
|
||||
elsif owner.is_a?(Organization)
|
||||
developers.exists?(user_id: user.id) || owner.is_write?(user.id)
|
||||
developers.exists?(user_id: user.id) || owner.is_only_write?(user.id)
|
||||
else
|
||||
false
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# tracker_id :integer not null
|
||||
# project_id :integer not null
|
||||
# subject :string(255) default(""), not null
|
||||
# description :text(65535)
|
||||
# description :text(4294967295)
|
||||
# due_date :date
|
||||
# category_id :integer
|
||||
# status_id :integer not null
|
||||
@@ -14,7 +14,6 @@
|
||||
# priority_id :integer not null
|
||||
# fixed_version_id :integer
|
||||
# author_id :integer not null
|
||||
# lock_version :integer default("0"), not null
|
||||
# created_on :datetime
|
||||
# updated_on :datetime
|
||||
# start_date :date
|
||||
@@ -28,7 +27,7 @@
|
||||
# closed_on :datetime
|
||||
# project_issues_index :integer
|
||||
# issue_type :string(255)
|
||||
# token :string(255)
|
||||
# token :integer default("0")
|
||||
# issue_tags_value :string(255)
|
||||
# is_lock :boolean default("0")
|
||||
# issue_classify :string(255)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# content :text(65535)
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# is_secret :boolean default("0")
|
||||
#
|
||||
|
||||
class License < ApplicationRecord
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
# course_group_id :integer default("0")
|
||||
# is_collect :integer default("1")
|
||||
# graduation_group_id :integer default("0")
|
||||
# is_apply_signature :boolean default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
# is_sync_pwd :boolean default("1")
|
||||
# watchers_count :integer default("0")
|
||||
# devops_step :integer default("0")
|
||||
# sponsor_certification :integer default("0")
|
||||
# sponsor_num :integer default("0")
|
||||
# sponsored_num :integer default("0")
|
||||
# award_time :datetime
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
@@ -106,6 +110,14 @@ class Organization < Owner
|
||||
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read write admin owner)}).present?
|
||||
end
|
||||
|
||||
def is_only_admin?(user_id)
|
||||
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(admin)}).present?
|
||||
end
|
||||
|
||||
def is_only_write?(user_id)
|
||||
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(write)}).present?
|
||||
end
|
||||
|
||||
def is_only_read?(user_id)
|
||||
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read)}).present?
|
||||
end
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: praise_treads
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer not null
|
||||
# praise_tread_object_id :integer
|
||||
# praise_tread_object_type :string(255)
|
||||
# praise_or_tread :integer default("1")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# praise_tread (praise_tread_object_id,praise_tread_object_type)
|
||||
#
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: praise_treads
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer not null
|
||||
# praise_tread_object_id :integer
|
||||
# praise_tread_object_type :string(255)
|
||||
# praise_or_tread :integer default("1")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# praise_tread (praise_tread_object_id,praise_tread_object_type)
|
||||
#
|
||||
|
||||
|
||||
class PraiseTread < ApplicationRecord
|
||||
belongs_to :user
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255) default(""), not null
|
||||
# description :text(65535)
|
||||
# description :text(4294967295)
|
||||
# homepage :string(255) default("")
|
||||
# is_public :boolean default("1"), not null
|
||||
# parent_id :integer
|
||||
@@ -43,6 +43,19 @@
|
||||
# watchers_count :integer default("0")
|
||||
# issues_count :integer default("0")
|
||||
# pull_requests_count :integer default("0")
|
||||
# language :string(255)
|
||||
# versions_count :integer default("0")
|
||||
# issue_tags_count :integer default("0")
|
||||
# closed_issues_count :integer default("0")
|
||||
# open_devops :boolean default("0")
|
||||
# gitea_webhook_id :integer
|
||||
# open_devops_count :integer default("0")
|
||||
# recommend :boolean default("0")
|
||||
# platform :integer default("0")
|
||||
# default_branch :string(255) default("master")
|
||||
# website :string(255)
|
||||
# order_index :integer default("0")
|
||||
# lesson_url :string(255)
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
# head :string(255)
|
||||
# base :string(255)
|
||||
# issue_id :integer
|
||||
# fork_project_id :integer
|
||||
# is_original :boolean default("0")
|
||||
# comments_count :integer default("0")
|
||||
# commits_count :integer default("0")
|
||||
# files_count :integer default("0")
|
||||
#
|
||||
|
||||
class PullRequest < ApplicationRecord
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
# is_sync_pwd :boolean default("1")
|
||||
# watchers_count :integer default("0")
|
||||
# devops_step :integer default("0")
|
||||
# sponsor_certification :integer default("0")
|
||||
# sponsor_num :integer default("0")
|
||||
# sponsored_num :integer default("0")
|
||||
# award_time :datetime
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
@@ -206,6 +210,13 @@ class User < Owner
|
||||
return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||
end
|
||||
|
||||
# 用户管理的所有项目
|
||||
def full_admin_projects
|
||||
normal_projects = Project.joins(members: :roles).where(roles: {name: 'Manager'}, members: {user_id: self.id}).to_sql
|
||||
org_projects = Project.joins(teams: :team_users).where(teams: {authorize: %w(admin owner)}, team_users: {user_id: self.id}).to_sql
|
||||
return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||
end
|
||||
|
||||
def name
|
||||
login
|
||||
end
|
||||
|
||||
61
app/services/projects/accept_join_service.rb
Normal file
61
app/services/projects/accept_join_service.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
class Projects::AcceptJoinService < ApplicationService
|
||||
attr_accessor :applied_project, :owner
|
||||
attr_reader :user, :project
|
||||
|
||||
def initialize(user, applied_project)
|
||||
@user = user
|
||||
@project = applied_project.project
|
||||
@applied_project = applied_project
|
||||
end
|
||||
|
||||
def call
|
||||
Rails.logger.info("###### Project accept_join_service begin ######")
|
||||
ActiveRecord::Base.transaction do
|
||||
validate!
|
||||
update_apply
|
||||
operate_project_member
|
||||
send_apply_message
|
||||
end
|
||||
|
||||
Rails.logger.info("##### Project accept_join_service end ######")
|
||||
|
||||
|
||||
return @applied_project
|
||||
end
|
||||
|
||||
private
|
||||
def permission
|
||||
case @applied_project.role
|
||||
when 'manager'
|
||||
'admin'
|
||||
when 'developer'
|
||||
'write'
|
||||
when 'reporter'
|
||||
'read'
|
||||
else
|
||||
'read'
|
||||
end
|
||||
end
|
||||
|
||||
def validate!
|
||||
raise Error, '该申请已经被接受' if @applied_project.accepted?
|
||||
raise Error, '该申请不存在' unless @applied_project.present?
|
||||
raise Error, '未拥有接受申请权限' unless is_permit_operator
|
||||
end
|
||||
|
||||
def is_permit_operator
|
||||
return @user.admin? || @project.manager?(@user)
|
||||
end
|
||||
|
||||
def update_apply
|
||||
@applied_project.update!(status: 'accepted')
|
||||
end
|
||||
|
||||
def operate_project_member
|
||||
Projects::AddMemberInteractor.call(@project.owner, @project, @user, permission)
|
||||
end
|
||||
|
||||
def send_apply_message
|
||||
SendJoinProjectAppliedMessageJob.perform_now(@applied_project, @user, 'successed')
|
||||
end
|
||||
end
|
||||
@@ -9,26 +9,25 @@ class Projects::ApplyJoinService < ApplicationService
|
||||
end
|
||||
|
||||
def call
|
||||
validate!
|
||||
|
||||
# 项目报告人员直接加入项目
|
||||
if params[:role] == 'reporter'
|
||||
# Projects::JoinService.call(project, user, role: 'reporter')
|
||||
return project
|
||||
end
|
||||
# if params[:role] == 'reporter'
|
||||
# # Projects::JoinService.call(project, user, role: 'reporter')
|
||||
# return project
|
||||
# end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
validate!
|
||||
apply = user.applied_projects.create!(project: project, role: role_value)
|
||||
apply
|
||||
# apply.forge_activities.find_or_create_by!(user: user, project: project)
|
||||
|
||||
apply.forge_activities.find_or_create_by!(user: user, project: project)
|
||||
|
||||
notify_project_manager!(apply)
|
||||
# notify_project_manager!(apply)
|
||||
end
|
||||
|
||||
# notify_project_owner
|
||||
ApplyJoinProjectNotifyJob.perform_later(user.id, project.id, role_value)
|
||||
# ApplyJoinProjectNotifyJob.perform_later(user.id, project.id, role_value)
|
||||
|
||||
project
|
||||
end
|
||||
|
||||
private
|
||||
@@ -43,7 +42,8 @@ class Projects::ApplyJoinService < ApplicationService
|
||||
when 'manager' then 3
|
||||
when 'developer' then 4
|
||||
when 'reporter' then 5
|
||||
else raise Error, '角色无效'
|
||||
else
|
||||
5
|
||||
end
|
||||
end
|
||||
|
||||
@@ -74,12 +74,18 @@ class Projects::ApplyJoinService < ApplicationService
|
||||
def validate!
|
||||
# params check
|
||||
raise Error, '邀请码不能为空' if params[:code].blank?
|
||||
raise Error, '角色不能为空' if params[:role].blank?
|
||||
raise Error, '角色无效' unless %w(manager developer reporter).include?(params[:role])
|
||||
raise Error, '请输入6位项目邀请码' unless valid_invite_code( params[:code])
|
||||
|
||||
# logical check
|
||||
raise Error, '邀请码无效' if project.blank?
|
||||
raise Error, '您已在该项目中' if project.member?(user)
|
||||
raise Error, '您已经提交过申请' if user.applied_projects.pending.exists?(project: project)
|
||||
raise Error, '您已是项目成员' if project.member?(user)
|
||||
raise Error, '您已经提交过申请' if user.applied_projects.common.exists?(project: project)
|
||||
end
|
||||
|
||||
def valid_invite_code(str)
|
||||
if (str =~ /^[A-Za-z0-9]{6}+$/)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
39
app/services/projects/refuse_join_service.rb
Normal file
39
app/services/projects/refuse_join_service.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
class Projects::RefuseJoinService < ApplicationService
|
||||
attr_accessor :applied_project, :owner
|
||||
attr_reader :user, :project
|
||||
|
||||
def initialize(user, applied_project)
|
||||
@user = user
|
||||
@project = applied_project.project
|
||||
@applied_project = applied_project
|
||||
end
|
||||
|
||||
def call
|
||||
Rails.logger.info("###### Project refuse_join_service begin ######")
|
||||
validate!
|
||||
update_apply
|
||||
send_apply_message
|
||||
Rails.logger.info("###### Project refuse_join_service end ######")
|
||||
|
||||
return @applied_project
|
||||
end
|
||||
|
||||
private
|
||||
def validate!
|
||||
raise Error, '该申请已被拒绝' if @applied_project.refused?
|
||||
raise Error, '该申请不存在' unless @applied_project.present?
|
||||
raise Error, '未拥有接受申请权限' unless is_permit_operator
|
||||
end
|
||||
|
||||
def is_permit_operator
|
||||
return @user.admin? || @project.manager?(@user)
|
||||
end
|
||||
|
||||
def update_apply
|
||||
@applied_project.update!(status: 'refused')
|
||||
end
|
||||
|
||||
def send_apply_message
|
||||
SendJoinProjectAppliedMessageJob.perform_now(@applied_project, @user, 'failure')
|
||||
end
|
||||
end
|
||||
18
app/views/applied_projects/_detail.json.jbuilder
Normal file
18
app/views/applied_projects/_detail.json.jbuilder
Normal file
@@ -0,0 +1,18 @@
|
||||
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.id object.id
|
||||
json.status object.status
|
||||
json.created_at format_time(object.created_at)
|
||||
json.time_ago time_from_now(object.created_at)
|
||||
1
app/views/applied_projects/create.json.jbuilder
Normal file
1
app/views/applied_projects/create.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.partial! "detail", locals: {object: @applied_project}
|
||||
@@ -13,7 +13,12 @@
|
||||
# json.partial! "/users/user_simple", locals: {user: object.user}
|
||||
# end
|
||||
json.applied do
|
||||
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: object.applied}
|
||||
case object.applied_type
|
||||
when 'AppliedTransferProject'
|
||||
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: object.applied}
|
||||
when 'AppliedProject'
|
||||
json.partial! "/applied_projects/detail", locals: {object: object.applied}
|
||||
end
|
||||
end
|
||||
json.applied_user do
|
||||
json.partial! "/users/user_simple", locals: {user: object.applied_user}
|
||||
|
||||
1
app/views/users/applied_projects/accept.json.jbuilder
Normal file
1
app/views/users/applied_projects/accept.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.partial! "/applied_projects/detail", locals: {object: @applied_project}
|
||||
4
app/views/users/applied_projects/index.json.jbuilder
Normal file
4
app/views/users/applied_projects/index.json.jbuilder
Normal file
@@ -0,0 +1,4 @@
|
||||
json.total_count @applied_projects.total_count
|
||||
json.applied_projects @applied_projects do |apply|
|
||||
json.partial! "/applied_projects/detail", locals: {object: apply}
|
||||
end
|
||||
1
app/views/users/applied_projects/refuse.json.jbuilder
Normal file
1
app/views/users/applied_projects/refuse.json.jbuilder
Normal file
@@ -0,0 +1 @@
|
||||
json.partial! "/applied_projects/detail", locals: {object: @applied_project}
|
||||
Reference in New Issue
Block a user