dev_forge
caicai8 5 years ago
commit cf5b03887e

@ -95,6 +95,53 @@ curl -X GET http://localhost:3000/api/users/me | jq
```
---
#### 用户列表(带搜索功能)
```
GET api/users/list
```
*示例*
```
curl -X GET \
-d "limit=10" \
-d "search=18816895620"
http://localhost:3000/api/users/list | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|page |否|int |页数,第几页 |
|limit |否|int |每页多少条数据默认15条 |
|search |否|string |用户名、登录名匹配搜索 |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|total_count |int |总用户条数 |
|users |array| |
|-- username |string|用户全名|
|-- login |string|用户登录名|
|-- user_id |int|用户id|
|-- image_url |string|用户头像|
返回值
```
{
"total_count": 1,
"users": [
{
"username": "18816895620",
"login": "18816895620",
"user_id": 36401,
"image_url": "avatars/User/b"
}
]
}
```
---
#### 获取项目类别列表(可根据名称搜素)
```
GET api/project_categories
@ -363,6 +410,251 @@ http://localhost:3000/api/projects/migrate | jq
```
---
#### 项目详情
```
GET api/projects/:id
```
*示例*
```
curl -X GET http://localhost:3000/api/projects/3263 | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|id |是|int |项目id |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|id |int |id |
|name |string|项目名称|
返回值
```
{
"id": 3240,
"name": "好项目"
}
```
---
#### 修改项目信息
```
PUT api/projects/:id
```
*示例*
```
curl -X PUT \
-d "user_id=36401" \
-d "name=hnfl_demo" \
-d "description=my first project" \
-d "repository_name=hnfl_demo" \
-d "project_category_id=1" \
-d "project_language_id=2" \
-d "ignore_id=2" \
-d "license_id=1" \
http://localhost:3000/api/projects/3263 | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|id |是|int |项目id |
|name |是|string |项目名称 |
|description |是|string |项目描述 |
|project_category_id|是|int |项目类别id |
|project_language_id|是|int |项目语言id |
|private |否|boolean|项目是否私有, true为私有false: 公开,默认为公开 |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|id |int |id |
|name |string|项目名称|
返回值
```
{
"id": 3240,
"name": "好项目"
}
```
---
#### 项目添加成员
```
POST api/projects/:id/members
```
*示例*
```
curl -X POST \
-d "user_id=36400" \
http://localhost:3000/api/projects/3263/members | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|id |是|int |项目id |
|user_id |是|int |用户id |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|status |int |0:添加成功, -1: 添加失败, 1: 表示已经是项目成员 |
|message |string|返回信息说明|
返回值
```
{
"status": 0,
"message": "success"
}
```
---
#### 项目删除成员
```
DELETE api/projects/:id/members/remove
```
*示例*
```
curl -X DELETE \
-d "user_id=36400" \
http://localhost:3000/api/projects/3263/members/remove | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|id |是|int |项目id |
|user_id |是|int |用户id |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|status |int |0:移除成功, -1: 移除失败, 1: 表示还不是项目成员 |
|message |string|返回信息说明|
返回值
```
{
"status": 0,
"message": "success"
}
```
---
#### 更改项目成员角色
```
PUT api/projects/:id/members/change_role
```
*示例*
```
curl -X PUT \
-d "user_id=36400" \
-d "role=Developer" \
http://localhost:3000/api/projects/3263/members/change_role | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|id |是|int |项目id |
|user_id |是|int |用户id |
|role |是|string |取值范围:"Manager", "Developer", "Reporter";分别为项目管理人员(拥有所有操作权限)、项目开发人员(只拥有读写权限)、项目报告人员(只拥有读权限) |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|status |int |0:角色更改成功, -1: 更改失败失败, 1: 表示还不是项目成员 |
|message |string|返回信息说明|
返回值
```
{
"status": 0,
"message": "success"
}
```
---
#### 项目成员列表
```
GET api/projects/:id/members
```
*示例*
```
curl -X GET \
-d "page=1" \
-d "limit=5" \
http://localhost:3000/api/projects/3263/members | jq
```
*请求参数说明:*
|参数名|必选|类型|说明|
-|-|-|-
|id |是|int |项目id |
|page |否|string |页数,第几页 |
|limit |否|string |每页多少条数据默认15条 |
*返回参数说明:*
|参数名|类型|说明|
-|-|-
|total_count |int |返回记录总条数 |
|members |array|项目成员信息|
|-- id |int|用户id|
|-- name |string|用户名称|
|-- login |string|用户登录名/标识|
|-- image_url |string|用户头像|
|-- is_owner |boolean|是否是项目的拥有者true:是, false:不是|
|-- role |string|该用户在项目中的角色, Manager: 管理员(拥有操作权限); Developer:开发人员(只拥有读写权限) Reporter:报告人员(只拥有读权限)|
返回值
```
{
"total_count": 2,
"members": [
{
"id": 36401,
"name": "18816895620",
"login": "18816895620",
"image_url": "avatars/User/b",
"is_owner": true,
"role": "Manager"
},
{
"id": 36399,
"name": "18816365620",
"login": "18816365620",
"image_url": "avatars/User/b",
"is_owner": false,
"role": "Developer"
}
]
}
```
---
#### 获取代码目录列表
```
POST api/:login/:repo_identifier/entries

@ -632,13 +632,18 @@ class ApplicationController < ActionController::Base
render_not_found("未找到’#{params[:login]}’相关的用户") unless @user
end
def find_user_with_id
@user = User.find_by_id params[:user_id]
render_not_found("未找到’#{params[:login]}’相关的用户") unless @user
end
def find_repository
@repo = @user.repositories.find_by_identifier params[:repo_identifier]
render_not_found("未找到’#{params[:repo_identifier]}’相关的项目") unless @repo
end
def find_project
@project = Project.find_by_identifier! params[:id]
@project = Project.find_by_identifier!(params[:id]) || (Project.find params[:project_id])
render_not_found("未找到’#{params[:id]}’相关的项目") unless @project
end
@ -649,6 +654,14 @@ class ApplicationController < ActionController::Base
tip_exception(e.message)
end
def render_response(interactor)
if interactor.success?
render_ok
else
render_error(interactor.error)
end
end
private
def object_not_found
uid_logger("Missing template or cant't find record, responding with 404")

@ -0,0 +1,59 @@
class MembersController < ApplicationController
before_action :require_login
before_action :find_project_with_id
before_action :find_user_with_id, only: %i[create remove change_role]
before_action :operate!, except: %i[index]
before_action :check_member_exists!, only: %i[create]
before_action :check_member_not_exists!, only: %i[remove change_role]
def create
interactor = Projects::AddMemberInteractor.call(current_user, @project, @user)
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def index
scope = @project.members.includes(:user, :roles)
@total_count = scope.size
@members = paginate(scope)
end
def remove
interactor = Projects::DeleteMemberInteractor.call(current_user, @project, @user)
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def change_role
interactor = Projects::ChangeMemberRoleInteractor.call(current_user, @project, @user, params[:role])
render_response(interactor)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def can_operate?
current_user.project_manager?(@project)
end
def member_exists?
@project.member?(params[:user_id])
end
def operate!
return render_forbidden('你不是管理员,没有权限操作') unless can_operate?
end
def check_member_exists!
return render_result(1, "user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists?
end
def check_member_not_exists!
return render_result(1, "user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists?
end
end

@ -16,13 +16,7 @@ class RepositoriesController < ApplicationController
interactor = Repositories::EntriesInteractor.call(@user, @repo.identifier, params[:filepath], ref: params[:ref])
if interactor.success?
@sub_entries = interactor.result
# if @sub_entries.is_a? Array
# @sub_entries = @sub_entries.sort_by{ |hash| hash['type'] }
# else
# @sub_entries = [] << @sub_entries
# end
@sub_entries = [] << @sub_entries unless @sub_entries.is_a? Array
Rails.logger.info("######_________________###########{@sub_entries}")
@sub_entries = @sub_entries.sort_by{ |hash| hash['type'] }
else
render_error(interactor.error)

@ -2,8 +2,13 @@ class UsersController < ApplicationController
before_action :load_user, only: [:show, :homepage_info]
before_action :check_user_exist, only: [:show, :homepage_info]
before_action :require_login, only: %i[me]
before_action :require_login, only: %i[me list]
def list
scope = User.active.recent.like(params[:search]).includes(:user_extension)
@total_count = scope.size
@users = paginate(scope)
end
def show;end

@ -0,0 +1,10 @@
class Projects::ChangeMemberRoleForm < BaseForm
attr_accessor :user_id, :role
validates :user_id, :role, presence: true
validate :check_roles
def check_roles
raise '无效的role值.' unless ["Manager","Developer", "Reporter"].include? role
end
end

@ -0,0 +1,2 @@
module MembersHelper
end

@ -0,0 +1,42 @@
module Projects
class AddMemberInteractor
def self.call(owner, project, collaborator, permission="write")
interactor = new(owner, project, collaborator, permission)
interactor.run
interactor
end
attr_reader :error, :result
def initialize(owner, project, collaborator, permission)
@owner = owner
@project = project
@collaborator = collaborator
@permission = permission
end
def success?
@error.nil?
end
def run
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)
end
fail!(nil)
end
rescue Exception => exception
fail!(exception.message)
end
private
attr_reader :owner, :project, :collaborator, :permission
def fail!(error)
@error = error
end
end
end

@ -0,0 +1,51 @@
module Projects
class ChangeMemberRoleInteractor
def self.call(owner, project, collaborator, role)
interactor = new(owner, project, collaborator, role)
interactor.run
interactor
end
attr_reader :error, :result
def initialize(owner, project, collaborator, role)
@owner = owner
@collaborator = collaborator
@project = project
@role = role
end
def success?
@error.nil?
end
def run
Projects::ChangeMemberRoleForm.new({user_id: collaborator.id, role: role}).validate!
ActiveRecord::Base.transaction do
gitea_result = Gitea::Repository::Members::AddService.new(owner, project.identifier, collaborator.login, treated_role).call
if gitea_result.status == 204
Projects::ChangeMemberRoleService.new(project, collaborator.id, role).call
fail!(nil)
end
end
rescue Exception => exception
fail!(exception.message)
end
private
attr_reader :role, :project, :collaborator, :owner
def fail!(error)
@error = error
end
def treated_role
case role
when "Manager" then "admin"
when "Developer" then "write"
when "Reporter" then "read"
end
end
end
end

@ -0,0 +1,41 @@
module Projects
class DeleteMemberInteractor
def self.call(owner, project, collaborator)
interactor = new(owner, project, collaborator)
interactor.run
interactor
end
attr_reader :error, :result
def initialize(owner, project, collaborator)
@owner = owner
@project = project
@collaborator = collaborator
end
def success?
@error.nil?
end
def run
ActiveRecord::Base.transaction do
gitea_result = Gitea::Repository::Members::DeleteService.new(owner, project.identifier, collaborator.login).call
if gitea_result.status == 204
project.remove_member!(collaborator.id)
end
fail!(nil)
end
rescue Exception => exception
fail!(exception.message)
end
private
attr_reader :owner, :project, :collaborator
def fail!(error)
@error = error
end
end
end

@ -0,0 +1,43 @@
module ProjectOperable
extend ActiveSupport::Concern
included do
has_many :members
# has_many :except_owner_members, -> { members.where("members.use_id != ? ", self.owner.id ) }
has_many :manager_members, -> { joins(:roles).where(roles: { name: 'Manager' }) }, class_name: 'Member'
end
def add_member!(user_id, role_name='Developer')
member = members.create!(user_id: user_id)
set_developer_role(member)
end
def remove_member!(user_id)
member = members.find_by(user_id: user_id)
member.destroy! if member && self.user_id != user_id
end
def member?(user_id)
members.exists?(user_id: user_id)
end
# 除了项目创建者本身
def member(user_id)
members.where.not("members.user_id = ? ", owner.id).find_by(user_id: user_id)
end
def change_member_role!(user_id, role)
member = self.member(user_id)
member.member_roles.last.update_attributes!(role: role)
end
def owner?(user)
self.owner == user
end
def set_developer_role(member)
role = Role.find_by_name 'Developer'
member.member_roles.create!(role: role)
end
end

@ -6,4 +6,6 @@ class Member < ApplicationRecord
has_many :member_roles, dependent: :destroy
has_many :roles, through: :member_roles
validates :user_id, :project_id, presence: true
end

@ -1,4 +1,6 @@
class MemberRole < ApplicationRecord
belongs_to :role
belongs_to :member
validates :member_id, :role_id, presence: true
end

@ -2,6 +2,7 @@ class Project < ApplicationRecord
include Matchable
include Publicable
include Watchable
include ProjectOperable
enum project_type: { mirror: 1, common: 0 } # common:开源托管项目, mirror:开源镜像项目
@ -14,8 +15,6 @@ class Project < ApplicationRecord
has_many :commits
has_many :members
has_many :manager_members, -> { joins(:roles).where(roles: { name: 'Manager' }) }, class_name: 'Member'
has_one :project_score, dependent: :destroy
has_one :repository, dependent: :destroy
has_many :issue_tags
@ -38,14 +37,6 @@ class Project < ApplicationRecord
User.find(user_id).full_name
end
def project_members
self.members
end
def member?(user)
members.exists?(user_id: user.id) || user.id == self.user_id
end
def members_user_infos
members.joins("left join users on members.user_id = users.id").includes(:user)
# members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname")

@ -1,6 +1,8 @@
class User < ApplicationRecord
include Watchable
include Likeable
include BaseModel
include ProjectOperable
include Searchable::Dependents::User
# Account statuses
@ -31,6 +33,9 @@ class User < ApplicationRecord
LOGIN_CHARS = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z).freeze
# FIX Invalid single-table inheritance type
self.inheritance_column = nil
# educoder: 来自Educoder平台
# trustie: 来自Trustie平台
# forge: 平台本身注册的用户
@ -171,6 +176,9 @@ class User < ApplicationRecord
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
scope :like, lambda { |keywords|
where("LOWER(concat(lastname, firstname, login)) LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
}
attr_accessor :password, :password_confirmation
@ -212,6 +220,10 @@ class User < ApplicationRecord
mail.blank? ? "#{login}@educoder.net" : mail
end
def project_manager?(project)
project.manager_members.exists?(user: self) || self.admin?
end
# 学号
def student_id
self.user_extension.try(:student_id)

@ -0,0 +1,28 @@
# 添加协作者/或者更改协作这的可读写权限
class Gitea::Repository::Members::AddService < Gitea::ClientService
attr_reader :owner, :repo_name, :collaborator, :permission
# owner: owner of the repo
# repo_name: name of the repo
# collaborator: username of the collaborator
# permission: permission name, FIX: admin | read | write
def initialize(owner, repo_name, collaborator, permission)
@owner = owner
@repo_name = repo_name
@collaborator = collaborator
@permission = permission
end
def call
put(url, params)
end
private
def params
Hash.new.merge(token: owner.gitea_token, data: {permission: permission})
end
def url
"/repos/#{owner.login}/#{repo_name}/collaborators/#{collaborator}".freeze
end
end

@ -0,0 +1,25 @@
class Gitea::Repository::Members::DeleteService < Gitea::ClientService
attr_reader :owner, :repo_name, :collaborator
# owner: owner of the repo
# repo_name: name of the repo
# collaborator: username of the collaborator
def initialize(owner, repo_name, collaborator)
@owner = owner
@repo_name = repo_name
@collaborator = collaborator
end
def call
delete(url, params)
end
private
def params
Hash.new.merge(token: owner.gitea_token)
end
def url
"/repos/#{owner.login}/#{repo_name}/collaborators/#{collaborator}".freeze
end
end

@ -0,0 +1,18 @@
class Projects::ChangeMemberRoleService < ApplicationService
attr_reader :project, :user_id, :role
def initialize(project, user_id, role)
@project = project
@user_id = user_id
@role = role
end
def call
ActiveRecord::Base.transaction do
tmp_role = Role.find_by_name role
@project.change_member_role!(user_id, tmp_role)
end
rescue => e
raise Error, e.message
end
end

@ -0,0 +1,4 @@
json.id user.id
json.name user.real_name
json.login user.login
json.image_url url_to_avatar(user)

@ -0,0 +1,6 @@
json.total_count @total_count
json.members @members do |member|
json.partial! 'member', user: member.user
json.is_owner @project.owner?(member.user)
json.role member.roles.last.name
end

@ -0,0 +1,4 @@
json.total_count @total_count
json.users do
json.partial! 'user_small', users: @users
end

@ -39,7 +39,7 @@ Rails.application.routes.draw do
resources :ignores, only: [:index, :show]
resources :licenses, only: [:index, :show]
resources :projects, only: [:index, :create, :show] do
resources :projects, only: [:index, :create, :show, :update] do
resources :pull_requests, except: [:destroy] do
member do
post :pr_merge
@ -80,6 +80,13 @@ Rails.application.routes.draw do
end
end
resources :members, only: [:index, :create] do
collection do
delete :remove
put :change_role
end
end
collection do
post :migrate
get :group_type_list
@ -88,6 +95,7 @@ Rails.application.routes.draw do
member do
get :branches
post :watch
get :fork
end
end
@ -127,6 +135,7 @@ Rails.application.routes.draw do
post :attendance
get :system_update
get :me
get :list
resource :trial_apply, only: [:create]
resources :projects, module: :users, only: [] do

Loading…
Cancel
Save