forked from Gitlink/forgeplus
Compare commits
96 Commits
master
...
trustie_se
| Author | SHA1 | Date |
|---|---|---|
|
|
abbabfdefd | |
|
|
edd76b9286 | |
|
|
4643d2387c | |
|
|
3ca629d47d | |
|
|
a9c0d18a5f | |
|
|
a3ca94d433 | |
|
|
91a804caf7 | |
|
|
b22330d146 | |
|
|
b2e338732d | |
|
|
663deae21b | |
|
|
dae5c9690f | |
|
|
d71272146f | |
|
|
c56f0ca7fc | |
|
|
e65df07d79 | |
|
|
246b6b52ec | |
|
|
744f857f20 | |
|
|
f222cc6e4f | |
|
|
b9789183e3 | |
|
|
7cf2c6021f | |
|
|
e87413f8a0 | |
|
|
e0f9a3d43d | |
|
|
0133ec24ca | |
|
|
c1ef39b262 | |
|
|
03e54f9b3d | |
|
|
1277e717ff | |
|
|
1a7b323120 | |
|
|
fffe57a211 | |
|
|
b673747475 | |
|
|
51643dc02c | |
|
|
a078c07b59 | |
|
|
a4555e2d10 | |
|
|
c920994274 | |
|
|
c14c92ac11 | |
|
|
b984790d5c | |
|
|
876591100e | |
|
|
8bf02b1ee5 | |
|
|
9876e84c17 | |
|
|
ea42b0d6ed | |
|
|
660a48b257 | |
|
|
65d51e8578 | |
|
|
ba9848ebe7 | |
|
|
c3d9e38e05 | |
|
|
7d612ea6b3 | |
|
|
120a33bc8a | |
|
|
b68c9945e5 | |
|
|
01360de423 | |
|
|
41c621cf55 | |
|
|
5bd33c033c | |
|
|
0d828ead1f | |
|
|
09ac49dda5 | |
|
|
1a22491e36 | |
|
|
95a355b87c | |
|
|
13768f9778 | |
|
|
220ca96669 | |
|
|
28c8761f32 | |
|
|
1d81548eb6 | |
|
|
96238c2e13 | |
|
|
d532dc7cf5 | |
|
|
8b7b1b7a4e | |
|
|
1e081b5a3e | |
|
|
341a810afc | |
|
|
2282c52efb | |
|
|
34edd78ae7 | |
|
|
36fb5a118c | |
|
|
b756be1d6a | |
|
|
348c2244f7 | |
|
|
31738fc227 | |
|
|
a93c98fb7c | |
|
|
39193324e9 | |
|
|
81743ce3bc | |
|
|
e9ae536f04 | |
|
|
186955fe4a | |
|
|
8ce7fd95cb | |
|
|
0867e5130f | |
|
|
db476a1a9b | |
|
|
fa1fd8a4ba | |
|
|
0d7a11f3ab | |
|
|
879e45e106 | |
|
|
b3b0f75e9b | |
|
|
5c8e561bd8 | |
|
|
2b0c987558 | |
|
|
6796805b21 | |
|
|
5752f19b2f | |
|
|
eb52f05417 | |
|
|
786629dbff | |
|
|
7a00541375 | |
|
|
1d832a1723 | |
|
|
80ce40e492 | |
|
|
91f6dae56a | |
|
|
8c5a834b14 | |
|
|
57f420848e | |
|
|
fba58800a7 | |
|
|
c4a43c4392 | |
|
|
1153bd5ab6 | |
|
|
f732b0374c | |
|
|
0d97d7d4f0 |
|
|
@ -329,7 +329,6 @@ class ApplicationController < ActionController::Base
|
||||||
User.current = user
|
User.current = user
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# if !User.current.logged? && Rails.env.development?
|
# if !User.current.logged? && Rails.env.development?
|
||||||
# User.current = User.find 1
|
# User.current = User.find 1
|
||||||
# end
|
# end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
module Acceleratorable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def enable_accelerator?(clone_addr)
|
||||||
|
clone_addr.include?(github_domain) || clone_addr.include?(gitlab_domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
def accelerator_url(repo_name)
|
||||||
|
[accelerator_domain, accelerator_username, "#{repo_name}.git"].join('/')
|
||||||
|
end
|
||||||
|
|
||||||
|
def github_domain
|
||||||
|
'github.com'
|
||||||
|
end
|
||||||
|
|
||||||
|
def gitlab_domain
|
||||||
|
'gitlab.com'
|
||||||
|
end
|
||||||
|
|
||||||
|
def accelerator_domain
|
||||||
|
Gitea.gitea_config[:accelerator]["domain"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def accelerator_username
|
||||||
|
Gitea.gitea_config[:accelerator]["access_key_id"]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
module RegisterHelper
|
module RegisterHelper
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
def autologin_register(username, email, password, platform= 'forge')
|
def autologin_register(username, email, password, platform= 'forge', need_edit_info = false)
|
||||||
result = {message: nil, user: nil}
|
result = {message: nil, user: nil}
|
||||||
|
|
||||||
user = User.new(admin: false, login: username, mail: email, type: "User")
|
user = User.new(admin: false, login: username, mail: email, type: "User")
|
||||||
user.password = password
|
user.password = password
|
||||||
user.platform = platform
|
user.platform = platform
|
||||||
user.activate
|
if need_edit_info
|
||||||
|
user.need_edit_info
|
||||||
|
else
|
||||||
|
user.activate
|
||||||
|
end
|
||||||
|
|
||||||
return unless user.valid?
|
return unless user.valid?
|
||||||
|
|
||||||
|
|
@ -27,4 +31,30 @@ module RegisterHelper
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def autosync_register_trustie(username, password, email)
|
||||||
|
config = Rails.application.config_for(:configuration).symbolize_keys!
|
||||||
|
|
||||||
|
api_host = config[:sync_url]
|
||||||
|
|
||||||
|
return if api_host.blank?
|
||||||
|
|
||||||
|
url = "#{api_host}/api/v1/users/common"
|
||||||
|
sync_json = {
|
||||||
|
"mail": email,
|
||||||
|
"password": password,
|
||||||
|
"login": username
|
||||||
|
}
|
||||||
|
uri = URI.parse(url)
|
||||||
|
|
||||||
|
if api_host
|
||||||
|
http = Net::HTTP.new(uri.hostname, uri.port)
|
||||||
|
|
||||||
|
if api_host.include?("https://")
|
||||||
|
http.use_ssl = true
|
||||||
|
end
|
||||||
|
|
||||||
|
http.send_request('POST', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ class Oauth::BaseController < ActionController::Base
|
||||||
include RenderHelper
|
include RenderHelper
|
||||||
include LoginHelper
|
include LoginHelper
|
||||||
include ControllerRescueHandler
|
include ControllerRescueHandler
|
||||||
|
include LoggerHelper
|
||||||
# include LaboratoryHelper
|
# include LaboratoryHelper
|
||||||
|
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
|
|
@ -11,6 +12,18 @@ class Oauth::BaseController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
def tip_exception(status = -1, message)
|
||||||
|
raise Educoder::TipException.new(status, message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tip_show_exception(status = -2, message)
|
||||||
|
raise Educoder::TipException.new(status, message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tip_show(exception)
|
||||||
|
uid_logger("Tip show status is #{exception.status}, message is #{exception.message}")
|
||||||
|
render json: exception.tip_json
|
||||||
|
end
|
||||||
|
|
||||||
def session_user_id
|
def session_user_id
|
||||||
# session[:user_id]
|
# session[:user_id]
|
||||||
|
|
@ -48,4 +61,13 @@ class Oauth::BaseController < ActionController::Base
|
||||||
Rails.logger.info("[wechat] set session unionid: #{unionid}")
|
Rails.logger.info("[wechat] set session unionid: #{unionid}")
|
||||||
session[:unionid] = unionid
|
session[:unionid] = unionid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def session_edulogin
|
||||||
|
session[:edulogin]
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_session_edulogin(login)
|
||||||
|
Rails.logger.info("[educoder] set sesstion edulogin: #{login}")
|
||||||
|
session[:edulogin] = login
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
class Oauth::EducoderController < Oauth::BaseController
|
class Oauth::EducoderController < Oauth::BaseController
|
||||||
|
include RegisterHelper
|
||||||
|
|
||||||
def bind
|
def bind
|
||||||
begin
|
begin
|
||||||
login = params[:login]
|
login = params[:login]
|
||||||
|
|
@ -32,4 +34,41 @@ class Oauth::EducoderController < Oauth::BaseController
|
||||||
render_error(ex.message)
|
render_error(ex.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 需要educoder那边设置回调地址
|
||||||
|
def create
|
||||||
|
begin
|
||||||
|
code = params['code'].to_s.strip
|
||||||
|
tip_exception("code不能为空") if code.blank?
|
||||||
|
|
||||||
|
new_user = false
|
||||||
|
result = EducoderOauth::Service.access_token(code)
|
||||||
|
result = EducoderOauth::Service.user_info(result[:access_token])
|
||||||
|
|
||||||
|
# 存在该用户
|
||||||
|
open_user = OpenUsers::Educoder.find_by(uid: result['login'])
|
||||||
|
if open_user.present? && open_user.user.present?
|
||||||
|
successful_authentication(open_user.user)
|
||||||
|
else
|
||||||
|
if current_user.blank? || !current_user.logged?
|
||||||
|
new_user = true
|
||||||
|
login = User.generate_login('E')
|
||||||
|
reg_result = autologin_register(login,"#{login}@forge.com", "Ec#{login}2021#", 'educoder', true)
|
||||||
|
if reg_result[:message].blank?
|
||||||
|
open_user = OpenUsers::Educoder.create!(user_id: reg_result[:user][:id], uid: result['login'], extra: result)
|
||||||
|
autosync_register_trustie(login, "Ec#{login}2021#", "#{login}@forge.com")
|
||||||
|
successful_authentication(open_user.user)
|
||||||
|
else
|
||||||
|
render_error(reg_result[:message])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
OpenUsers::Educoder.create!(user: current_user, uid: result['login'], extra: result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to root_path(new_user: new_user)
|
||||||
|
rescue Exception => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class Organizations::BaseController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def org_privacy_condition
|
def org_privacy_condition
|
||||||
|
return false if current_user.admin?
|
||||||
@organization.organization_extension.privacy? && @organization.organization_users.where(user_id: current_user.id).blank?
|
@organization.organization_extension.privacy? && @organization.organization_users.where(user_id: current_user.id).blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -2,6 +2,8 @@ class ProjectsController < ApplicationController
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
include OperateProjectAbilityAble
|
include OperateProjectAbilityAble
|
||||||
include ProjectsHelper
|
include ProjectsHelper
|
||||||
|
include Acceleratorable
|
||||||
|
|
||||||
before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about menu_list]
|
before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about menu_list]
|
||||||
before_action :load_project, except: %i[index group_type_list migrate create recommend]
|
before_action :load_project, except: %i[index group_type_list migrate create recommend]
|
||||||
before_action :authorizate_user_can_edit_project!, only: %i[update]
|
before_action :authorizate_user_can_edit_project!, only: %i[update]
|
||||||
|
|
@ -53,7 +55,23 @@ class ProjectsController < ApplicationController
|
||||||
|
|
||||||
def migrate
|
def migrate
|
||||||
Projects::MigrateForm.new(mirror_params).validate!
|
Projects::MigrateForm.new(mirror_params).validate!
|
||||||
@project = Projects::MigrateService.new(current_user, mirror_params).call
|
|
||||||
|
@project =
|
||||||
|
if enable_accelerator?(mirror_params[:clone_addr])
|
||||||
|
source_clone_url = mirror_params[:clone_addr]
|
||||||
|
uid_logger("########## 已动加速器 ##########")
|
||||||
|
result = Gitea::Accelerator::MigrateService.call(mirror_params)
|
||||||
|
if result[:status] == :success
|
||||||
|
Rails.logger.info "########## 加速镜像成功 ########## "
|
||||||
|
Projects::MigrateService.call(current_user,
|
||||||
|
mirror_params.merge(source_clone_url: source_clone_url,
|
||||||
|
clone_addr: accelerator_url(mirror_params[:repository_name])))
|
||||||
|
else
|
||||||
|
Projects::MigrateService.call(current_user, mirror_params)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Projects::MigrateService.call(current_user, mirror_params)
|
||||||
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ class PullRequestsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def pr_merge
|
def pr_merge
|
||||||
return render_forbidden("你没有权限操作.") unless current_user.project_manager?(@project)
|
return render_forbidden("你没有权限操作.") unless @project.operator?(current_user)
|
||||||
|
|
||||||
if params[:do].blank?
|
if params[:do].blank?
|
||||||
normal_status(-1, "请选择合并方式")
|
normal_status(-1, "请选择合并方式")
|
||||||
|
|
@ -149,12 +149,12 @@ class PullRequestsController < ApplicationController
|
||||||
begin
|
begin
|
||||||
result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params)
|
result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params)
|
||||||
|
|
||||||
if result && @pull_request.merge!
|
if result.status == 200 && @pull_request.merge!
|
||||||
@pull_request.project_trend_status!
|
@pull_request.project_trend_status!
|
||||||
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
|
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
|
||||||
normal_status(1, "合并成功")
|
normal_status(1, "合并成功")
|
||||||
else
|
else
|
||||||
normal_status(-1, "合并失败")
|
normal_status(-1, result.message)
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
normal_status(-1, e.message)
|
normal_status(-1, e.message)
|
||||||
|
|
@ -215,7 +215,7 @@ class PullRequestsController < ApplicationController
|
||||||
def get_relatived
|
def get_relatived
|
||||||
@project_tags = @project.issue_tags&.select(:id,:name, :color).as_json
|
@project_tags = @project.issue_tags&.select(:id,:name, :color).as_json
|
||||||
@project_versions = @project.versions&.select(:id,:name, :status).as_json
|
@project_versions = @project.versions&.select(:id,:name, :status).as_json
|
||||||
@project_members = @project.members_user_infos
|
@project_members = @project.all_developers
|
||||||
@project_priories = IssuePriority&.select(:id,:name, :position).as_json
|
@project_priories = IssuePriority&.select(:id,:name, :position).as_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ class SettingsController < ApplicationController
|
||||||
get_add_menu
|
get_add_menu
|
||||||
get_common_menu
|
get_common_menu
|
||||||
get_personal_menu
|
get_personal_menu
|
||||||
|
get_third_party
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -40,6 +40,14 @@ class SettingsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_third_party
|
||||||
|
@third_party = []
|
||||||
|
@third_party << {
|
||||||
|
name: 'educoder',
|
||||||
|
url: EducoderOauth.oauth_url
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def get_site_url(key, value)
|
def get_site_url(key, value)
|
||||||
key.to_s === "url" ? append_http(reset_site_url(value)) : reset_site_url(value)
|
key.to_s === "url" ? append_http(reset_site_url(value)) : reset_site_url(value)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -27,12 +27,24 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
def show
|
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 = @user.composes.size
|
||||||
@user_composes_count = 0
|
@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_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? @user.projects : @user.projects.visible
|
@user_org_count = user_organizations.size
|
||||||
|
normal_projects = Project.members_projects(@user.id).to_sql
|
||||||
|
org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @user.id}).to_sql
|
||||||
|
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||||
|
user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? projects : projects.visible
|
||||||
@projects_common_count = user_projects.common.size
|
@projects_common_count = user_projects.common.size
|
||||||
@projects_mirrior_count = user_projects.mirror.size
|
@projects_mirrior_count = user_projects.mirror.size
|
||||||
@projects_sync_mirrior_count = user_projects.sync_mirror.size
|
@projects_sync_mirrior_count = user_projects.sync_mirror.size
|
||||||
|
|
@ -249,7 +261,7 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
|
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
|
||||||
if interactor.success?
|
if interactor.success?
|
||||||
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_EDIT_INFO)
|
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE)
|
||||||
render_ok
|
render_ok
|
||||||
else
|
else
|
||||||
render_error(interactor.error)
|
render_error(interactor.error)
|
||||||
|
|
|
||||||
|
|
@ -526,3 +526,241 @@ await octokit.request('POST /api/jaser/jasder_test/forks.json')
|
||||||
"identifier": "newadm"
|
"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分钟前"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -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
|
# Users
|
||||||
|
|
||||||
## 获取当前登陆用户信息
|
## 获取当前登陆用户信息
|
||||||
|
|
@ -40,3 +46,390 @@ await octokit.request('GET /api/users/me.json')
|
||||||
<aside class="success">
|
<aside class="success">
|
||||||
Success Data.
|
Success Data.
|
||||||
</aside>
|
</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小时前"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
module Admins::ProjectsHelper
|
||||||
|
|
||||||
|
def link_to_project(project)
|
||||||
|
owner = project.owner
|
||||||
|
|
||||||
|
if owner.is_a?(User)
|
||||||
|
link_to(project.owner&.real_name, "/users/#{project&.owner&.login}", target: '_blank')
|
||||||
|
elsif owner.is_a?(Organization)
|
||||||
|
link_to(project.owner&.real_name, "/organize/#{project&.owner&.login}", target: '_blank')
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -34,15 +34,14 @@ module ProjectsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def json_response(project, user)
|
def json_response(project, user)
|
||||||
# repo = project.repository
|
repo = Repository.includes(:mirror).select(:id, :mirror_url, :source_clone_url).find_by(project: project)
|
||||||
repo = Repository.includes(:mirror).select(:id, :mirror_url).find_by(project: project)
|
|
||||||
|
|
||||||
tmp_json = {}
|
tmp_json = {}
|
||||||
unless project.common?
|
unless project.common?
|
||||||
tmp_json = tmp_json.merge({
|
tmp_json = tmp_json.merge({
|
||||||
mirror_status: repo.mirror_status,
|
mirror_status: repo.mirror_status,
|
||||||
mirror_num: repo.mirror_num,
|
mirror_num: repo.mirror_num,
|
||||||
mirror_url: repo.mirror_url,
|
mirror_url: repo.source_clone_url || repo.mirror_url,
|
||||||
first_sync: repo.first_sync?
|
first_sync: repo.first_sync?
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -124,14 +124,13 @@ module TagChosenHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_cache_collaborators(project)
|
def render_cache_collaborators(project)
|
||||||
cache_key = "all_collaborators/#{project.members.maximum('created_on')}"
|
cache_key = "all_collaborators/#{project.all_collaborators.maximum('created_on')}"
|
||||||
|
|
||||||
Rails.cache.fetch(cache_key) do
|
Rails.cache.fetch(cache_key) do
|
||||||
project.members.includes(:user).collect do |event|
|
project.all_collaborators.order(created_on: :desc).collect do |user|
|
||||||
{
|
{
|
||||||
id: event.user&.id,
|
id: user&.id,
|
||||||
name: event.user&.show_real_name,
|
name: user&.show_real_name,
|
||||||
avatar_url: url_to_avatar(event.user),
|
avatar_url: url_to_avatar(user),
|
||||||
is_chosen: '0'
|
is_chosen: '0'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
@ -171,10 +170,8 @@ module TagChosenHelper
|
||||||
# depended_issues_id = @depended_issues_id
|
# depended_issues_id = @depended_issues_id
|
||||||
|
|
||||||
end
|
end
|
||||||
project_members = project.members_user_infos
|
|
||||||
project_members_info = [] #指派给
|
project_members_info = [] #指派给
|
||||||
project_members.includes(user: :user_extension).each do |member|
|
project.all_collaborators.includes(:user_extension).each do |user|
|
||||||
user = member&.user
|
|
||||||
if user
|
if user
|
||||||
real_name = user.try(:show_real_name)
|
real_name = user.try(:show_real_name)
|
||||||
user_id = user.id
|
user_id = user.id
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
module EducoderOauth
|
||||||
|
class << self
|
||||||
|
attr_accessor :client_id, :client_secret, :base_url, :redirect_uri
|
||||||
|
|
||||||
|
def logger
|
||||||
|
@_logger ||= STDOUT
|
||||||
|
end
|
||||||
|
|
||||||
|
def logger=(l)
|
||||||
|
@_logger = l
|
||||||
|
end
|
||||||
|
|
||||||
|
def oauth_url
|
||||||
|
"#{base_url}/oauth2?call_url=/oauth/authorize?client_id=#{client_id}&redirect_uri=#{URI.encode_www_form_component(redirect_uri)}&response_type=code"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
require 'oauth2'
|
||||||
|
|
||||||
|
module EducoderOauth::Service
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def request(method, url, params)
|
||||||
|
begin
|
||||||
|
Rails.logger.info("[EducoderOauth] [#{method.to_s.upcase}] #{url} || #{params}")
|
||||||
|
|
||||||
|
client = Faraday.new(url: EducoderOauth.base_url)
|
||||||
|
response = client.public_send(method, url, params)
|
||||||
|
result = JSON.parse(response.body)
|
||||||
|
|
||||||
|
Rails.logger.info("[EducoderOauth] [#{response.status}] #{result}")
|
||||||
|
|
||||||
|
result
|
||||||
|
rescue Exception => e
|
||||||
|
raise Educoder::TipException.new(e.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def access_token(code)
|
||||||
|
begin
|
||||||
|
Rails.logger.info("[EducoderOauth] [code] #{code} ")
|
||||||
|
Rails.logger.info("[EducoderOauth] [redirect_uri] #{EducoderOauth.redirect_uri} ")
|
||||||
|
client = OAuth2::Client.new(EducoderOauth.client_id, EducoderOauth.client_secret, site: EducoderOauth.base_url)
|
||||||
|
result = client.auth_code.get_token(code, redirect_uri: EducoderOauth.redirect_uri).to_hash
|
||||||
|
return result
|
||||||
|
rescue Exception => e
|
||||||
|
raise Educoder::TipException.new(e.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_info(access_token)
|
||||||
|
request(:get, '/api/users/info.json', {access_token: access_token})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -19,5 +19,10 @@
|
||||||
class AppliedMessage < ApplicationRecord
|
class AppliedMessage < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :applied, polymorphic: true
|
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -11,6 +11,14 @@ module ProjectOperable
|
||||||
has_many :team_projects, dependent: :destroy
|
has_many :team_projects, dependent: :destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_owner_permission(creator)
|
||||||
|
return unless owner.is_a?(Organization)
|
||||||
|
owner.build_permit_team_projects!(id)
|
||||||
|
# 避免自己创建的项目,却无法拥有访问权,因为该用户所在团队暂未获得项目访问权
|
||||||
|
return if creator.nil? || owner.is_owner?(creator.id)
|
||||||
|
add_member!(creator.id, "Manager")
|
||||||
|
end
|
||||||
|
|
||||||
def add_member!(user_id, role_name='Developer')
|
def add_member!(user_id, role_name='Developer')
|
||||||
member = members.create!(user_id: user_id)
|
member = members.create!(user_id: user_id)
|
||||||
set_developer_role(member, role_name)
|
set_developer_role(member, role_name)
|
||||||
|
|
@ -78,12 +86,16 @@ module ProjectOperable
|
||||||
if owner.is_a?(User)
|
if owner.is_a?(User)
|
||||||
reporters.exists?(user_id: user.id)
|
reporters.exists?(user_id: user.id)
|
||||||
elsif owner.is_a?(Organization)
|
elsif owner.is_a?(Organization)
|
||||||
reporters.exists?(user_id: user.id) || owner.is_read?(user.id)
|
reporters.exists?(user_id: user.id) || owner.is_only_read?(user.id)
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def operator?(user)
|
||||||
|
user.admin? || !reporter?(user)
|
||||||
|
end
|
||||||
|
|
||||||
def set_developer_role(member, role_name)
|
def set_developer_role(member, role_name)
|
||||||
role = Role.find_by(name: role_name)
|
role = Role.find_by(name: role_name)
|
||||||
member.member_roles.create!(role: role)
|
member.member_roles.create!(role: role)
|
||||||
|
|
@ -92,4 +104,22 @@ module ProjectOperable
|
||||||
def has_menu_permission(unit_type)
|
def has_menu_permission(unit_type)
|
||||||
self.project_units.where(unit_type: unit_type).exists?
|
self.project_units.where(unit_type: unit_type).exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def all_collaborators
|
||||||
|
member_sql = User.joins(members: :roles).where(members: {project_id: self.id}, roles: {name: %w(Manager Developer Reporter)}).to_sql
|
||||||
|
team_user_sql = User.joins(teams: :team_projects).where(team_projects: {project_id: self.id}).to_sql
|
||||||
|
return User.from("( #{ member_sql } UNION #{ team_user_sql } ) AS users").distinct
|
||||||
|
end
|
||||||
|
|
||||||
|
def all_developers
|
||||||
|
member_sql = User.joins(members: :roles).where(members: {project_id: self.id}, roles: {name: %w(Manager Developer)}).to_sql
|
||||||
|
team_user_sql = User.joins(teams: :team_projects).where(teams: {authorize: %w(owner admin write)}, team_projects: {project_id: self.id}).to_sql
|
||||||
|
return User.from("( #{ member_sql } UNION #{ team_user_sql } ) AS users").distinct
|
||||||
|
end
|
||||||
|
|
||||||
|
def all_managers
|
||||||
|
member_sql = User.joins(members: :roles).where(members: {project_id: self.id}, roles: {name: %w(Manager)}).to_sql
|
||||||
|
team_user_sql = User.joins(teams: :team_projects).where(teams: {authorize: %w(owner admin)},team_projects: {project_id: self.id}).to_sql
|
||||||
|
return User.from("( #{ member_sql} UNION #{ team_user_sql } ) AS users").distinct
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -108,12 +108,23 @@ class Organization < Owner
|
||||||
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read write admin owner)}).present?
|
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read write admin owner)}).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_only_read?(user_id)
|
||||||
|
team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read)}).present?
|
||||||
|
end
|
||||||
|
|
||||||
# 是不是所有者团队的最后一个成员
|
# 是不是所有者团队的最后一个成员
|
||||||
def is_owner_team_last_one?(user_id)
|
def is_owner_team_last_one?(user_id)
|
||||||
owner_team_users = team_users.joins(:team).where(teams: {authorize: %w(owner)})
|
owner_team_users = team_users.joins(:team).where(teams: {authorize: %w(owner)})
|
||||||
owner_team_users.pluck(:user_id).include?(user_id) && owner_team_users.size == 1
|
owner_team_users.pluck(:user_id).include?(user_id) && owner_team_users.size == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 为包含组织所有项目的团队创建项目访问权限
|
||||||
|
def build_permit_team_projects!(project_id)
|
||||||
|
teams.where(includes_all_project: true).each do |team|
|
||||||
|
TeamProject.build(id, team.id, project_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def real_name
|
def real_name
|
||||||
name = lastname + firstname
|
name = lastname + firstname
|
||||||
name = name.blank? ? (nickname.blank? ? login : nickname) : name
|
name = name.blank? ? (nickname.blank? ? login : nickname) : name
|
||||||
|
|
|
||||||
|
|
@ -66,4 +66,6 @@ class Owner < ApplicationRecord
|
||||||
|
|
||||||
has_many :projects, foreign_key: :user_id, dependent: :destroy
|
has_many :projects, foreign_key: :user_id, dependent: :destroy
|
||||||
has_many :repositories, foreign_key: :user_id, dependent: :destroy
|
has_many :repositories, foreign_key: :user_id, dependent: :destroy
|
||||||
|
has_many :applied_transfer_projects, dependent: :destroy
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@
|
||||||
# index_projects_on_updated_on (updated_on)
|
# index_projects_on_updated_on (updated_on)
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class Project < ApplicationRecord
|
class Project < ApplicationRecord
|
||||||
include Matchable
|
include Matchable
|
||||||
include Publicable
|
include Publicable
|
||||||
|
|
@ -112,6 +113,7 @@ class Project < ApplicationRecord
|
||||||
has_one :project_detail, dependent: :destroy
|
has_one :project_detail, dependent: :destroy
|
||||||
has_many :team_projects, dependent: :destroy
|
has_many :team_projects, dependent: :destroy
|
||||||
has_many :project_units, dependent: :destroy
|
has_many :project_units, dependent: :destroy
|
||||||
|
has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy
|
||||||
|
|
||||||
after_save :check_project_members
|
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)}
|
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 +297,7 @@ class Project < ApplicationRecord
|
||||||
update_column(:updated_on, time)
|
update_column(:updated_on, time)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_transfering
|
||||||
|
applied_transfer_project&.common? ? true : false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ class ProjectUnit < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.update_by_unit_types!(project, types)
|
def self.update_by_unit_types!(project, types)
|
||||||
|
# 默认code类型自动创建
|
||||||
|
types << "code"
|
||||||
project.project_units.where.not(unit_type: types).each(&:destroy!)
|
project.project_units.where.not(unit_type: types).each(&:destroy!)
|
||||||
types.each do |type|
|
types.each do |type|
|
||||||
project.project_units.find_or_create_by!(unit_type: type)
|
project.project_units.find_or_create_by!(unit_type: type)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@
|
||||||
# version_releases_count :integer default("0")
|
# version_releases_count :integer default("0")
|
||||||
# fork_url :string(255)
|
# fork_url :string(255)
|
||||||
# is_mirror :boolean default("0")
|
# is_mirror :boolean default("0")
|
||||||
|
# accelerator_url :string(255) default("")
|
||||||
|
# source_clone_url :string(255) default("")
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class Token < ActiveRecord::Base
|
||||||
# Returns the active user who owns the key for the given action
|
# Returns the active user who owns the key for the given action
|
||||||
def self.find_active_user(action, key, validity_days=nil)
|
def self.find_active_user(action, key, validity_days=nil)
|
||||||
user = find_user(action, key, validity_days)
|
user = find_user(action, key, validity_days)
|
||||||
if user && user.active?
|
if user && (user.active? || user.need_edit_info?)
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ class User < Owner
|
||||||
STATUS_ACTIVE = 1
|
STATUS_ACTIVE = 1
|
||||||
STATUS_REGISTERED = 2
|
STATUS_REGISTERED = 2
|
||||||
STATUS_LOCKED = 3
|
STATUS_LOCKED = 3
|
||||||
|
STATUS_EDIT_INFO = 4
|
||||||
|
|
||||||
# tpi tpm权限控制
|
# tpi tpm权限控制
|
||||||
EDU_ADMIN = 1 # 超级管理员
|
EDU_ADMIN = 1 # 超级管理员
|
||||||
|
|
@ -147,9 +148,14 @@ class User < Owner
|
||||||
has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction'
|
has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction'
|
||||||
|
|
||||||
# has_many :attendances
|
# 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 :applied_projects, dependent: :destroy
|
||||||
|
has_many :operate_applied_transfer_projects, class_name: 'AppliedTransferProject', dependent: :destroy
|
||||||
|
has_many :members, dependent: :destroy
|
||||||
|
has_many :team_users, dependent: :destroy
|
||||||
|
has_many :teams, through: :team_users
|
||||||
|
|
||||||
# 教学案例
|
# 教学案例
|
||||||
# has_many :libraries, dependent: :destroy
|
# has_many :libraries, dependent: :destroy
|
||||||
|
|
@ -160,7 +166,7 @@ class User < Owner
|
||||||
has_many :organizations, through: :organization_users
|
has_many :organizations, through: :organization_users
|
||||||
|
|
||||||
# Groups and active users
|
# Groups and active users
|
||||||
scope :active, lambda { where(status: STATUS_ACTIVE) }
|
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
|
||||||
scope :like, lambda { |keywords|
|
scope :like, lambda { |keywords|
|
||||||
where("LOWER(concat(lastname, firstname, login, mail)) LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
|
where("LOWER(concat(lastname, firstname, login, mail)) LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
|
||||||
}
|
}
|
||||||
|
|
@ -381,6 +387,10 @@ class User < Owner
|
||||||
status == STATUS_LOCKED
|
status == STATUS_LOCKED
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def need_edit_info?
|
||||||
|
status == STATUS_EDIT_INFO
|
||||||
|
end
|
||||||
|
|
||||||
def activate
|
def activate
|
||||||
self.status = STATUS_ACTIVE
|
self.status = STATUS_ACTIVE
|
||||||
end
|
end
|
||||||
|
|
@ -393,6 +403,10 @@ class User < Owner
|
||||||
self.status = STATUS_LOCKED
|
self.status = STATUS_LOCKED
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def need_edit_info
|
||||||
|
self.status = STATUS_EDIT_INFO
|
||||||
|
end
|
||||||
|
|
||||||
def activate!
|
def activate!
|
||||||
update_attribute(:status, STATUS_ACTIVE)
|
update_attribute(:status, STATUS_ACTIVE)
|
||||||
end
|
end
|
||||||
|
|
@ -405,6 +419,10 @@ class User < Owner
|
||||||
update_attribute(:status, STATUS_LOCKED)
|
update_attribute(:status, STATUS_LOCKED)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def need_edit_info!
|
||||||
|
update_attribute(:status, STATUS_EDIT_INFO)
|
||||||
|
end
|
||||||
|
|
||||||
# 课程用户身份
|
# 课程用户身份
|
||||||
def course_identity(course)
|
def course_identity(course)
|
||||||
if !logged?
|
if !logged?
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ class Projects::ListMyQuery < ApplicationQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
if params[:category].blank?
|
if params[:category].blank?
|
||||||
projects = projects.members_projects(user.id)
|
normal_projects = projects.members_projects(user.id).to_sql
|
||||||
|
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: user.id}).to_sql
|
||||||
|
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
|
||||||
elsif params[:category].to_s == "join"
|
elsif params[:category].to_s == "join"
|
||||||
normal_projects = projects.where.not(user_id: user.id).members_projects(user.id).to_sql
|
normal_projects = projects.where.not(user_id: user.id).members_projects(user.id).to_sql
|
||||||
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: user.id}).to_sql
|
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: user.id}).to_sql
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
class Gitea::Accelerator::MigrateService < ApplicationService
|
||||||
|
attr_reader :params
|
||||||
|
|
||||||
|
# params description:
|
||||||
|
# {
|
||||||
|
# auth_username string
|
||||||
|
# clone_addr* string #clone地址
|
||||||
|
# description string
|
||||||
|
# issues boolean
|
||||||
|
# labels boolean
|
||||||
|
# milestones boolean
|
||||||
|
# mirror boolean
|
||||||
|
# private boolean
|
||||||
|
# pull_requests boolean
|
||||||
|
# releases boolean
|
||||||
|
# repo_name* string #仓库名称
|
||||||
|
# uid* integer($int64) #gitea用户id或组织id
|
||||||
|
# wiki boolean
|
||||||
|
# }
|
||||||
|
# EX:
|
||||||
|
# params = {
|
||||||
|
# clone_addr: 'xxx.com',
|
||||||
|
# repo_name: 'repo_name',
|
||||||
|
# uid: 2,
|
||||||
|
# private: false
|
||||||
|
# }
|
||||||
|
|
||||||
|
def initialize(params)
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
return error('[gitea:] accelerator config missing') if check_accelerator!
|
||||||
|
response = post(url, request_params)
|
||||||
|
|
||||||
|
render_status(response)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def request_params
|
||||||
|
{
|
||||||
|
uid: access_uid,
|
||||||
|
clone_addr: params[:clone_addr],
|
||||||
|
repo_name: params[:repository_name],
|
||||||
|
auth_username: params[:auth_username],
|
||||||
|
auth_password: params[:auth_password],
|
||||||
|
mirror: ActiveModel::Type::Boolean.new.cast(params[:is_mirror])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def url
|
||||||
|
"/repos/migrate".freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def post(url, params)
|
||||||
|
puts "[gitea] request params: #{params}"
|
||||||
|
puts "[gitea] access_username: #{access_username}"
|
||||||
|
puts "[gitea] access_password: #{access_password}"
|
||||||
|
conn.post do |req|
|
||||||
|
req.url full_url(url)
|
||||||
|
req.body = params.to_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def conn
|
||||||
|
@client ||= begin
|
||||||
|
Faraday.new(url: domain) do |req|
|
||||||
|
req.request :url_encoded
|
||||||
|
req.headers['Content-Type'] = 'application/json'
|
||||||
|
req.response :logger # 显示日志
|
||||||
|
req.adapter Faraday.default_adapter
|
||||||
|
req.basic_auth(access_username, access_password)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@client
|
||||||
|
end
|
||||||
|
|
||||||
|
def base_url
|
||||||
|
accelerator["base_url"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain
|
||||||
|
accelerator["domain"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_url
|
||||||
|
[domain, base_url].join('')
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_url(api_rest, action='post')
|
||||||
|
url = [api_url, api_rest].join('').freeze
|
||||||
|
url = action === 'get' ? url : URI.escape(url)
|
||||||
|
puts "[gitea] request url: #{url}"
|
||||||
|
url
|
||||||
|
end
|
||||||
|
|
||||||
|
def access_username
|
||||||
|
accelerator["access_key_id"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def access_password
|
||||||
|
accelerator["access_key_secret"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def access_uid
|
||||||
|
accelerator["access_admin_uid"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def accelerator
|
||||||
|
Gitea.gitea_config[:accelerator]
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_status(response)
|
||||||
|
puts "[gitea] response status: #{response.status}"
|
||||||
|
puts "[gitea] response body: #{response.body}"
|
||||||
|
case response.status
|
||||||
|
when 201
|
||||||
|
success
|
||||||
|
when 403
|
||||||
|
error('APIForbiddenError')
|
||||||
|
when 422
|
||||||
|
error('APIValidationError')
|
||||||
|
else
|
||||||
|
error("MigrateError")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def error(message)
|
||||||
|
{
|
||||||
|
status: :error,
|
||||||
|
message: message,
|
||||||
|
data: nil
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def success(data=nil)
|
||||||
|
{
|
||||||
|
status: :success,
|
||||||
|
message: nil,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_accelerator!
|
||||||
|
accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -176,6 +176,25 @@ class Gitea::ClientService < ApplicationService
|
||||||
[status, message, body]
|
[status, message, body]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_gitea_response(response)
|
||||||
|
status = response.status
|
||||||
|
body = response&.body
|
||||||
|
|
||||||
|
log_error(status, body)
|
||||||
|
message = nil
|
||||||
|
begin
|
||||||
|
translate = YAML.load(File.read('config/gitea_response.yml'))
|
||||||
|
|
||||||
|
self.class.to_s.underscore.split("/").map{|i| translate=translate[i]}
|
||||||
|
message = body.nil? ? translate[status]['default'] : JSON.parse(body)['message']
|
||||||
|
message = translate[status][message].nil? ? message : translate[status][message]
|
||||||
|
|
||||||
|
return [status, message]
|
||||||
|
rescue
|
||||||
|
return [status, message]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_body_by_status(status, body)
|
def get_body_by_status(status, body)
|
||||||
body, message =
|
body, message =
|
||||||
case status
|
case status
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class Gitea::PullRequest::MergeService < Gitea::ClientService
|
||||||
def call
|
def call
|
||||||
response = post(url, request_params)
|
response = post(url, request_params)
|
||||||
|
|
||||||
render_200_no_body(response)
|
render_gitea_response(response)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
class Projects::MigrateService < ApplicationService
|
class Projects::MigrateService < ApplicationService
|
||||||
attr_reader :user, :params
|
attr_reader :user, :params
|
||||||
|
attr_accessor :project
|
||||||
|
|
||||||
def initialize(user, params)
|
def initialize(user, params)
|
||||||
@user = user
|
@user = user
|
||||||
|
|
@ -11,6 +12,7 @@ class Projects::MigrateService < ApplicationService
|
||||||
if @project.save!
|
if @project.save!
|
||||||
ProjectUnit.init_types(@project.id)
|
ProjectUnit.init_types(@project.id)
|
||||||
Project.update_mirror_projects_count!
|
Project.update_mirror_projects_count!
|
||||||
|
@project.set_owner_permission(user)
|
||||||
Repositories::MigrateService.new(user, @project, repository_params).call
|
Repositories::MigrateService.new(user, @project, repository_params).call
|
||||||
else
|
else
|
||||||
#
|
#
|
||||||
|
|
@ -48,7 +50,8 @@ class Projects::MigrateService < ApplicationService
|
||||||
user_id: params[:user_id],
|
user_id: params[:user_id],
|
||||||
login: params[:auth_username],
|
login: params[:auth_username],
|
||||||
password: params[:auth_password],
|
password: params[:auth_password],
|
||||||
is_mirror: params[:is_mirror]
|
is_mirror: params[:is_mirror],
|
||||||
|
source_clone_url: params[:source_clone_url]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -23,6 +23,7 @@ class Projects::TransferService < ApplicationService
|
||||||
|
|
||||||
private
|
private
|
||||||
def update_owner
|
def update_owner
|
||||||
|
project.members.find_by(user_id: owner.id).destroy! if owner.is_a?(User)
|
||||||
project.update!(user_id: new_owner.id)
|
project.update!(user_id: new_owner.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -32,9 +33,8 @@ class Projects::TransferService < ApplicationService
|
||||||
|
|
||||||
def update_visit_teams
|
def update_visit_teams
|
||||||
if new_owner.is_a?(Organization)
|
if new_owner.is_a?(Organization)
|
||||||
new_owner.teams.where(includes_all_project: true).each do |team|
|
# 为包含组织所有项目的团队创建项目访问权限
|
||||||
TeamProject.build(new_owner.id, team.id, project.id)
|
new_owner.build_permit_team_projects(project.id)
|
||||||
end
|
|
||||||
else
|
else
|
||||||
project.team_projects.each(&:destroy!)
|
project.team_projects.each(&:destroy!)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
class PullRequests::MergeService < ApplicationService
|
class PullRequests::MergeService < ApplicationService
|
||||||
attr_reader :owner, :repo, :pull, :current_user, :params
|
attr_reader :owner, :repo, :pull, :current_user, :params
|
||||||
|
attr_accessor :status, :message
|
||||||
# eq:
|
# eq:
|
||||||
# PullRequests::MergeService.call(owner, repo, pull, current_user, params)
|
# PullRequests::MergeService.call(owner, repo, pull, current_user, params)
|
||||||
def initialize(owner, repo, pull, current_user, params)
|
def initialize(owner, repo, pull, current_user, params)
|
||||||
|
|
@ -15,6 +15,7 @@ class PullRequests::MergeService < ApplicationService
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
gitea_pull_merge!
|
gitea_pull_merge!
|
||||||
end
|
end
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -22,8 +23,7 @@ class PullRequests::MergeService < ApplicationService
|
||||||
def gitea_pull_merge!
|
def gitea_pull_merge!
|
||||||
result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login,
|
result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login,
|
||||||
@repo.identifier, @pull.gpid, gitea_merge_pull_params)
|
@repo.identifier, @pull.gpid, gitea_merge_pull_params)
|
||||||
|
@status, @message = result
|
||||||
result[:status] === 200 ? true : false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def gitea_merge_pull_params
|
def gitea_merge_pull_params
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ class Repositories::CreateService < ApplicationService
|
||||||
create_gitea_repository
|
create_gitea_repository
|
||||||
sync_project
|
sync_project
|
||||||
sync_repository
|
sync_repository
|
||||||
|
@project.set_owner_permission(user)
|
||||||
# if project.project_type == "common"
|
# if project.project_type == "common"
|
||||||
# chain_params = {
|
# chain_params = {
|
||||||
# type: "create",
|
# type: "create",
|
||||||
|
|
@ -44,19 +45,9 @@ class Repositories::CreateService < ApplicationService
|
||||||
@gitea_repository = Gitea::Repository::CreateService.new(user.gitea_token, gitea_repository_params).call
|
@gitea_repository = Gitea::Repository::CreateService.new(user.gitea_token, gitea_repository_params).call
|
||||||
elsif project.owner.is_a?(Organization)
|
elsif project.owner.is_a?(Organization)
|
||||||
@gitea_repository = Gitea::Organization::Repository::CreateService.call(user.gitea_token, project.owner.login, gitea_repository_params)
|
@gitea_repository = Gitea::Organization::Repository::CreateService.call(user.gitea_token, project.owner.login, gitea_repository_params)
|
||||||
project.owner.teams.each do |team|
|
|
||||||
next unless team.includes_all_project
|
|
||||||
TeamProject.build(project.user_id, team.id, project.id)
|
|
||||||
end
|
|
||||||
create_manager_member
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_manager_member
|
|
||||||
return if project.owner.is_owner?(user.id)
|
|
||||||
project.add_member!(user.id, "Manager")
|
|
||||||
end
|
|
||||||
|
|
||||||
def sync_project
|
def sync_project
|
||||||
if gitea_repository
|
if gitea_repository
|
||||||
project.update_columns(
|
project.update_columns(
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ class Repositories::MigrateService < ApplicationService
|
||||||
|
|
||||||
private
|
private
|
||||||
def repository_params
|
def repository_params
|
||||||
params.merge(project_id: project.id, identifier: params[:identifier])
|
params.merge(project_id: project.id,
|
||||||
|
identifier: params[:identifier],
|
||||||
|
source_clone_url: params[:source_clone_url])
|
||||||
end
|
end
|
||||||
|
|
||||||
def gitea_repository_params
|
def gitea_repository_params
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
|
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
|
||||||
<td><%= project.id %></td>
|
<td><%= project.id %></td>
|
||||||
<td class="text-left">
|
<td class="text-left">
|
||||||
<%= link_to(project.name, "/projects/#{project.id}", target: '_blank') %>
|
<%= link_to(project.name, "/projects/#{project&.owner&.login}/#{project.identifier}", target: '_blank') %>
|
||||||
</td>
|
</td>
|
||||||
<td><%= project.is_public ? '√' : '' %></td>
|
<td><%= project.is_public ? '√' : '' %></td>
|
||||||
<td><%= project.issues.size %></td>
|
<td><%= project.issues.size %></td>
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
<td><%= project.versions.size %></td>
|
<td><%= project.versions.size %></td>
|
||||||
<td><%= project.members.size %></td>
|
<td><%= project.members.size %></td>
|
||||||
<td>
|
<td>
|
||||||
<%= project.owner ? link_to(project.owner&.real_name, "/users/#{project.owner&.login}", target: '_blank') : "" %>
|
<%= link_to_project(project) %>
|
||||||
</td>
|
</td>
|
||||||
<td><%= project.created_on&.strftime('%Y-%m-%d %H:%M') %></td>
|
<td><%= project.created_on&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||||
<td class="action-container">
|
<td class="action-container">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ json.commits do
|
||||||
json.array! @compare_result['Commits'] do |commit|
|
json.array! @compare_result['Commits'] do |commit|
|
||||||
json.author do
|
json.author do
|
||||||
# TODO: 获取头像地址待优化
|
# TODO: 获取头像地址待优化
|
||||||
forge_user = User.includes(:user_extension).select(:id, :login).find_by(login: commit['Author']['Name'])
|
forge_user = User.includes(:user_extension).find_by(login: commit['Author']['Name'])
|
||||||
json.login commit['Author']['Name']
|
json.login commit['Author']['Name']
|
||||||
json.name commit['Author']['Name']
|
json.name commit['Author']['Name']
|
||||||
json.image_url forge_user.nil? ? '' : url_to_avatar(forge_user)
|
json.image_url forge_user.nil? ? '' : url_to_avatar(forge_user)
|
||||||
|
|
@ -12,7 +12,7 @@ json.commits do
|
||||||
|
|
||||||
json.committer do
|
json.committer do
|
||||||
# TODO: 获取头像地址待优化
|
# TODO: 获取头像地址待优化
|
||||||
forge_user = User.includes(:user_extension).select(:id, :login).find_by(login: commit['Committer']['Name'])
|
forge_user = User.includes(:user_extension).find_by(login: commit['Committer']['Name'])
|
||||||
json.login commit['Committer']['Name']
|
json.login commit['Committer']['Name']
|
||||||
json.name commit['Committer']['Name']
|
json.name commit['Committer']['Name']
|
||||||
json.image_url forge_user.nil? ? '' : url_to_avatar(forge_user)
|
json.image_url forge_user.nil? ? '' : url_to_avatar(forge_user)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
json.total_count @organizations.size
|
||||||
|
json.organizations @organizations do |org|
|
||||||
|
json.partial! "/organizations/organizations/simple", locals: {organization: org}
|
||||||
|
end
|
||||||
|
|
@ -5,10 +5,10 @@ json.issue_priories @project_priories
|
||||||
json.project_author @project.owner.try(:show_real_name)
|
json.project_author @project.owner.try(:show_real_name)
|
||||||
json.project_name @project.try(:name)
|
json.project_name @project.try(:name)
|
||||||
json.members do
|
json.members do
|
||||||
json.array! @project_members.to_a.each do |member|
|
json.array! @project_members.to_a.each do |user|
|
||||||
json.id member.user_id
|
json.id user.id
|
||||||
json.login member.user.try(:login)
|
json.login user.try(:login)
|
||||||
json.name member.user.try(:show_real_name)
|
json.name user.try(:show_real_name)
|
||||||
json.avatar_url url_to_avatar(member.user)
|
json.avatar_url url_to_avatar(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -21,7 +21,7 @@ json.versions_count @project.versions_count #里程碑数量
|
||||||
json.version_releases_count @project.releases_size(@user.try(:id), "all")
|
json.version_releases_count @project.releases_size(@user.try(:id), "all")
|
||||||
json.version_releasesed_count @project.releases_size(@user.try(:id), "released") #已发行的版本
|
json.version_releasesed_count @project.releases_size(@user.try(:id), "released") #已发行的版本
|
||||||
json.permission render_permission(@user, @project)
|
json.permission render_permission(@user, @project)
|
||||||
json.mirror_url @project&.repository.mirror_url
|
json.mirror_url @project&.repository.source_clone_url
|
||||||
json.mirror @project&.repository.mirror_url.present?
|
json.mirror @project&.repository.mirror_url.present?
|
||||||
json.type @project.numerical_for_project_type
|
json.type @project.numerical_for_project_type
|
||||||
json.open_devops @project.open_devops?
|
json.open_devops @project.open_devops?
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,8 @@ json.private !@project.is_public
|
||||||
json.website @project.website
|
json.website @project.website
|
||||||
json.project_units @project.project_units.pluck(:unit_type)
|
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
|
||||||
|
|
@ -56,4 +56,5 @@ json.setting do
|
||||||
end
|
end
|
||||||
|
|
||||||
json.common @common
|
json.common @common
|
||||||
|
json.third_party @third_party
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
json.id user.id
|
if user.present?
|
||||||
json.name user.real_name
|
json.id user.id
|
||||||
json.login user.login
|
json.type user.type
|
||||||
json.image_url url_to_avatar(user)
|
json.name user.real_name
|
||||||
|
json.login user.login
|
||||||
|
json.image_url url_to_avatar(user)
|
||||||
|
else
|
||||||
|
json.nil!
|
||||||
|
end
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
json.partial! "/projects/applied_transfer_projects/detail", locals: {object: @applied_transfer_project}
|
||||||
|
|
@ -8,8 +8,9 @@ json.is_teacher @user.user_extension&.teacher?
|
||||||
json.user_identity @user.identity
|
json.user_identity @user.identity
|
||||||
json.tidding_count 0
|
json.tidding_count 0
|
||||||
json.user_phone_binded @user.phone.present?
|
json.user_phone_binded @user.phone.present?
|
||||||
|
json.need_edit_info @user.need_edit_info?
|
||||||
# json.phone @user.phone
|
# json.phone @user.phone
|
||||||
# json.email @user.mail
|
json.email @user.mail
|
||||||
json.profile_completed @user.profile_completed?
|
json.profile_completed @user.profile_completed?
|
||||||
json.professional_certification @user.professional_certification
|
json.professional_certification @user.professional_certification
|
||||||
json.devops_step @user.devops_step
|
json.devops_step @user.devops_step
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ json.user_identity @user.identity
|
||||||
json.is_watch current_user&.watched?(@user)
|
json.is_watch current_user&.watched?(@user)
|
||||||
json.watched_count @user.fan_count #粉丝
|
json.watched_count @user.fan_count #粉丝
|
||||||
json.watching_count @user.follow_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.undo_events @undo_events
|
||||||
json.user_composes_count @user_composes_count
|
json.user_composes_count @user_composes_count
|
||||||
json.user_org_count @user_org_count
|
json.user_org_count @user_org_count
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,23 @@ default: &default
|
||||||
cate_id: '-1'
|
cate_id: '-1'
|
||||||
callback_url: 'callback_url'
|
callback_url: 'callback_url'
|
||||||
signature_key: 'test12345678'
|
signature_key: 'test12345678'
|
||||||
|
educoder:
|
||||||
|
client_id: 'e9ce4d5ba1698d6f7d01d8ee2959776c7a6d743ebe94da2341e288fd2fbf60aa'
|
||||||
|
client_secret: '6ff84dd75eddd859c5bd0e7a791b58bc5ad1ba4fbb30bc9db37cb0baf9f33012'
|
||||||
|
base_url: 'https://test-data.educoder.net'
|
||||||
|
redirect_uri: 'https://testforgeplus.trustie.net/api/auth/educoder/callback'
|
||||||
|
|
||||||
gitea:
|
gitea:
|
||||||
access_key_id: 'root'
|
access_key_id: ''
|
||||||
access_key_secret: '_Trustie_10010'
|
access_key_secret: ''
|
||||||
domain: 'https://testgitea.trustie.net'
|
domain: 'https://testgit.trustie.net'
|
||||||
base_url: '/api/v1'
|
base_url: '/api/v1'
|
||||||
|
accelerator:
|
||||||
|
access_key_id: ''
|
||||||
|
access_key_secret: ''
|
||||||
|
access_admin_uid: 1
|
||||||
|
domain: 'https://testgit.trustie.net'
|
||||||
|
base_url: '/api/v1'
|
||||||
|
|
||||||
|
|
||||||
production:
|
production:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
gitea:
|
||||||
|
pull_request:
|
||||||
|
merge_service:
|
||||||
|
405:
|
||||||
|
default: "此合并请求有变更与目标分支冲突。"
|
||||||
|
'User not allowed to merge PR': "用户没有合并请求的权限"
|
||||||
|
403:
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
oauth_config = {}
|
||||||
|
begin
|
||||||
|
config = Rails.application.config_for(:configuration)
|
||||||
|
oauth_config = config.dig('oauth', 'educoder')
|
||||||
|
raise 'oauth educoder config missing' if oauth_config.blank?
|
||||||
|
rescue => ex
|
||||||
|
raise ex if Rails.env.production?
|
||||||
|
|
||||||
|
puts %Q{\033[33m [warning] wechat oauth config or configuration.yml missing,
|
||||||
|
please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m}
|
||||||
|
end
|
||||||
|
|
||||||
|
EducoderOauth.client_id = oauth_config['client_id']
|
||||||
|
EducoderOauth.client_secret = oauth_config['client_secret']
|
||||||
|
EducoderOauth.base_url = oauth_config['base_url']
|
||||||
|
EducoderOauth.redirect_uri = oauth_config['redirect_uri']
|
||||||
|
|
@ -257,6 +257,13 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
scope module: :users do
|
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 :organizations, only: [:index]
|
||||||
# resources :projects, only: [:index]
|
# resources :projects, only: [:index]
|
||||||
# resources :subjects, only: [:index]
|
# resources :subjects, only: [:index]
|
||||||
|
|
@ -314,6 +321,7 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
get '/auth/qq/callback', to: 'oauth/qq#create'
|
get '/auth/qq/callback', to: 'oauth/qq#create'
|
||||||
get '/auth/wechat/callback', to: 'oauth/wechat#create'
|
get '/auth/wechat/callback', to: 'oauth/wechat#create'
|
||||||
|
get '/auth/educoder/callback', to: 'oauth/educoder#create'
|
||||||
resource :bind_user, only: [:create]
|
resource :bind_user, only: [:create]
|
||||||
|
|
||||||
resources :hot_keywords, only: [:index]
|
resources :hot_keywords, only: [:index]
|
||||||
|
|
@ -532,6 +540,12 @@ Rails.application.routes.draw do
|
||||||
scope module: :projects do
|
scope module: :projects do
|
||||||
resources :teams, only: [:index, :create, :destroy]
|
resources :teams, only: [:index, :create, :destroy]
|
||||||
resources :project_units, only: [:index, :create]
|
resources :project_units, only: [:index, :create]
|
||||||
|
resources :applied_transfer_projects, only: [:create] do
|
||||||
|
collection do
|
||||||
|
get :organizations
|
||||||
|
post :cancel
|
||||||
|
end
|
||||||
|
end
|
||||||
scope do
|
scope do
|
||||||
get(
|
get(
|
||||||
'/blob/*id/diff',
|
'/blob/*id/diff',
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddAcceleratorUrlToRepositories < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :repositories, :accelerator_url, :string, default: ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddSourceCloneUrlToRepositories < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :repositories, :source_clone_url, :string, default: ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace :sync_org_project_permission do
|
||||||
|
desc "sync organization project team permissions"
|
||||||
|
task mirror: :environment do
|
||||||
|
Project.mirror.includes(:team_projects,:owner).where(team_projects: {id: nil}, users: {type: 'Organization'}).find_each do |project|
|
||||||
|
project.set_owner_permission(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
1336
public/docs/api.html
1336
public/docs/api.html
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue