Merge branch 'pre_trustie_server' into trustie_server

This commit is contained in:
yystopf 2022-07-08 14:20:21 +08:00
commit 42a22f38b0
67 changed files with 1770 additions and 634 deletions

View File

@ -134,3 +134,5 @@ gem 'jwt'
gem 'doorkeeper' gem 'doorkeeper'
gem 'doorkeeper-jwt' gem 'doorkeeper-jwt'
gem 'gitea-client', '~> 0.8.2'

View File

@ -0,0 +1,18 @@
class Api::V1::BaseController < ApplicationController
include Api::ProjectHelper
include Api::UserHelper
before_action :doorkeeper_authorize!
skip_before_action :user_setup
protected
def current_user
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end
def require_manager_above
@project = load_project
return render_forbidden unless current_user.admin? && @project.manager?(current_user)
end
end

View File

@ -0,0 +1,55 @@
class Api::V1::Projects::WebhooksController < Api::V1::BaseController
before_action :require_manager_above
before_action :find_webhook, only: [:show, :update, :destroy, :tests, :hooktasks]
def index
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
@webhooks = @project.webhooks
@webhooks = kaminari_paginate(@webhooks)
end
def create
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, webhook_params, current_user&.gitea_token)
end
def show
@result_object = Api::V1::Projects::Webhooks::GetService.call(@project, params[:id], current_user&.gitea_token)
end
def update
@result_object = Api::V1::Projects::Webhooks::UpdateService.call(@project, params[:id], webhook_params, current_user&.gitea_token)
end
def destroy
@result_object = Api::V1::Projects::Webhooks::DeleteService.call(@project, params[:id], current_user&.gitea_token)
if @result_object
return render_ok
else
return render_error('删除失败!')
end
end
def tests
@result_object = Api::V1::Projects::Webhooks::TestsService.call(@project, params[:id], current_user&.gitea_token)
if @result_object
return render_ok
else
return render_error('推送失败!')
end
end
def hooktasks
@hooktasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
@hooktasks = kaminari_paginate(@hooktasks)
end
private
def webhook_params
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
end
def find_webhook
@webhook = Gitea::Webhook.find_by_id(params[:id])
return render_not_found unless @webhook.present?
end
end

View File

@ -0,0 +1,11 @@
class Api::V1::ProjectsController < Api::V1::BaseController
before_action :load_project, only: [:show]
def index
render_ok
end
def show
@result_object = Api::V1::Projects::GetService.call(@project, current_user.gitea_token)
end
end

View File

@ -0,0 +1,13 @@
class Api::V1::Users::ProjectsController < Api::V1::BaseController
before_action :load_observe_user
def index
@object_results = Api::V1::Users::Projects::ListService.call(@observe_user, query_params, current_user)
@projects = kaminari_paginate(@object_results)
end
private
def query_params
params.permit(:category, :is_public, :project_type, :sort_by, :sort_direction, :search)
end
end

View File

@ -0,0 +1,6 @@
class Api::V1::UsersController < Api::V1::BaseController
def index
render_ok
end
end

View File

@ -170,7 +170,10 @@ class ApplicationController < ActionController::Base
# 未授权的捕捉407弹试用申请弹框 # 未授权的捕捉407弹试用申请弹框
def require_login def require_login
#6.13 -hs #6.13 -hs
if request.headers["Authorization"].present?
tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id) if @doorkeeper_token.present?
end
tip_exception(401, "请登录后再操作") unless User.current.logged? tip_exception(401, "请登录后再操作") unless User.current.logged?
end end
@ -266,11 +269,11 @@ class ApplicationController < ActionController::Base
end end
end end
if !User.current.logged? && Rails.env.development? # if !User.current.logged? && Rails.env.development?
user = User.find 1 # user = User.find 1
User.current = user # User.current = user
start_user_session(user) # start_user_session(user)
end # end
# 测试版前端需求 # 测试版前端需求

View File

@ -33,8 +33,8 @@ class AttachmentsController < ApplicationController
normal_status(-1, "参数缺失") if params[:download_url].blank? normal_status(-1, "参数缺失") if params[:download_url].blank?
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:")) url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
if url.starts_with?(base_url) if url.starts_with?(base_url)
domain = Gitea.gitea_config[:domain] domain = GiteaService.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = GiteaService.gitea_config[:base_url]
url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?') url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?')
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
response = Faraday.get(request_url) response = Faraday.get(request_url)

View File

@ -6,9 +6,14 @@ class CompareController < ApplicationController
end end
def show def show
load_compare_params if params[:type] == "sha"
compare load_compare_params
@merge_status, @merge_message = get_merge_message @compare_result ||= gitea_compare(@base, @head)
else
load_compare_params
compare
@merge_status, @merge_message = get_merge_message
end
@page_size = page_size <= 0 ? 1 : page_size @page_size = page_size <= 0 ? 1 : page_size
@page_limit = page_limit <=0 ? 15 : page_limit @page_limit = page_limit <=0 ? 15 : page_limit
@page_offset = (@page_size -1) * @page_limit @page_offset = (@page_size -1) * @page_limit

View File

@ -18,15 +18,15 @@ module Acceleratorable
end end
def accelerator_domain def accelerator_domain
Gitea.gitea_config[:accelerator]["domain"] GiteaService.gitea_config[:accelerator]["domain"]
end end
def accelerator_username def accelerator_username
Gitea.gitea_config[:accelerator]["access_key_id"] GiteaService.gitea_config[:accelerator]["access_key_id"]
end end
def config_accelerator? def config_accelerator?
Gitea.gitea_config[:accelerator].present? GiteaService.gitea_config[:accelerator].present?
end end
def is_foreign_url?(clone_addr) def is_foreign_url?(clone_addr)

View File

@ -0,0 +1,20 @@
module Api::ProjectHelper
extend ActiveSupport::Concern
def load_project
namespace = params[:owner]
repo = params[:repo]
@project, @owner = Project.find_with_namespace(namespace, repo)
if @project
logger.info "###########project not founded"
@project
else
logger.info "###########project not found"
@project = nil
render_not_found and return
end
@project
end
end

View File

@ -0,0 +1,19 @@
module Api::UserHelper
extend ActiveSupport::Concern
def load_observe_user
username = params[:owner]
@observe_user = User.find_by(login: username)
if @observe_user
logger.info "###########observe_user not founded"
@observe_user
else
logger.info "###########observe_user not found"
@observe_user = nil
render_not_found and return
end
@observe_user
end
end

View File

@ -116,6 +116,7 @@ module LoginHelper
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash)) interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
if interactor.success? if interactor.success?
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########" Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"
user.update_column(:is_sync_pwd, true)
true true
else else
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}" Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}"

View File

@ -5,7 +5,16 @@ module Repository::LanguagesPercentagable
result = Gitea::Repository::Languages::ListService.call(@owner.login, result = Gitea::Repository::Languages::ListService.call(@owner.login,
@repository.identifier, current_user&.gitea_token) @repository.identifier, current_user&.gitea_token)
result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil @transform_language = result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
update_project_language(@transform_language) unless @transform_language.nil?
@transform_language
end
def update_project_language(language)
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
@project.update_column(:project_language_id, db_language.id)
rescue
return
end end
# hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781} # hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781}

View File

@ -0,0 +1,39 @@
class Oauth2Controller < ActionController::Base
layout 'doorkeeper/application'
include LoginHelper
def show
client_id = params[:call_url].split("client_id=")[1].split("&redirect_uri")[0]
@call_url = request.fullpath.split('call_url=').last
@app = Doorkeeper::Application.find_by(uid: client_id)
end
def create
if params[:login].blank?
@error = {msg: '邮箱地址或用户名不能为空', id: 'login'}
elsif params[:password].blank?
@error = {msg: '请输入密码', id: 'password'}
else
@user = User.try_to_login(params[:login], params[:password])
return @error = {msg: '账号或密码错误', id: 'login'} if @user.blank?
return @error = {msg: '违反平台使用规范,账号已被锁定', id: 'login'} if @user.locked?
login_control = LimitForbidControl::UserLogin.new(@user)
return @error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} if login_control.forbid?
password_ok = @user.check_password?(params[:password].to_s)
unless password_ok
if login_control.remain_times-1 == 0
@error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'}
else
@error = {msg: "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会", id: 'account'}
end
login_control.increment!
return
end
login_control.clear
redirect_to params[:call_url] + "&auth=" + @user.login
end
end
end

View File

@ -56,7 +56,12 @@ class PullRequestsController < ApplicationController
end end
def create def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user) if params[:fork_project_id].present?
fork_project= Project.find_by(id: params[:fork_project_id])
return normal_status(-1, "您不是源项目开发者,没有权限,请联系源项目管理员.") unless fork_project && fork_project.operator?(current_user)
else
return normal_status(-1, "您不是项目开发者,没有权限,请联系项目管理员.") unless @project.operator?(current_user)
end
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate! Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params) @pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
@ -176,6 +181,7 @@ class PullRequestsController < ApplicationController
@issue_assign_to = @issue.get_assign_user @issue_assign_to = @issue.get_assign_user
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token) @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
@last_review = @pull_request.issue.reviews.take
end end
def pr_merge def pr_merge

View File

@ -9,7 +9,7 @@ class RepositoriesController < ApplicationController
before_action :load_repository before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive] before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
before_action :get_ref, only: %i[entries sub_entries top_counts file archive] before_action :get_ref, only: %i[entries sub_entries top_counts files archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts] before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts] before_action :get_statistics, only: %i[top_counts]
@ -54,7 +54,7 @@ class RepositoriesController < ApplicationController
else else
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call @entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
end end
end end
@ -99,7 +99,7 @@ class RepositoriesController < ApplicationController
end end
end end
else else
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref) interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success? if interactor.success?
result = interactor.result result = interactor.result
@ -222,7 +222,7 @@ class RepositoriesController < ApplicationController
else else
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token) result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
end end
@path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" @path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
@readme = result[:status] === :success ? result[:body] : nil @readme = result[:status] === :success ? result[:body] : nil
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
@readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path) @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
@ -240,8 +240,8 @@ class RepositoriesController < ApplicationController
end end
def archive def archive
domain = Gitea.gitea_config[:domain] domain = GiteaService.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = GiteaService.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}" archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"
file_path = [domain, api_url, archive_url].join file_path = [domain, api_url, archive_url].join
@ -253,8 +253,8 @@ class RepositoriesController < ApplicationController
end end
def raw def raw
domain = Gitea.gitea_config[:domain] domain = GiteaService.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = GiteaService.gitea_config[:base_url]
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}" url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}"
file_path = [domain, api_url, url].join file_path = [domain, api_url, url].join

View File

@ -0,0 +1,20 @@
class ReviewsController < ApplicationController
before_action :require_login
before_action :load_project
before_action :load_pull_request
def create
return render_forbidden('您不是审查人员,无法进行审查!') if current_user&.id != @pull_request.issue.assigned_to_id
@journal, @review = Api::V1::Projects::PullRequests::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
end
private
def review_params
params.require(:review).permit(:content, :commit_id, :status)
end
def load_pull_request
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
end
end

View File

@ -1115,15 +1115,15 @@ await octokit.request('GET /api/yystopf/csfjkkj/contributors.json')
```shell ```shell
curl -X GET \ curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks.json
``` ```
```javascript ```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks.json') await octokit.request('GET /api/v1/yystopf/ceshi/webhooks.json')
``` ```
### HTTP 请求 ### HTTP 请求
`GET /api/:owner/:repo/webhooks.json` `GET /api/v1/:owner/:repo/webhooks.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
@ -1139,7 +1139,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
|url |string|地址| |url |string|地址|
|http_method |string|请求方式| |http_method |string|请求方式|
|is_active |bool |是否激活| |is_active |bool |是否激活|
|type |string|类型|
|last_status |string|最后一次推送的状态| |last_status |string|最后一次推送的状态|
|create_time |string|创建时间| |create_time |string|创建时间|
@ -1155,7 +1154,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "https://oapi.dingtalk.com/robot/send?access_token=7e1e19d0eddb6a5e33c5c2c4e66f4c88f9437184b9ed2c2653194c6374c7d513", "url": "https://oapi.dingtalk.com/robot/send?access_token=7e1e19d0eddb6a5e33c5c2c4e66f4c88f9437184b9ed2c2653194c6374c7d513",
"http_method": "", "http_method": "",
"is_active": true, "is_active": true,
"type": "dingtalk",
"last_status": "succeed", "last_status": "succeed",
"create_time": "2021-07-12 10:50:07" "create_time": "2021-07-12 10:50:07"
}, },
@ -1164,7 +1162,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "http://localhost:3000", "url": "http://localhost:3000",
"http_method": "GET", "http_method": "GET",
"is_active": true, "is_active": true,
"type": "gitea",
"last_status": "succeed", "last_status": "succeed",
"create_time": "2021-07-26 10:03:45" "create_time": "2021-07-26 10:03:45"
}, },
@ -1173,7 +1170,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "http://localhost:10081", "url": "http://localhost:10081",
"http_method": "POST", "http_method": "POST",
"is_active": true, "is_active": true,
"type": "gitea",
"last_status": "waiting", "last_status": "waiting",
"create_time": "2021-07-26 16:56:53" "create_time": "2021-07-26 16:56:53"
}, },
@ -1182,7 +1178,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "http://localhost:3001", "url": "http://localhost:3001",
"http_method": "POST", "http_method": "POST",
"is_active": true, "is_active": true,
"type": "gitea",
"last_status": "fail", "last_status": "fail",
"create_time": "2021-07-26 16:58:23" "create_time": "2021-07-26 16:58:23"
} }
@ -1200,15 +1195,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
```shell ```shell
curl -X GET \ curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/edit.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks/3.json
``` ```
```javascript ```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json') await octokit.request('GET /api/v1/yystopf/ceshi/webhooks/3.json')
``` ```
### HTTP 请求 ### HTTP 请求
`GET /api/:owner/:repo/webhooks/:id/edit.json` `GET /api/v1/:owner/:repo/webhooks/:id.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
@ -1226,36 +1221,21 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
|content_type |string|POST Content Type| |content_type |string|POST Content Type|
|http_method |string|请求方式| |http_method |string|请求方式|
|secret| |string|密钥| |secret| |string|密钥|
|is_active |bool |是否激活| |active |bool |是否激活|
|type |string|类型|
|last_status |string|最后一次推送的状态, waiting 等待,fail 失败,succeed 成功|
|branch_filter |string|分支过滤| |branch_filter |string|分支过滤|
|events |string|触发条件| |events |string|触发条件|
|create_time |string|创建时间| |create_at |string|创建时间|
参数| 含义| 参数| 含义|
--------- | ------- | ------- | --------- | ------- | ------- |
|create|创建分支或标签| |create|创建分支或标签|
|delete|分支或标签删除| |delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送| |push|git仓库推送|
|issue|疑修已打开、已关闭、已重新打开或编辑|
|issue_assign|疑修被指派|
|issue_label|疑修标签被更新或删除|
|issue_milestone|疑修被收入里程碑|
|issue_comment|疑修评论|
|pull_request|合并请求| |pull_request|合并请求|
|pull_request_assign|合并请求被指派| |pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
|pull_request_milestone|合并请求被记录于里程碑中|
|pull_request_comment|合并请求被评论|
|pull_request_review_approved|合并请求被批准| |pull_request_review_approved|合并请求被批准|
|pull_request_review_rejected|合并请求被拒绝| |pull_request_review_rejected|合并请求被拒绝|
|pull_request_review_comment|合并请求被提出审查意见|
|pull_request_sync|合并请求被同步|
|repository|创建或删除仓库|
|release|版本发布|
> 返回的JSON示例: > 返回的JSON示例:
@ -1266,31 +1246,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
"http_method": "GET", "http_method": "GET",
"content_type": "form", "content_type": "form",
"url": "http://localhost:3000", "url": "http://localhost:3000",
"secret": "123456", "active": true,
"last_status": "succeed", "create_at": "2021-07-26 10:03",
"is_active": true,
"type": "gitea",
"create_time": "2021-07-26 10:03:45",
"branch_filter": "*", "branch_filter": "*",
"events": [ "events": [
"create", "create",
"delete", "delete",
"fork",
"issues",
"issue_assign",
"issue_label",
"issue_milestone",
"issue_comment",
"push", "push",
"pull_request", "pull_request",
"pull_request_assign", "pull_request_assign",
"pull_request_label",
"pull_request_milestone",
"pull_request_comment",
"pull_request_review",
"pull_request_sync",
"repository",
"release"
] ]
} }
``` ```
@ -1305,15 +1269,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
```shell ```shell
curl -X POST \ curl -X POST \
http://localhost:3000/api/yystopf/ceshi/webhooks.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks.json
``` ```
```javascript ```javascript
await octokit.request('POST /api/yystopf/ceshi/webhooks.json') await octokit.request('POST /api/v1/yystopf/ceshi/webhooks.json')
``` ```
### HTTP 请求 ### HTTP 请求
`POST /api/:owner/:repo/webhooks.json` `POST /api/v1/:owner/:repo/webhooks.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
@ -1321,7 +1285,6 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
|owner |是| | string |用户登录名 | |owner |是| | string |用户登录名 |
|repo |是| | string |项目标识identifier | |repo |是| | string |项目标识identifier |
|webhook.url |是| | string |目标url | |webhook.url |是| | string |目标url |
|webhook.type |否| | string |类型|
|webhook.http_method |是| | string | http方法, POST和GET | |webhook.http_method |是| | string | http方法, POST和GET |
|webhook.content_type |是| | string | POST Content Type | |webhook.content_type |是| | string | POST Content Type |
|webhook.secret |否| | string |密钥文本| |webhook.secret |否| | string |密钥文本|
@ -1335,24 +1298,11 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
--------- | ------- | ------- | --------- | ------- | ------- |
|create|创建分支或标签| |create|创建分支或标签|
|delete|分支或标签删除| |delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送| |push|git仓库推送|
|issue|疑修已打开、已关闭、已重新打开或编辑|
|issue_assign|疑修被指派|
|issue_label|疑修标签被更新或删除|
|issue_milestone|疑修被收入里程碑|
|issue_comment|疑修评论|
|pull_request|合并请求| |pull_request|合并请求|
|pull_request_assign|合并请求被指派| |pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
|pull_request_milestone|合并请求被记录于里程碑中|
|pull_request_comment|合并请求被评论|
|pull_request_review_approved|合并请求被批准| |pull_request_review_approved|合并请求被批准|
|pull_request_review_rejected|合并请求被拒绝| |pull_request_review_rejected|合并请求被拒绝|
|pull_request_review_comment|合并请求被提出审查意见|
|pull_request_sync|合并请求被同步|
|repository|创建或删除仓库|
|release|版本发布|
> 请求的JSON示例: > 请求的JSON示例:
@ -1385,15 +1335,22 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
```json ```json
{ {
"id": 18, "id": 68,
"type": "gitea",
"content_type": "json", "content_type": "json",
"url": "http://localhost:10000", "http_method": "GET",
"url": "http://127.0.0.1:3000",
"events": [ "events": [
"push" "create",
"delete",
"push",
"pull_request",
"pull_request_assign",
"pull_request_review_approved",
"pull_request_review_rejected"
], ],
"active": true, "active": true,
"create_time": "2021-07-26 18:53:43" "branch_filter": "*",
"created_at": "2022-06-23 15:52"
} }
``` ```
<aside class="success"> <aside class="success">
@ -1407,15 +1364,15 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
```shell ```shell
curl -X PATCH \ curl -X PATCH \
http://localhost:3000/api/yystopf/ceshi/webhooks/7.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks/7.json
``` ```
```javascript ```javascript
await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json') await octokit.request('PATCH /api/v1/yystopf/ceshi/webhooks/7.json')
``` ```
### HTTP 请求 ### HTTP 请求
`PATCH /api/:owner/:repo/webhooks/:id.json` `PATCH /api/v1/:owner/:repo/webhooks/68.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
@ -1424,7 +1381,6 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
|repo |是| | string |项目标识identifier | |repo |是| | string |项目标识identifier |
|id |是| | string |webhook id | |id |是| | string |webhook id |
|webhook.url |是| | string |目标url | |webhook.url |是| | string |目标url |
|webhook.type |否| | string |类型|
|webhook.http_method |是| | string | http方法, POST和GET | |webhook.http_method |是| | string | http方法, POST和GET |
|webhook.content_type |是| | string | POST Content Type | |webhook.content_type |是| | string | POST Content Type |
|webhook.secret |否| | string |密钥文本| |webhook.secret |否| | string |密钥文本|
@ -1438,24 +1394,11 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
--------- | ------- | ------- | --------- | ------- | ------- |
|create|创建分支或标签| |create|创建分支或标签|
|delete|分支或标签删除| |delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送| |push|git仓库推送|
|issue|疑修已打开、已关闭、已重新打开或编辑|
|issue_assign|疑修被指派|
|issue_label|疑修标签被更新或删除|
|issue_milestone|疑修被收入里程碑|
|issue_comment|疑修评论|
|pull_request|合并请求| |pull_request|合并请求|
|pull_request_assign|合并请求被指派| |pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
|pull_request_milestone|合并请求被记录于里程碑中|
|pull_request_comment|合并请求被评论|
|pull_request_review_approved|合并请求被批准| |pull_request_review_approved|合并请求被批准|
|pull_request_review_rejected|合并请求被拒绝| |pull_request_review_rejected|合并请求被拒绝|
|pull_request_review_comment|合并请求被提出审查意见|
|pull_request_sync|合并请求被同步|
|repository|创建或删除仓库|
|release|版本发布|
> 请求的JSON示例: > 请求的JSON示例:
@ -1478,8 +1421,22 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
```json ```json
{ {
"status": 0, "id": 68,
"message": "success" "content_type": "json",
"http_method": "GET",
"url": "http://127.0.0.1:3000",
"events": [
"create",
"delete",
"push",
"pull_request",
"pull_request_assign",
"pull_request_review_approved",
"pull_request_review_rejected"
],
"active": true,
"branch_filter": "*",
"created_at": "2022-06-23 15:52"
} }
``` ```
<aside class="success"> <aside class="success">
@ -1494,15 +1451,15 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
```shell ```shell
curl -X DELETE \ curl -X DELETE \
http://localhost:3000/api/yystopf/ceshi/webhooks/7.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks/7.json
``` ```
```javascript ```javascript
await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json') await octokit.request('DELETE /api/v1/yystopf/ceshi/webhooks/7.json')
``` ```
### HTTP 请求 ### HTTP 请求
`DELETE /api/:owner/:repo/webhooks/:id.json` `DELETE /api/v1/:owner/:repo/webhooks/:id.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
@ -1532,15 +1489,15 @@ await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json')
```shell ```shell
curl -X GET \ curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/tasks.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks/3/hooktasks.json
``` ```
```javascript ```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json') await octokit.request('GET /api/v1/yystopf/ceshi/webhooks/3/hooktasks.json')
``` ```
### HTTP 请求 ### HTTP 请求
`GET /api/:owner/:repo/webhooks/:id/tasks.json` `GET /api/v1/:owner/:repo/webhooks/:id/hooktasks.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
@ -1568,7 +1525,7 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
```json ```json
{ {
"total_count": 6, "total_count": 6,
"tasks": [ "hooktasks": [
{ {
"id": 20, "id": 20,
"type": "gitea", "type": "gitea",
@ -1744,15 +1701,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
```shell ```shell
curl -X POST \ curl -X POST \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json http://localhost:3000/api/v1/yystopf/ceshi/webhooks/3/tests.json
``` ```
```javascript ```javascript
await octokit.request('POST /api/yystopf/ceshi/webhooks/3/test.json') await octokit.request('POST /api/v1/yystopf/ceshi/webhooks/3/tests.json')
``` ```
### HTTP 请求 ### HTTP 请求
`POST /api/:owner/:repo/webhooks/:id/test.json` `POST /api/v1/:owner/:repo/webhooks/:id/tests.json`
### 请求参数: ### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明

View File

@ -47,6 +47,105 @@ await octokit.request('GET /api/users/me.json')
Success Data. Success Data.
</aside> </aside>
## 用户项目列表
获取用户项目列表
> 示例:
```shell
curl -X GET http://localhost:3000/api/v1/:login/projects.json
```
```javascript
await octokit.request('GET /api/v1/:login/projects.json')
```
### HTTP 请求
`GET api/v1/yystopf/projects.json`
### 请求字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|login | string | 用户的用户名|
|category | string | 归属项目,默认为全部项目, join: 参与项目, created: 创建项目, manage: 管理项目, watched: 关注项目, forked: 复刻项目 |
|is_public | boolean | 公/私有项目true为公开项目false为私有项目|
|project_type | string | 项目类型common为托管项目, mirror为镜像项目, sync_mirror为同步镜像项目|
|sort_by | string | 项目的排序字段,比如 created_on, updated_on等|
|sort_direction | string | 排序的类型desc 倒序asc 正序|
|limit | integer | 每页个数 |
|page | integer | 页码 |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|total_count | integer | 项目总数 |
|projects.owner.id | integer | 项目拥有者id |
|projects.owner.type | string | 项目拥有者类型User 用户Organization 组织 |
|projects.owner.name | string | 项目拥有者名称|
|projects.owner.login | string | 项目拥有者用户名 |
|projects.owner.image_url | string | 项目拥有者头像地址 |
|type | string | 项目类型common 托管项目mirror 镜像项目, sync 同步镜像项目 |
|description | string | 项目描述 |
|forked_count | integer | 项目复刻数量 |
|forked_from_project_id | integer | 项目复刻来源项目 |
|identifier | string | 项目标识 |
|issues_count | integer | 项目issues数量|
|pull_requests_count | integer | 项目合并请求数量 |
|invite_code | string | 项目邀请码|
|website | string | 项目网址|
|platform | string | 项目平台 |
|name | string | 项目名称|
|open_devops | boolean | 项目是否开启工作流 |
|praises_count | integer | 项目点赞数量|
|is_public | boolean | 项目是否公开|
|status | integer | 项目状态|
|watchers_count | integer | 项目关注数量|
|ignore_id | integer | 项目ignoreID|
|license_id | integer | 项目许可证ID|
|project_category_id | integer | 项目分类ID|
|project_language_id | integer | 项目语言ID|
> 返回的JSON示例:
```json
"total_count": 1,
"projects": [
{
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"type": "common",
"description": null,
"forked_count": 1,
"forked_from_project_id": null,
"identifier": "hahahah",
"issues_count": 5,
"pull_requests_count": 3,
"invite_code": "8zfKtM",
"website": null,
"platform": "forge",
"name": "hahahah",
"open_devops": false,
"praises_count": 0,
"is_public": true,
"status": 1,
"watchers_count": 0,
"ignore_id": null,
"license_id": null,
"project_category_id": null,
"project_language_id": null
}
]
```
<aside class="success">
Success Data.
</aside>
## 用户消息列表 ## 用户消息列表
获取用户消息列表 获取用户消息列表

View File

@ -30,7 +30,7 @@ module ProjectsHelper
end end
def gitea_domain def gitea_domain
Gitea.gitea_config[:domain] GiteaService.gitea_config[:domain]
end end
def find_user_by_login_or_mail(identifier) def find_user_by_login_or_mail(identifier)

View File

@ -103,7 +103,7 @@ module RepositoriesHelper
end end
end end
# author hui.he # author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name) def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '') file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank? return nil if str.blank?
@ -120,8 +120,7 @@ module RepositoriesHelper
# 链接直接跳过不做替换 # 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank? next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1] ext = File.extname(s_content)[1..-1]
if (image_type?(ext) || download_type(ext)) && !ext.blank?
if (image_type?(ext) || download_type(ext)) && !s_content.to_s.end_with?('/')
s_content = File.expand_path(s_content, file_path) s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1] s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}") # content = content.gsub(s[0], "/#{s_content}")
@ -131,7 +130,7 @@ module RepositoriesHelper
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/") path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path) s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1] s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub(s[0], "/#{s_content}") content = content.gsub('('+s[0]+')', '('+"/#{s_content}"+')')
end end
rescue rescue
next next

View File

@ -44,8 +44,8 @@ module Gitea
def token def token
{ {
username: Gitea.gitea_config[:access_key_id], username: GiteaService.gitea_config[:access_key_id],
password: Gitea.gitea_config[:access_key_secret] password: GiteaService.gitea_config[:access_key_secret]
} }
end end
end end

View File

@ -37,7 +37,7 @@ class Ci::Drone::Server
private private
def gitea_url def gitea_url
Gitea.gitea_config[:domain] GiteaService.gitea_config[:domain]
end end
def database_username def database_username

View File

@ -1,4 +1,4 @@
module Gitea module GiteaService
class << self class << self
def gitea_config def gitea_config
gitea_config = {} gitea_config = {}

View File

@ -69,6 +69,7 @@ class Issue < ApplicationRecord
has_many :issue_tags, through: :issue_tags_relates has_many :issue_tags, through: :issue_tags_relates
has_many :issue_times, dependent: :destroy has_many :issue_times, dependent: :destroy
has_many :issue_depends, dependent: :destroy has_many :issue_depends, dependent: :destroy
has_many :reviews, dependent: :destroy
scope :issue_includes, ->{includes(:user)} scope :issue_includes, ->{includes(:user)}
scope :issue_many_includes, ->{includes(journals: :user)} scope :issue_many_includes, ->{includes(journals: :user)}
scope :issue_issue, ->{where(issue_classify: [nil,"issue"])} scope :issue_issue, ->{where(issue_classify: [nil,"issue"])}

View File

@ -12,11 +12,13 @@
# parent_id :integer # parent_id :integer
# comments_count :integer default("0") # comments_count :integer default("0")
# reply_id :integer # reply_id :integer
# review_id :integer
# #
# Indexes # Indexes
# #
# index_journals_on_created_on (created_on) # index_journals_on_created_on (created_on)
# index_journals_on_journalized_id (journalized_id) # index_journals_on_journalized_id (journalized_id)
# index_journals_on_review_id (review_id)
# index_journals_on_user_id (user_id) # index_journals_on_user_id (user_id)
# journals_journalized_id (journalized_id,journalized_type) # journals_journalized_id (journalized_id,journalized_type)
# #

27
app/models/review.rb Normal file
View File

@ -0,0 +1,27 @@
# == Schema Information
#
# Table name: reviews
#
# id :integer not null, primary key
# issue_id :integer
# reviewer_id :integer
# content :text(65535)
# commit_id :string(255)
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_reviews_on_issue_id (issue_id)
# index_reviews_on_reviewer_id (reviewer_id)
#
class Review < ApplicationRecord
belongs_to :issue
belongs_to :reviewer, class_name: 'User', foreign_key: :reviewer_id
has_one :journal, dependent: :destroy
enum status: {common: 0, approved: 1, rejected: 2}
end

View File

@ -0,0 +1,48 @@
class Api::V1::Projects::GetService < ApplicationService
attr_reader :project, :token, :owner, :repo
attr_accessor :gitea_data, :gitea_branch_tag_count
def initialize(project, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end
def call
$gitea_client.token = token unless token.blank?
load_gitea_data
load_gitea_branch_tag_count
$gitea_client.token = nil unless token.blank?
result_object
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
private
def result_object
{
full_name: "#{owner}/#{repo}",
owner: project&.owner,
ssh_url: gitea_data["ssh_url"],
clone_url: gitea_data["clone_url"],
size: gitea_data["size"],
default_branch: gitea_data["default_branch"],
empty: gitea_data["empty"],
branch_count: gitea_branch_tag_count["branch_count"],
tag_count: gitea_branch_tag_count["tag_count"],
}
end
def load_gitea_data
@gitea_data = $gitea_client.get_repos_by_owner_repo(owner, repo)
end
def load_gitea_branch_tag_count
@gitea_branch_tag_count = $gitea_client.get_repos_branch_tag_count_by_owner_repo(owner, repo)
end
end

View File

@ -0,0 +1,40 @@
class Api::V1::Projects::PullRequests::Reviews::CreateService < ApplicationService
include ActiveModel::Model
attr_reader :project, :pull_request, :issue, :status, :commit_id, :content, :current_user
attr_accessor :review, :journal
validates :status, inclusion: { in: %w(common approved rejected), message: '请输入正确的Type'}
def initialize(project, pull_request, params, current_user)
@project = project
@pull_request = pull_request
@issue = pull_request&.issue
@status = params[:status]
@commit_id = params[:commit_id]
@content = params[:content]
@current_user = current_user
end
def call
raise Error, errors.full_messages.join(", ") unless valid?
ActiveRecord::Base.transaction do
create_review
create_journal
end
return @journal, @review
rescue
raise Error, '服务器错误,请联系系统管理员!'
end
private
def create_review
@review = issue.reviews.create!(status: status, content: content, commit_id: commit_id, reviewer_id: @current_user.id)
end
def create_journal
@journal = issue.journals.create!(notes: content, user_id: @current_user.id, review_id: @review.id)
end
end

View File

@ -0,0 +1,60 @@
class Api::V1::Projects::Webhooks::CreateService < ApplicationService
include ActiveModel::Model
attr_reader :project, :token, :owner, :repo, :active, :branch_filter, :content_type, :url, :http_method, :secret, :events
attr_accessor :gitea_data
validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
validates :active, inclusion: {in: [true, false]}
validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}
def initialize(project, params, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@active = params[:active]
@branch_filter = params[:branch_filter]
@content_type = params[:content_type]
@url = params[:url]
@http_method = params[:http_method]
@secret = params[:secret]
@events = params[:events]
@token = token
end
def call
raise Error, errors.full_messages.join(",") unless valid?
begin
$gitea_client.token = token unless token.blank?
excute_data_to_gitea
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
end
private
def request_body
{
active: active,
branch_filter: branch_filter,
config: {
content_type: content_type,
url: url,
http_method: http_method,
secret: secret
},
events: events || [],
type: 'gitea',
}
end
def excute_data_to_gitea
@gitea_data = $gitea_client.post_repos_hooks_by_owner_repo(owner, repo, {body: request_body.to_json})
end
end

View File

@ -0,0 +1,30 @@
class Api::V1::Projects::Webhooks::DeleteService < ApplicationService
attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data
def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end
def call
$gitea_client.token = token unless token.blank?
excute_data_to_gitea
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
private
def excute_data_to_gitea
@gitea_data = $gitea_client.delete_repos_hooks_by_owner_repo_id(owner, repo, id)
end
end

View File

@ -0,0 +1,30 @@
class Api::V1::Projects::Webhooks::GetService < ApplicationService
attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data
def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end
def call
$gitea_client.token = token unless token.blank?
load_gitea_data
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
private
def load_gitea_data
@gitea_data = $gitea_client.get_repos_hooks_by_owner_repo_id(owner, repo, id)
end
end

View File

@ -0,0 +1,30 @@
class Api::V1::Projects::Webhooks::ListService < ApplicationService
attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data
def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end
def call
$gitea_client.token = token unless token.blank?
load_gitea_data
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
private
def load_gitea_data
@gitea_data = $gitea_client.get_repos_hooks_hooktasks_by_owner_repo(owner, repo, id)
end
end

View File

@ -0,0 +1,29 @@
class Api::V1::Projects::Webhooks::ListService < ApplicationService
attr_reader :project, :token, :owner, :repo
attr_accessor :gitea_data
def initialize(project, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end
def call
$gitea_client.token = token unless token.blank?
load_gitea_data
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
private
def load_gitea_data
@gitea_data = $gitea_client.get_repos_hooks_by_owner_repo(owner, repo)
end
end

View File

@ -0,0 +1,30 @@
class Api::V1::Projects::Webhooks::TestsService < ApplicationService
attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data
def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end
def call
$gitea_client.token = token unless token.blank?
excute_data_to_gitea
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
private
def excute_data_to_gitea
@gitea_data = $gitea_client.post_repos_hooks_tests_by_owner_repo_id(owner, repo, id)
end
end

View File

@ -0,0 +1,61 @@
class Api::V1::Projects::Webhooks::UpdateService < ApplicationService
include ActiveModel::Model
attr_reader :project, :id, :token, :owner, :repo, :active, :branch_filter, :content_type, :url, :http_method, :secret, :events
attr_accessor :gitea_data
validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
validates :active, inclusion: {in: [true, false]}
validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}
def initialize(project, id, params, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@active = params[:active]
@branch_filter = params[:branch_filter]
@content_type = params[:content_type]
@url = params[:url]
@http_method = params[:http_method]
@secret = params[:secret]
@events = params[:events]
@token = token
end
def call
raise Error, errors.full_messages.join(",") unless valid?
begin
$gitea_client.token = token unless token.blank?
excute_data_to_gitea
$gitea_client.token = nil unless token.blank?
gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
end
private
def request_body
{
active: active,
branch_filter: branch_filter,
config: {
content_type: content_type,
url: url,
http_method: http_method,
secret: secret
},
events: events || [],
type: 'gitea',
}
end
def excute_data_to_gitea
@gitea_data = $gitea_client.patch_repos_hooks_by_owner_repo_id(owner, repo, id, {body: request_body.to_json})
end
end

View File

@ -0,0 +1,86 @@
class Api::V1::Users::Projects::ListService < ApplicationService
include ActiveModel::Model
attr_reader :observe_user, :category, :is_public, :project_type, :sort_by, :sort_direction, :search, :current_user
attr_accessor :queried_projects
validates :category, inclusion: {in: %w(all join created manage watched forked), message: "请输入正确的Category"}
validates :is_public, inclusion: {in: [true, false], message: '请输入正确的IsPublic'}, allow_nil: true
validates :project_type, inclusion: {in: %w(common mirror sync_mirror), message: '请输入正确的ProjectType'}, allow_nil: true
validates :sort_by, inclusion: {in: Project.column_names, message: '请输入正确的SortBy'}
validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}
def initialize(observe_user, params, current_user=nil)
@observe_user = observe_user
@category = params[:category] || 'all'
@is_public = params[:is_public]
@project_type = params[:project_type]
@sort_by = params[:sort_by] || 'updated_on'
@sort_direction = params[:sort_direction] || 'desc'
@search = params[:search]
@current_user = current_user
end
def call
raise Error, errors.full_messages.join(", ") unless valid?
begin
project_query_data
queried_projects
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
end
private
def project_query_data
if current_user.admin?
projects = Project
else
projects = Project.visible
end
case category
when 'join'
normal_projects = projects.where.not(user_id: observe_user.id).members_projects(observe_user.id).to_sql
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observe_user.id}).to_sql
projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct
when 'created'
projects = projects.where(user_id: observe_user.id)
when 'manage'
normal_projects = projects.joins(members: :roles).where(members: {user_id: observe_user.id}, roles: {name: 'Manager'}).to_sql
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observe_user.id}, teams: {authorize: %w(owner admin)}).to_sql
projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct
when 'watched'
projects = projects.where.not(user_id: observe_user.id).joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observe_user.id})
when 'forked'
fork_ids = observe_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)
projects = projects.where(id: fork_ids)
else
normal_projects = projects.members_projects(observe_user.id).to_sql
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observe_user.id}).to_sql
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
end
unless is_public.nil?
if is_public
projects = projects.visible
else
projects = projects.is_private
end
end
projects = projects.with_project_type(project_type)
q = projects.ransack(name_or_identifier_cont: search)
scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users)
scope = scope.order("projects.#{sort_by} #{sort_direction}")
@queried_projects = scope
end
end

View File

@ -81,7 +81,7 @@ class Educoder::ClientService < ApplicationService
end end
def access_key_secret def access_key_secret
Gitea.gitea_config[:access_key_secret] GiteaService.gitea_config[:access_key_secret]
end end
def api_url(url) def api_url(url)

View File

@ -56,7 +56,7 @@ class Gitea::Accelerator::BaseService < ApplicationService
end end
def accelerator def accelerator
Gitea.gitea_config[:accelerator] GiteaService.gitea_config[:accelerator]
end end
def render_status(response) def render_status(response)

View File

@ -96,11 +96,11 @@ class Gitea::ClientService < ApplicationService
end end
def base_url def base_url
Gitea.gitea_config[:base_url] GiteaService.gitea_config[:base_url]
end end
def domain def domain
Gitea.gitea_config[:domain] GiteaService.gitea_config[:domain]
end end
def api_url def api_url

View File

@ -14,8 +14,8 @@ class Gitea::User::DeleteService < Gitea::ClientService
private private
def token def token
{ {
username: Gitea.gitea_config[:access_key_id], username: GiteaService.gitea_config[:access_key_id],
password: Gitea.gitea_config[:access_key_secret] password: GiteaService.gitea_config[:access_key_secret]
} }
end end

View File

@ -17,7 +17,7 @@ class Gitea::User::UpdateService < Gitea::ClientService
# source_id integer($int64) # source_id integer($int64)
# website string # website string
def initialize(edit_username, params={}, token={username: Gitea.gitea_config[:access_key_id], password: Gitea.gitea_config[:access_key_secret]}) def initialize(edit_username, params={}, token={username: GiteaService.gitea_config[:access_key_id], password: GiteaService.gitea_config[:access_key_secret]})
@token = token @token = token
@params = params @params = params
@edit_username = edit_username @edit_username = edit_username

View File

@ -63,7 +63,7 @@ class Repositories::CreateService < ApplicationService
end end
def remote_repository_url def remote_repository_url
[Gitea.gitea_config[:domain], '/', user.login, '/', params[:identifier], ".git"].join("") [GiteaService.gitea_config[:domain], '/', user.login, '/', params[:identifier], ".git"].join("")
end end
def repository_params def repository_params

View File

@ -0,0 +1,10 @@
if project.present?
json.type project.project_type
json.(project,
:description, :forked_count, :forked_from_project_id, :identifier,
:issues_count, :pull_requests_count, :invite_code, :website, :platform,
:name, :open_devops, :praises_count, :is_public, :status, :watchers_count,
:ignore_id, :license_id, :project_category_id, :project_language_id)
else
json.nil!
end

View File

@ -0,0 +1,5 @@
json.owner do
json.partial! "api/v1/users/simple_user", user: @result_object[:owner]
end
json.(@result_object, :full_name, :ssh_url, :clone_url, :default_branch, :empty, :branch_count, :tag_count)
json.partial! "api/v1/projects/simple_detail", project: @project

View File

@ -0,0 +1,3 @@
json.(webhook, :id, :url, :http_method, :is_active)
json.last_status webhook.last_status
json.create_time Time.at(webhook.created_unix).strftime("%Y-%m-%d %H:%M:%S")

View File

@ -0,0 +1,8 @@
json.id webhook["id"]
json.content_type webhook['config']['content_type']
json.http_method webhook['config']['http_method']
json.url webhook['config']['url']
json.events webhook['events']
json.active webhook['active']
json.branch_filter webhook['branch_filter']
json.created_at format_time(webhook['created_at'].to_time)

View File

@ -0,0 +1 @@
json.partial! "api/v1/projects/webhooks/simple_gitea_detail", webhook: @result_object

View File

@ -0,0 +1,6 @@
json.total_count @hooktasks.total_count
json.hooktasks @hooktasks.each do |task|
json.(task, :id, :event_type, :type, :uuid, :is_succeed, :is_delivered, :payload_content, :request_content)
json.response_content task.response_content_json
json.delivered_time Time.at(task.delivered*10**-9).strftime("%Y-%m-%d %H:%M:%S")
end

View File

@ -0,0 +1,4 @@
json.total_count @webhooks.total_count
json.webhooks @webhooks do |webhook|
json.partial! "api/v1/projects/webhooks/simple_detail", webhook: webhook
end

View File

@ -0,0 +1 @@
json.partial! "api/v1/projects/webhooks/simple_gitea_detail", webhook: @result_object

View File

@ -0,0 +1 @@
json.partial! "api/v1/projects/webhooks/simple_gitea_detail", webhook: @result_object

View File

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

View File

@ -0,0 +1,8 @@
json.total_count @projects.total_count
json.projects @projects do |project|
json.owner do
json.partial! "api/v1/users/simple_user", user: project.owner
end
json.partial! "api/v1/projects/simple_detail", project: project
end

View File

@ -0,0 +1,141 @@
<!DOCTYPE html>
<html>
<head>
<title>GitLink oauth2 认证</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<%= javascript_include_tag :application, 'data-turbolinks-track': 'reload' %>
<%= stylesheet_link_tag "doorkeeper/application" %>
<%= csrf_meta_tags %>
<%= yield(:css) if content_for?(:css) %>
<style>
body {
margin: 0;
color: rgba(0, 0, 0, .65);
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
font-variant: tabular-nums;
line-height: 1.5;
background-color: #fff;
-webkit-font-feature-settings: "tnum";
font-feature-settings: "tnum";
background: url(https://ali-cdn.educoder.net/react/build/static/media/beijintulogontwo.41076faf.png) center center / 100% 100% no-repeat fixed;
height: 100%;
width: 100%;
position: absolute;
top: 0px;
bottom: 0px;
min-height: 100%;
padding-top: 40px;
}
#container {
max-width: 500px;
}
.mt-20 {
margin-top: 20px;
}
.login-form {
margin-top: 10px;
}
.error {
color: #ee4a1f;
text-align: left;
margin-bottom: 0px;
min-height: 20px;
}
.app-name {
color: #459be6;
}
.logo-wraper {
text-align: center;
}
.auth-desc {
margin: 20px;
font-size: 20px;
}
.w {
position: relative;
width: 100%;
max-width: 350px;
margin: 0px auto;
}
.btn-login {
width: 100%;
text-align: center;
color: #fff !important;
display: block;
background: #459be6;
border-radius: 4px;
letter-spacing: 2px;
cursor: pointer;
}
input {
font-family: "Monospaced Number", "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
list-style: none;
position: relative;
display: inline-block;
padding: 4px 11px;
width: 100%;
height: 38px;
font-size: 14px;
line-height: 1.5;
color: rgba(0, 0, 0, 0.65);
width: 100%;
background-color: #fff;
height: 45px;
padding: 5px;
background-image: none;
border: 1px solid #d9d9d9;
border-radius: 4px;
-webkit-transition: all .3s;
-o-transition: all .3s;
transition: all .3s;
margin-top: 10px;
}
.reg {
text-align: center;
margin-top: 20px;
}
.reg-link {
font-size: 18px;
color: #999;
}
</style>
</head>
<body>
<header class="page-header" role="banner">
<div class="logo-wraper">
<img src="https://www.gitlink.org.cn/images/avatars/LaboratorySetting/1nav?t=1638344455" style="cursor: pointer;width: 80px;">
</div>
</header>
<div id="container">
<%- if flash[:notice].present? %>
<div class="alert alert-info">
<%= flash[:notice] %>
</div>
<% end -%>
<%= yield %>
</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<main role="main">
<p class="auth-desc">
申请使用<strong class="app-name"> GitLink </strong>账号登录
<strong class="app-name"><%= @app&.name %></strong>
</p>
<div class="actions">
<div class="w">
<%= form_tag oauth2_path, method: :post, authenticity_token: true, remote: true, class: 'login-form' do %>
<%= hidden_field_tag :client_id, @app.uid %>
<%= hidden_field_tag :call_url, @call_url %>
<p id="account_error" class='error'></p>
<%= text_field_tag :login, '', placeholder: '请输入邮箱地址/用户名' %>
<p id="login_error" class='error'></p>
<%= password_field_tag :password, '', placeholder: '请输入密码'%>
<p id="password_error" class='error'></p>
<%= submit_tag '授权登录', class: "btn btn-login btn-lg btn-block mt-20" %>
<% end %>
<div class="reg">
<%= link_to "注 册", '/register', class: 'reg-link' %>
</div>
</div>
</div>
</main>

View File

@ -7,6 +7,20 @@ json.commits_count @gitea_pull["commit_num"]
json.files_count @gitea_pull["changed_files"] json.files_count @gitea_pull["changed_files"]
json.comments_count @issue.journals.parent_journals.size json.comments_count @issue.journals.parent_journals.size
json.comments_total_count @issue.get_journals_size json.comments_total_count @issue.get_journals_size
json.assign_user do
json.partial! 'users/user_simple', user: @issue_assign_to
end
json.author do
json.partial! 'users/user_simple', user: @issue_user
end
if @last_review.present?
json.last_review do
json.(@last_review, :id, :commit_id, :content, :status)
json.created_at format_time(@last_review.created_at)
end
end
json.pull_request do json.pull_request do
json.extract! @pull_request, :id,:base, :head, :status,:fork_project_id, :is_original json.extract! @pull_request, :id,:base, :head, :status,:fork_project_id, :is_original

View File

@ -0,0 +1,10 @@
json.issue do
json.partial! 'pull_requests/detail', issue: @pull_request.issue
end
json.journal_id @journal.id
json.journal_notes @journal.notes
json.review_id @review.id
json.commit_id @review.commit_id
json.content @review.content
json.status @review.status
json.created_at format_time(@review.created_at)

View File

@ -10,7 +10,7 @@ Doorkeeper.configure do
# raise "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}" # raise "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
# Put your resource owner authentication logic here. # Put your resource owner authentication logic here.
# Example implementation: # Example implementation:
User.find_by(id: session[:www_user_id]) || redirect_to(new_user_session_url) User.find_by(login: params[:auth]) || redirect_to("/oauth2?call_url=#{request.fullpath}")
end end
resource_owner_from_credentials do |routes| resource_owner_from_credentials do |routes|
@ -21,7 +21,7 @@ Doorkeeper.configure do
admin_authenticator do admin_authenticator do
user = User.find_by_id(session[:www_user_id]) user = User.find_by_id(session[:www_user_id])
unless user #&& user.admin_or_business? unless user && user.admin_or_business?
redirect_to root_url redirect_to root_url
end end
end end
@ -242,8 +242,8 @@ Doorkeeper.configure do
# For more information go to # For more information go to
# https://doorkeeper.gitbook.io/guides/ruby-on-rails/scopes # https://doorkeeper.gitbook.io/guides/ruby-on-rails/scopes
# #
# default_scopes :public default_scopes :public
# optional_scopes :write, :update optional_scopes :write, :update
# Allows to restrict only certain scopes for grant_type. # Allows to restrict only certain scopes for grant_type.
# By default, all the scopes will be available for all the grant types. # By default, all the scopes will be available for all the grant types.
@ -516,7 +516,7 @@ Doorkeeper::JWT.configure do
user = User.find(opts[:resource_owner_id]) user = User.find(opts[:resource_owner_id])
{ {
iss: 'My App', iss: 'GitLink',
iat: Time.current.utc.to_i, iat: Time.current.utc.to_i,
# @see JWT reserved claims - https://tools.ietf.org/html/draft-jones-json-web-token-07#page-7 # @see JWT reserved claims - https://tools.ietf.org/html/draft-jones-json-web-token-07#page-7

View File

@ -0,0 +1,11 @@
require 'gitea-client'
config = Rails.application.config_for(:configuration).symbolize_keys!
gitea_config = config[:gitea].symbolize_keys!
$gitea_client = Gitea::Api::Client.new({
domain: gitea_config[:domain],
base_url: gitea_config[:base_url],
username: gitea_config[:username],
password: gitea_config[:password]
})

View File

@ -1,5 +1,11 @@
Rails.application.routes.draw do Rails.application.routes.draw do
def draw(routes_name)
instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb")))
end
draw :api
use_doorkeeper use_doorkeeper
require 'sidekiq/web' require 'sidekiq/web'
require 'sidekiq/cron/web' require 'sidekiq/cron/web'
@ -22,6 +28,9 @@ Rails.application.routes.draw do
get 'oauth/register', to: 'oauth#register' get 'oauth/register', to: 'oauth#register'
post 'oauth/auto_register', to: 'oauth#auto_register' post 'oauth/auto_register', to: 'oauth#auto_register'
get 'oauth2', to: 'oauth2#show'
post 'oauth2', to: 'oauth2#create'
resources :edu_settings resources :edu_settings
scope '/api' do scope '/api' do
@ -547,6 +556,7 @@ Rails.application.routes.draw do
post :refuse_merge post :refuse_merge
get :files get :files
get :commits get :commits
resources :reviews, only: [:create]
end end
collection do collection do
post :check_can_merge post :check_can_merge

36
config/routes/api.rb Normal file
View File

@ -0,0 +1,36 @@
defaults format: :json do
namespace :api do
namespace :v1 do
scope ':owner' do
resource :users, path: '/', only: [:show, :update, :edit, :destroy]
scope module: :users do
resources :projects, only: [:index]
end
scope ':repo' do
# projects
resource :projects, path: '/', only: [:show, :update, :edit, :destroy]
# projects文件夹下的
scope module: :projects do
resources :issues
resources :pull_requests
resources :versions
resources :release_versions
resources :webhooks do
member do
post :tests
get :hooktasks
end
end
end
end
end
resources :projects, only: [:index]
end
end
end

View File

@ -0,0 +1,15 @@
class CreateReviews < ActiveRecord::Migration[5.2]
def change
create_table :reviews do |t|
t.references :issue
t.references :reviewer
t.text :content
t.string :commit_id
t.integer :status, default: 0
t.timestamps
end
add_reference :journals, :review
end
end

View File

@ -128,7 +128,7 @@ namespace :sync_data_to_gitea do
end end
def remote_repository_url(username, identifier) def remote_repository_url(username, identifier)
[Gitea.gitea_config[:domain], '/', username, '/', identifier, ".git"].join("") [GiteaService.gitea_config[:domain], '/', username, '/', identifier, ".git"].join("")
end end
def generate_identifier def generate_identifier

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe Review, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end