Merge branch 'dev_trustie_server' into trustie_server

This commit is contained in:
jasder 2021-07-30 17:08:23 +08:00
commit 20e2e22be5
86 changed files with 3364 additions and 239 deletions

1
.gitignore vendored
View File

@ -74,6 +74,7 @@ vendor/bundle/
/log
/public/admin
/mysql_data
/public/repo/
.generators

View File

@ -770,7 +770,7 @@ class ApplicationController < ActionController::Base
end
def base_url
request.base_url
Rails.application.config_for(:configuration)['platform_url'] || request.base_url
end
def convert_image!

View File

@ -6,26 +6,48 @@ class CompareController < ApplicationController
end
def show
load_compare_params
compare
@merge_status, @merge_message = get_merge_message
end
private
def get_merge_message
if @base.blank? || @head.blank?
return -2, "请选择分支"
else
if @head.include?(":")
fork_project = @project.forked_projects.joins(:owner).where(users: {login: @head.to_s.split("/")[0]}).take
return -2, "请选择正确的仓库" unless fork_project.present?
@exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take
else
@exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).take
end
if @exist_pullrequest.present?
return -2, "在这些分支之间的合并请求已存在:<a href='/projects/#{@owner.login}/#{@project.identifier}/pulls/#{@exist_pullrequest.id}/Messagecount'>#{@exist_pullrequest.try(:title)}</a>"
else
if @compare_result["Commits"].blank? && @compare_result["Diff"].blank?
return -2, "分支内容相同,无需创建合并请求"
end
end
end
return 0, "可以合并"
end
def compare
base, head = compare_params
# TODO: 处理fork的项目向源项目发送PR的base、head参数问题
@compare_result ||=
head.include?(":") ? gitea_compare(base, head) : gitea_compare(head, base)
@head.include?(":") ? gitea_compare(@base, @head) : gitea_compare(@head, @base)
end
def compare_params
base = Addressable::URI.unescape(params[:base])
head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head]
def load_compare_params
@base = Addressable::URI.unescape(params[:base])
@head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head]
[base, head]
end
def gitea_compare(base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head, current_user.gitea_token)
end
end

View File

@ -3,6 +3,7 @@ class IssuesController < ApplicationController
before_action :load_project
before_action :set_user
before_action :check_issue_permission
before_action :operate_issue_permission, only:[:create, :update, :destroy, :clean, :series_update, :copy]
before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue]
before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue]
@ -230,7 +231,7 @@ class IssuesController < ApplicationController
end
def show
@user_permission = current_user.present? && current_user.logged? && (!@issue.is_lock || @project.member?(current_user) || current_user.admin? || @issue.user == current_user)
@user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user)
@issue_attachments = @issue.attachments
@issue_user = @issue.user
@issue_assign_to = @issue.get_assign_user
@ -303,7 +304,7 @@ class IssuesController < ApplicationController
if issue_ids.present?
if update_hash.blank?
normal_status(-1, "请选择批量更新内容")
elsif Issue.where(id: issue_ids).update_all(update_hash)
elsif Issue.where(id: issue_ids)&.update(update_hash)
normal_status(0, "批量更新成功")
else
normal_status(-1, "批量更新失败")
@ -315,6 +316,7 @@ class IssuesController < ApplicationController
def copy
@new_issue = @issue.dup
@new_issue.author_id = current_user.id
if @new_issue.save
issue_tags = @issue.issue_tags.pluck(:id)
if issue_tags.present?
@ -412,6 +414,10 @@ class IssuesController < ApplicationController
end
end
def operate_issue_permission
return render_forbidden("您没有权限进行此操作.") unless current_user.admin? || @project.member?(current_user)
end
def export_issues(issues)
@table_columns = %w(ID 类型 标题 描述 状态 指派给 优先级 标签 发布人 创建时间 里程碑 开始时间 截止时间 完成度 分类 金额 属于)
@export_issues = []

View File

@ -4,4 +4,7 @@ class Projects::BaseController < ApplicationController
before_action :load_project
before_action :load_repository
def require_manager!
return render_forbidden('你没有权限操作') unless current_user.admin? || @project.manager?(current_user)
end
end

View File

@ -0,0 +1,116 @@
class Projects::WebhooksController < Projects::BaseController
before_action :require_manager!
before_action :find_webhook, only:[:edit, :update, :destroy, :tasks, :test]
def index
@webhooks = @project.webhooks
@webhooks = kaminari_paginate(@webhooks)
end
def create
ActiveRecord::Base.transaction do
return render_error("webhooks数量已到上限请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 19
return render_error("参数错误.") unless webhook_params.present?
form = Projects::Webhooks::CreateForm.new(webhook_params)
return render json: {status: -1, message: form.errors} unless form.validate!
response = Gitea::Repository::Webhooks::CreateService.new(operating_token, @project&.owner&.login, @project&.identifier, gitea_webhooks_params).call
if response[0] == 201
@webhook = response[2]
else
render_error("创建失败.")
end
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def edit
end
def update
return render_error("参数错误.") unless webhook_params.present?
form = Projects::Webhooks::CreateForm.new(webhook_params)
return render json: {status: -1, message: form.errors} unless form.validate!
response = Gitea::Repository::Webhooks::UpdateService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id, gitea_webhooks_params)
if response[0] == 200
@webhook = response[2]
render_ok
else
render_error("更新失败.")
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def destroy
response = Gitea::Repository::Webhooks::DeleteService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id)
if response[0] == 204
@webhook = response[2]
render_ok
else
render_error("删除失败.")
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def tasks
@tasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
@tasks = kaminari_paginate(@tasks)
end
def test
ActiveRecord::Base.transaction do
response = Gitea::Repository::Webhooks::TestService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id)
if response[0] == 204
render_ok
else
render_error("测试推送失败.")
end
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def find_webhook
@webhook = @project.webhooks.find_by_id(params[:id])
return render_not_found if @webhook.nil?
end
def webhook_params
params.require(:webhook).permit(:url, :type, :http_method, :content_type, :secret, :active, :branch_filter, events: [])
end
def webhook_type
webhook_params.fetch(:type, "gitea")
end
def webhook_branch_filter
webhook_params.fetch(:branch_filter, "*")
end
def gitea_webhooks_params
{
active: webhook_params[:active],
branch_filter: webhook_branch_filter,
config: {
content_type: webhook_params[:content_type],
url: webhook_params[:url],
http_method: webhook_params[:http_method],
secret: webhook_params[:secret]
},
events: webhook_params[:events],
type: webhook_type,
}
end
def operating_token
@project.member?(current_user) ? current_user.gitea_token : @project&.owner&.gitea_token
end
end

View File

@ -5,7 +5,7 @@ class ProjectsController < ApplicationController
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 :load_project, except: %i[index group_type_list migrate create recommend]
before_action :load_repository, except: %i[index group_type_list migrate create recommend]
before_action :authorizate_user_can_edit_project!, only: %i[update]
before_action :project_public?, only: %i[fork_users praise_users watch_users]
@ -116,10 +116,11 @@ class ProjectsController < ApplicationController
Projects::UpdateForm.new(validate_params).validate!
private = params[:private] || false
private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false
new_project_params = project_params.except(:private).merge(is_public: !private)
@project.update_attributes!(new_project_params)
@project.forked_projects.update_all(is_public: @project.is_public)
gitea_params = {
private: private,
default_branch: @project.default_branch,
@ -144,6 +145,7 @@ class ProjectsController < ApplicationController
ActiveRecord::Base.transaction do
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
@project.destroy!
@project.forked_projects.update_all(forked_from_project_id: nil)
render_ok
end
else

View File

@ -0,0 +1,64 @@
class PublicKeysController < ApplicationController
before_action :require_login
before_action :find_public_key, only: [:destroy]
def index
@public_keys = current_user.public_keys
@public_keys = kaminari_paginate(@public_keys)
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def create
return render_error("参数错误") if public_key_params.blank?
return render_ok({status: 10002, message: "请输入密钥"}) if public_key_params[:key].blank?
return render_ok({status: 10001, message: "请输入标题"}) if public_key_params[:title].blank?
@gitea_response = Gitea::User::Keys::CreateService.call(current_user.gitea_token, public_key_params)
if @gitea_response[0] == 201
@public_key = @gitea_response[2]
else
return render_error("创建ssh key失败") if @gitea_response[2].blank?
return render_ok({status: 10002, message: "密钥格式不正确"}) if @gitea_response[2]["message"].starts_with?("Invalid key content")
exist_public_key = Gitea::PublicKey.find_by(content: public_key_params[:key])
return render_ok({status: 10002, message: "密钥已被占用"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key") && exist_public_key.present? && exist_public_key&.owner_id != current_user.gitea_uid
return render_ok({status: 10002, message: "密钥已存在,请勿重复添加"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key")
@public_key = nil
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def destroy
return render_not_found unless @public_key.present?
result = Gitea::User::Keys::DeleteService.call(current_user.gitea_token, @public_key.id)
if result[0] == 204
render_ok
else
render_error
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def page
params[:page].to_i.zero? ? 1 : params[:page].to_i
end
def limit
limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
end
def public_key_params
params.require(:public_key).permit(:key, :title)
end
def find_public_key
@public_key = current_user.public_keys.find_by_id(params[:id])
end
end

View File

@ -56,7 +56,7 @@ class PullRequestsController < ApplicationController
ActiveRecord::Base.transaction do
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"])
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
render_ok
else
render_error("create pull request error: #{@gitea_pull_request[:status]}")
@ -91,7 +91,7 @@ class PullRequestsController < ApplicationController
if @issue.update_attributes(@issue_params)
if @pull_request.update_attributes(@local_params.compact)
gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier,
@pull_request.gpid, @requests_params, current_user.gitea_token)
@pull_request.gitea_number, @requests_params, current_user.gitea_token)
if gitea_pull[:status] === :success
if params[:issue_tag_ids].present?
@ -139,7 +139,7 @@ class PullRequestsController < ApplicationController
@issue_user = @issue.user
@issue_assign_to = @issue.get_assign_user
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
@repository.identifier, @pull_request.gpid, current_user&.gitea_token)
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
end
def pr_merge
@ -150,9 +150,16 @@ class PullRequestsController < ApplicationController
else
ActiveRecord::Base.transaction do
begin
result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params)
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
if result.status == 200 && @pull_request.merge!
if @gitea_pull["merged_by"].present?
success_condition = true
else
result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params)
success_condition = result.status == 200
end
if success_condition && @pull_request.merge!
@pull_request.project_trend_status!
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
normal_status(1, "合并成功")
@ -191,12 +198,12 @@ class PullRequestsController < ApplicationController
def files
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gpid, current_user&.gitea_token)
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token)
# render json: @files_result
end
def commits
@commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gpid, current_user&.gitea_token)
@commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token)
# render json: @commits_result
end

View File

@ -5,9 +5,9 @@ class RepositoriesController < ApplicationController
before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror]
before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit]
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
before_action :get_ref, only: %i[entries sub_entries top_counts file]
before_action :get_ref, only: %i[entries sub_entries top_counts file archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts]
@ -192,6 +192,19 @@ class RepositoriesController < ApplicationController
render json: languages_precentagable
end
def archive
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}"
file_path = [domain, api_url, archive_url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
return render_not_found if !request.format.zip? && !request.format.gzip?
redirect_to file_path
end
private
def find_project
@ -303,7 +316,7 @@ class RepositoriesController < ApplicationController
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
if local_requests.save
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"])
if gitea_request[:status] == :success && local_requests.update_attributes(gitea_number: gitea_request["body"]["number"])
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
end
end

View File

@ -25,17 +25,13 @@ class VersionsController < ApplicationController
end
def show
version_issues = @version.issues.issue_includes
version_issues = @version.issues.issue_issue.issue_includes
status_type = params[:status_type] || "1"
# @close_issues_size = version_issues.where(status_id: 5).size
# @open_issues_size = version_issues.size - @close_issues_size
if status_type.to_s == "1" #表示开启中的
version_issues = version_issues.where.not(status_id: 5)
else
version_issues = version_issues.where(status_id: 5)
end
version_issues = version_issues.where(author_id: params[:author_id]) if params[:author_id].present? && params[:author_id].to_s != "all"
version_issues = version_issues.where(assigned_to_id: params[:assigned_to_id]) if params[:assigned_to_id].present? && params[:assigned_to_id].to_s != "all"
version_issues = version_issues.where(tracker_id: params[:tracker_id]) if params[:tracker_id].present? && params[:tracker_id].to_s != "all"
@ -47,10 +43,26 @@ class VersionsController < ApplicationController
version_issues = version_issues.joins(:issue_tags).where(issue_tags: {id: params[:issue_tag_id].to_i}) if params[:issue_tag_id].present? && params[:issue_tag_id].to_s != "all"
version_issues = version_issues.reorder("#{order_name} #{order_type}")
has_filter_params = (params[:author_id].present? && params[:author_id].to_s != "all") ||
(params[:assigned_to_id].present? && params[:assigned_to_id].to_s != "all") ||
(params[:tracker_id].present? && params[:tracker_id].to_s != "all") ||
(params[:status_id].present? && params[:status_id].to_s != "all") ||
(params[:priority_id].present? && params[:priority_id].to_s != "all") ||
(params[:fixed_version_id].present? && params[:fixed_version_id].to_s != "all") ||
(params[:done_ratio].present? && params[:done_ratio].to_s != "all") ||
(params[:issue_type].present? && params[:issue_type].to_s != "all") ||
(params[:issue_tag_id].present? && params[:issue_tag_id].to_s != "all")
@version_close_issues_size = has_filter_params ? version_issues.closed.size : @version.issues.issue_issue.issue_includes.closed.size
@version_issues_size = has_filter_params ? version_issues.size : @version.issues.issue_issue.issue_includes.size
if status_type.to_s == "1" #表示开启中的
version_issues = version_issues.where.not(status_id: 5)
else
version_issues = version_issues.where(status_id: 5)
end
@page = params[:page] || 1
@limit = params[:limit] || 15
@version_issues_size = version_issues.size
# @version_issues_size = version_issues.size
@version_issues = version_issues.page(@page).per(@limit)
end

View File

@ -12,6 +12,7 @@ toc_footers:
includes:
- licenses
- gitignores
- public_keys
- users
- projects
- repositories

View File

@ -0,0 +1,158 @@
<!--
* @Date: 2021-07-14 15:10:29
* @LastEditors: viletyy
* @LastEditTime: 2021-07-14 15:37:23
* @FilePath: /forgeplus/app/docs/slate/source/includes/_public_keys.md
-->
# PublicKeys
## public_keys列表
获取public_keys列表支持分页
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/public_keys.json
```
```javascript
await octokit.request('GET /api/public_keys.json')
```
### HTTP 请求
`GET api/public_keys.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
page |否| 1 | int | 页码 |
limit |否| 15 | int | 每页数量 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
total_count |int |总数 |
public_keys.id |int |ID|
public_keys.name |string|密钥标题|
public_keys.content |string|密钥内容|
public_keys.fingerprint |string|密钥标识|
public_keys.created_time |string|密钥创建时间|
> 返回的JSON示例:
```json
{
"total_count": 1,
"public_keys": [
{
"id": 16,
"name": "xxx",
"content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
"fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM",
"created_unix": 1626246596,
"created_time": "2021/07/14 15:09"
}
]
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 创建public_key
创建public_key
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/public_keys.json
```
```javascript
await octokit.request('POST /api/public_keys.json')
```
### HTTP 请求
`POST api/public_keys.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
key |是 | 否 | string | 密钥 |
title |是 | 否 | string | 密钥标题 |
> 请求的JSON示例
```json
{
"public_key": {
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
"title": "xxx"
}
}
```
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
total_count |int |总数 |
id |int |ID|
name |string|密钥标题|
content |string|密钥内容|
fingerprint |string|密钥标识|
created_time |string|密钥创建时间|
> 返回的JSON示例:
```json
{
"id": 17,
"name": "xxx",
"content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
"fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM",
"created_time": "2021/07/14 15:26"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 删除public_key
删除public_key
> 示例:
```shell
curl -X DELETE \
http://localhost:3000/api/public_keys/:id.json
```
```javascript
await octokit.request('DELETE /api/public_keys/:id.json')
```
### HTTP 请求
`DELETE api/public_keys/:id.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
id |是 | 否 | int | 密钥ID |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>

View File

@ -867,3 +867,674 @@ await octokit.request('GET /api/jasder/jasder_test/sub_entries.json')
<aside class="success">
Success Data.
</aside>
## 获取仓库webhooks列表
获取仓库webhooks列表
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
```
### HTTP 请求
`GET /api/:owner/:repo/webhooks.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|url |string|地址|
|http_method |string|请求方式|
|is_active |bool |是否激活|
|type |string|类型|
|last_status |string|最后一次推送的状态|
|create_time |string|创建时间|
> 返回的JSON示例:
```json
{
"total_count": 4,
"webhooks": [
{
"id": 2,
"url": "https://oapi.dingtalk.com/robot/send?access_token=7e1e19d0eddb6a5e33c5c2c4e66f4c88f9437184b9ed2c2653194c6374c7d513",
"http_method": "",
"is_active": true,
"type": "dingtalk",
"last_status": "succeed",
"create_time": "2021-07-12 10:50:07"
},
{
"id": 3,
"url": "http://localhost:3000",
"http_method": "GET",
"is_active": true,
"type": "gitea",
"last_status": "succeed",
"create_time": "2021-07-26 10:03:45"
},
{
"id": 4,
"url": "http://localhost:10081",
"http_method": "POST",
"is_active": true,
"type": "gitea",
"last_status": "waiting",
"create_time": "2021-07-26 16:56:53"
},
{
"id": 5,
"url": "http://localhost:3001",
"http_method": "POST",
"is_active": true,
"type": "gitea",
"last_status": "fail",
"create_time": "2021-07-26 16:58:23"
}
]
}
```
<aside class="success">
Success Data.
</aside>
## 获取仓库单个webhook
获取仓库单个webhook
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/edit.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
```
### HTTP 请求
`GET /api/:owner/:repo/webhooks/:id/edit.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
|id |是||integer|webhook ID|
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|url |string|地址|
|content_type |string|POST Content Type|
|http_method |string|请求方式|
|secret| |string|密钥|
|is_active |bool |是否激活|
|type |string|类型|
|last_status |string|最后一次推送的状态, waiting 等待,fail 失败,succeed 成功|
|branch_filter |string|分支过滤|
|events |string|触发条件|
|create_time |string|创建时间|
参数| 含义|
--------- | ------- | ------- |
|create|创建分支或标签|
|delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送|
|issue|易修已打开、已关闭、已重新打开或编辑|
|issue_assign|易修被指派|
|issue_label|易修标签被更新或删除|
|issue_milestone|易修被收入里程碑|
|issue_comment|易修评论|
|pull_request|合并请求|
|pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
|pull_request_milestone|合并请求被记录于里程碑中|
|pull_request_comment|合并请求被评论|
|pull_request_review_approved|合并请求被批准|
|pull_request_review_rejected|合并请求被拒绝|
|pull_request_review_comment|合并请求被提出审查意见|
|pull_request_sync|合并请求被同步|
|repository|创建或删除仓库|
|release|版本发布|
> 返回的JSON示例:
```json
{
"id": 3,
"http_method": "GET",
"content_type": "form",
"url": "http://localhost:3000",
"secret": "123456",
"last_status": "succeed",
"is_active": true,
"type": "gitea",
"create_time": "2021-07-26 10:03:45",
"branch_filter": "*",
"events": [
"create",
"delete",
"fork",
"issues",
"issue_assign",
"issue_label",
"issue_milestone",
"issue_comment",
"push",
"pull_request",
"pull_request_assign",
"pull_request_label",
"pull_request_milestone",
"pull_request_comment",
"pull_request_review",
"pull_request_sync",
"repository",
"release"
]
}
```
<aside class="success">
Success Data.
</aside>
## 添加仓库webhook
添加仓库webhook
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/yystopf/ceshi/webhooks.json
```
```javascript
await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
```
### HTTP 请求
`POST /api/:owner/:repo/webhooks.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| | string |用户登录名 |
|repo |是| | string |项目标识identifier |
|webhook.url |是| | string |目标url |
|webhook.type |否| | string |类型|
|webhook.http_method |是| | string | http方法, POST和GET |
|webhook.content_type |是| | string | POST Content Type |
|webhook.secret |否| | string |密钥文本|
|webhook.active |是| | bool | 是否激活|
|webhook.branch_filter|否| |string|分支过滤|
|webhook.events |否| |array|触发事件|
触发事件字段说明
参数| 含义|
--------- | ------- | ------- |
|create|创建分支或标签|
|delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送|
|issue|易修已打开、已关闭、已重新打开或编辑|
|issue_assign|易修被指派|
|issue_label|易修标签被更新或删除|
|issue_milestone|易修被收入里程碑|
|issue_comment|易修评论|
|pull_request|合并请求|
|pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
|pull_request_milestone|合并请求被记录于里程碑中|
|pull_request_comment|合并请求被评论|
|pull_request_review_approved|合并请求被批准|
|pull_request_review_rejected|合并请求被拒绝|
|pull_request_review_comment|合并请求被提出审查意见|
|pull_request_sync|合并请求被同步|
|repository|创建或删除仓库|
|release|版本发布|
> 请求的JSON示例:
```json
{
"active": true,
"content_type": "json",
"http_method": "GET",
"secret": "123456",
"url": "http://localhost:10000",
"branch_filter": "*",
"events": ["push"]
}
```
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|url |string|地址|
|content_type |string|POST Content Type|
|is_active |bool |是否激活|
|type |string|类型|
|events | array|触发事件 |
|create_time |string|创建时间|
> 返回的JSON示例:
```json
{
"id": 18,
"type": "gitea",
"content_type": "json",
"url": "http://localhost:10000",
"events": [
"push"
],
"active": true,
"create_time": "2021-07-26 18:53:43"
}
```
<aside class="success">
Success Data.
</aside>
## 更新仓库webhook
更新仓库webhook
> 示例:
```shell
curl -X PATCH \
http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
```
```javascript
await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
```
### HTTP 请求
`PATCH /api/:owner/:repo/webhooks/:id.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| | string |用户登录名 |
|repo |是| | string |项目标识identifier |
|id |是| | string |webhook id |
|webhook.url |是| | string |目标url |
|webhook.type |否| | string |类型|
|webhook.http_method |是| | string | http方法, POST和GET |
|webhook.content_type |是| | string | POST Content Type |
|webhook.secret |否| | string |密钥文本|
|webhook.active |是| | bool | 是否激活|
|webhook.branch_filter|否| |string|分支过滤|
|webhook.events |否| |array|触发事件|
触发事件字段说明
参数| 含义|
--------- | ------- | ------- |
|create|创建分支或标签|
|delete|分支或标签删除|
|fork|仓库被fork|
|push|git仓库推送|
|issue|易修已打开、已关闭、已重新打开或编辑|
|issue_assign|易修被指派|
|issue_label|易修标签被更新或删除|
|issue_milestone|易修被收入里程碑|
|issue_comment|易修评论|
|pull_request|合并请求|
|pull_request_assign|合并请求被指派|
|pull_request_label|合并请求被贴上标签|
|pull_request_milestone|合并请求被记录于里程碑中|
|pull_request_comment|合并请求被评论|
|pull_request_review_approved|合并请求被批准|
|pull_request_review_rejected|合并请求被拒绝|
|pull_request_review_comment|合并请求被提出审查意见|
|pull_request_sync|合并请求被同步|
|repository|创建或删除仓库|
|release|版本发布|
> 请求的JSON示例:
```json
{
"active": true,
"content_type": "json",
"http_method": "GET",
"secret": "123456",
"url": "http://localhost:10000",
"branch_filter": "*",
"events": ["push"]
}
```
### 返回字段说明:
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success Data.
</aside>
## 删除仓库webhook
删除仓库webhook
> 示例:
```shell
curl -X DELETE \
http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
```
```javascript
await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json')
```
### HTTP 请求
`DELETE /api/:owner/:repo/webhooks/:id.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| | string |用户登录名 |
|repo |是| | string |项目标识identifier |
|id |是| | string |webhook id |
### 返回字段说明:
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success Data.
</aside>
## 获取仓库webhook的历史推送列表
获取仓库webhook的历史推送列表
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/tasks.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
```
### HTTP 请求
`GET /api/:owner/:repo/webhooks/:id/tasks.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
|id |是| |integer |webhook ID|
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|uuid |string|推送uuid|
|type |string|类型|
|is_succeed |bool|是否推送成功|
|is_delivered |bool|是否完成推送|
|payload_content |json|请求主体内容|
|request_content |json|请求内容,头部等等|
|reponse_content |json|响应内容,状态,头部,主体等等|
|delivered_time |string|推送时间|
> 返回的JSON示例:
```json
{
"total_count": 6,
"tasks": [
{
"id": 20,
"type": "gitea",
"uuid": "99aa2c23-6884-4c44-9020-5469320aa408",
"is_succeed": true,
"is_delivered": true,
"payload_content": {
"secret": "123456",
"ref": "refs/heads/master",
"before": "feb48e31362787a7620b53d4df3c4effddbb6f0b",
"after": "feb48e31362787a7620b53d4df3c4effddbb6f0b",
"compare_url": "",
"commits": [
{
"id": "feb48e31362787a7620b53d4df3c4effddbb6f0b",
"message": "fix\n",
"url": "http://localhost:10081/yystopf/ceshi/commit/feb48e31362787a7620b53d4df3c4effddbb6f0b",
"author": {
"name": "viletyy",
"email": "yystopf@163.com",
"username": "root"
},
"committer": {
"name": "viletyy",
"email": "yystopf@163.com",
"username": "root"
},
"verification": {
"verified": false,
"reason": "gpg.error.not_signed_commit",
"signature": "",
"signer": null,
"payload": ""
},
"timestamp": "2021-07-26T13:52:13+08:00",
"added": null,
"removed": null,
"modified": null
}
],
"head_commit": null,
"repository": {
"id": 2,
"owner": {
"id": 3,
"login": "yystopf",
"full_name": "",
"email": "yystopf@forge.com",
"avatar_url": "http://localhost:10081/user/avatar/yystopf/-1",
"language": "zh-CN",
"is_admin": true,
"last_login": "2021-07-21T18:38:21+08:00",
"created": "2021-06-03T14:50:25+08:00",
"username": "yystopf"
},
"name": "ceshi",
"full_name": "yystopf/ceshi",
"description": "",
"empty": false,
"private": false,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 3846,
"html_url": "http://localhost:10081/yystopf/ceshi",
"ssh_url": "virus@localhost:10081:yystopf/ceshi.git",
"clone_url": "http://localhost:10081/yystopf/ceshi.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 1,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 0,
"release_counter": 0,
"default_branch": "master",
"archived": false,
"created_at": "2021-06-03T15:15:30+08:00",
"updated_at": "2021-07-26T13:52:16+08:00",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"avatar_url": "",
"internal": false
},
"pusher": {
"id": 0,
"login": "yystopf",
"full_name": "",
"email": "yystopf@forge.com",
"avatar_url": "http://localhost:10081/user/avatar/yystopf/-1",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2021-06-03T14:50:25+08:00",
"username": "yystopf"
},
"sender": {
"id": 0,
"login": "yystopf",
"full_name": "",
"email": "yystopf@forge.com",
"avatar_url": "http://localhost:10081/user/avatar/yystopf/-1",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2021-06-03T14:50:25+08:00",
"username": "yystopf"
}
},
"request_content": {
"headers": {
"X-GitHub-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408",
"X-GitHub-Event": "push",
"X-Gitea-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408",
"X-Gitea-Event": "push",
"X-Gitea-Signature": "34a01edcd952ff6410ff6ebc946471161bde74aff86171f21621d2c2c4130f66",
"X-Gogs-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408",
"X-Gogs-Event": "push",
"X-Gogs-Signature": "34a01edcd952ff6410ff6ebc946471161bde74aff86171f21621d2c2c4130f66"
}
},
"response_content": {
"status": 200,
"headers": {
"Cache-Control": "no-store, must-revalidate, private, max-age=0",
"Content-Length": "2556",
"Content-Type": "text/html; charset=utf-8",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Set-Cookie": "__profilin=p%3Dt; path=/; HttpOnly",
"Vary": "Origin",
"X-Content-Type-Options": "nosniff",
"X-Download-Options": "noopen",
"X-Frame-Options": "SAMEORIGIN",
"X-Miniprofiler-Ids": "9ynvpncz5xm0rpgorb5y,hgggd9mv6lr4a9drcrlr,j7zqlx2vy5aji2vtgoba,f1ktsmh3jxvq0z2hf612,mih3dvgvlqhi3zy8lf2x,5k1qbkvbnru8mye9cest,tj6ern8w6awqf2zsimbr,9isaehvubivd52wo5p9v,1rzfhtq1nhuwbgy9p76g,z0xzidzyywna0y7a69m0,hzoklky92ycjqt42gi0s,y0ai7y0t28mcn8x0py2x,322il7nadinp51mw2r5m,m6dukftfsh6tjcxzp1gq,667wlqbytfwbrirnmma1,jcehj3dl8lkw8gk510cr",
"X-Miniprofiler-Original-Cache-Control": "max-age=0, private, must-revalidate",
"X-Permitted-Cross-Domain-Policies": "none",
"X-Request-Id": "08bff080-bbb5-4183-b845-81de3d47120a",
"X-Runtime": "0.394766",
"X-Xss-Protection": "1; mode=block"
},
"body": "<!doctype html><html lang=\"zh-CN\" class=\"notranslate translated-ltr\" translate=\"no\"><head><meta charset=\"utf-8\"><meta name=\"”Keywords”\" content=\"”trustie,trustieforge,forge,确实让创建更美好,协同开发平台″\"><meta name=\"”Keywords”\" content=\"”TrustieOpenSourceProject″\"><meta name=\"”Keywords”\" content=\"”issue,bug,tracker,软件工程,课程实践″\"><meta name=\"”Description”\" content=\"”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”\"><meta name=\"theme-color\" content=\"#000000\"><link rel=\"manifest\" href=\"/react/build//manifest.json\"><link rel=\"stylesheet\" href=\"/react/build/css/iconfont.css\"><link rel=\"stylesheet\" href=\"/react/build/css/edu-purge.css\"><link rel=\"stylesheet\" href=\"/react/build/css/editormd.min.css\"><link rel=\"stylesheet\" href=\"/react/build/css/merge.css\"><link href=\"/react/build/static/css/main.07f7e90c.chunk.css\" rel=\"stylesheet\"></head><body><div id=\"md_div\" style=\"display:none\"></div><div id=\"root\" class=\"page -layout-v -fit widthunit\"></div><div id=\"picture_display\" style=\"display:none\"></div><script src=\"/react/build/js/jquery-1.8.3.min.js\"></script><script src=\"/react/build/js/js_min_all.js\"></script><script src=\"/react/build/js/codemirror/codemirror.js\"></script><script src=\"/react/build/js/editormd/editormd.min.js\"></script><script src=\"/react/build/js/codemirror/merge/merge.js\"></script><script src=\"/react/build/./static/js/runtime~main.3d644966.js\"></script><script src=\"/react/build/./static/js/main.e46872e3.chunk.js\"></script><script async type=\"text/javascript\" id=\"mini-profiler\" src=\"/mini-profiler-resources/includes.js?v=67dd1c2571ced7fc74ae7f1813e47bdf\" data-version=\"67dd1c2571ced7fc74ae7f1813e47bdf\" data-path=\"/mini-profiler-resources/\" data-current-id=\"9ynvpncz5xm0rpgorb5y\" data-ids=\"9ynvpncz5xm0rpgorb5y,hgggd9mv6lr4a9drcrlr,j7zqlx2vy5aji2vtgoba,f1ktsmh3jxvq0z2hf612,mih3dvgvlqhi3zy8lf2x,5k1qbkvbnru8mye9cest,tj6ern8w6awqf2zsimbr,9isaehvubivd52wo5p9v,1rzfhtq1nhuwbgy9p76g,z0xzidzyywna0y7a69m0,hzoklky92ycjqt42gi0s,y0ai7y0t28mcn8x0py2x,322il7nadinp51mw2r5m,m6dukftfsh6tjcxzp1gq,667wlqbytfwbrirnmma1,jcehj3dl8lkw8gk510cr\" data-horizontal-position=\"left\" data-vertical-position=\"top\" data-trivial=\"false\" data-children=\"false\" data-max-traces=\"20\" data-controls=\"false\" data-total-sql-count=\"false\" data-authorized=\"true\" data-toggle-shortcut=\"alt+p\" data-start-hidden=\"false\" data-collapse-results=\"true\" data-html-container=\"body\"></script>\n</body></html>"
},
"delivered_time": "2021-07-28 11:47:29"
}
]
}
```
<aside class="success">
Success Data.
</aside>
## 仓库webhook测试推送
仓库webhook测试推送
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json
```
```javascript
await octokit.request('POST /api/yystopf/ceshi/webhooks/3/test.json')
```
### HTTP 请求
`POST /api/:owner/:repo/webhooks/:id/test.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| | string |用户登录名 |
|repo |是| | string |项目标识identifier |
|id |是| | integer|webhook ID|
### 返回字段说明:
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success Data.
</aside>

View File

@ -0,0 +1,8 @@
class Projects::Webhooks::CreateForm < BaseForm
attr_accessor :type, :url, :http_method, :content_type, :secret, :events, :active, :branch_filter
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"}
end

View File

@ -13,12 +13,12 @@ module ProjectsHelper
end
end
def render_zip_url(project, archive_name)
[gitea_domain, project.owner.login, project.identifier, "archive", "#{archive_name}.zip"].join('/')
def render_zip_url(owner, repository, archive)
[base_url, archive_repositories_path(owner&.login, repository, "#{archive}.zip")].join
end
def render_tar_url(project, archive_name)
[gitea_domain, project.owner.login, project.identifier, "archive", "#{archive_name}.tar.gz"].join('/')
def render_tar_url(owner, repository, archive)
[base_url, archive_repositories_path(owner&.login, repository, "#{archive}.tar.gz")].join
end
def render_http_url(project)

View File

@ -10,12 +10,12 @@ module RepositoriesHelper
end
def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx dot)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2)
default_type.include?(str&.downcase)
end
def image_type?(str)
default_type = %w(png jpg gif tif psd svg)
default_type = %w(png jpg gif tif psd svg gif bmp webp jpeg)
default_type.include?(str&.downcase)
end
@ -81,9 +81,47 @@ module RepositoriesHelper
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, entry['path'], ref: ref)['content']
readme_render_decode64_content(content, path)
else
file_type = entry['name'].to_s.split(".").last
return entry['content'] if download_type(file_type)
file_type = File.extname(entry['name'].to_s)[1..-1]
if download_type(file_type)
return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, entry['path'], ref: ref)['content'] : entry['content']
end
render_decode64_content(entry['content'])
end
end
def base64_to_image(path, content)
# generate to https://git.trusite.net/pawm36ozq/-/raw/branch/master/entrn.png"
content = Base64.decode64(content)
File.open(path, 'wb') { |f| f.write(content) }
end
def render_download_image_url(dir_path, file_path, content)
full_path = file_path.starts_with?("/") ? [dir_path, file_path].join("") : [dir_path, file_path].join("/")
file_name = full_path.split("/")[-1]
# 用户名/项目标识/文件路径
dir_path = generate_dir_path(full_path.split("/"+file_name)[0])
file_path = [dir_path, file_name].join('/')
puts "##### render_download_image_url file_path: #{file_path}"
base64_to_image(file_path, content)
file_path = file_path[6..-1]
File.join(base_url, file_path)
end
def generate_dir_path(dir_path)
# tmp_dir_path
# eg: jasder/forgeplus/raw/branch/ref
dir_path = ["public", tmp_dir, dir_path].join('/')
puts "#### dir_path: #{dir_path}"
unless Dir.exists?(dir_path)
FileUtils.mkdir_p(dir_path) ##不成功这里会抛异常
end
dir_path
end
def tmp_dir
"repo"
end
end

View File

@ -2,6 +2,7 @@ class ResetUserCacheJob < ApplicationJob
queue_as :cache
def perform(user)
return if user.nil?
Cache::UserFollowCountService.new(user).reset
Cache::UserIssueCountService.new(user).reset
Cache::UserProjectCountService.new(user).reset

View File

@ -1,19 +1,26 @@
# == Schema Information
#
# Table name: applied_messages
# Table name: forge_applied_messages
#
# id :integer not null, primary key
# user_id :integer
# applied_id :integer
# applied_type :string(255)
# applied_id :integer
# viewed :integer default("0")
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# name :string(255)
# applied_user_id :integer
# role :integer
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_forge_applied_messages_on_applied_type_and_applied_id (applied_type,applied_id)
# index_forge_applied_messages_on_applied_user_id (applied_user_id)
# index_forge_applied_messages_on_project_id (project_id)
# index_forge_applied_messages_on_user_id (user_id)
#
class AppliedMessage < ApplicationRecord

View File

@ -1,14 +1,19 @@
# == Schema Information
#
# Table name: applied_projects
# Table name: forge_applied_projects
#
# id :integer not null, primary key
# project_id :integer not null
# user_id :integer not null
# project_id :integer
# user_id :integer
# role :integer default("0")
# status :integer default("0")
# created_at :datetime
# updated_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_forge_applied_projects_on_project_id (project_id)
# index_forge_applied_projects_on_user_id (user_id)
#
class AppliedProject < ApplicationRecord

View File

@ -17,7 +17,7 @@
# disk_directory :string(255)
# attachtype :integer default("1")
# is_public :integer default("1")
# copy_from :integer
# copy_from :string(255)
# quotes :integer default("0")
# is_publish :integer default("1")
# publish_time :datetime
@ -26,18 +26,19 @@
# cloud_url :string(255) default("")
# course_second_category_id :integer default("0")
# delay_publish :boolean default("0")
# link :string(255)
# clone_id :integer
#
# Indexes
#
# index_attachments_on_author_id (author_id)
# index_attachments_on_clone_id (clone_id)
# index_attachments_on_container_id_and_container_type (container_id,container_type)
# index_attachments_on_course_second_category_id (course_second_category_id)
# index_attachments_on_created_on (created_on)
# index_attachments_on_is_public (is_public)
# index_attachments_on_quotes (quotes)
#
class Attachment < ApplicationRecord
include BaseModel
include Publicable

View File

@ -39,17 +39,15 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# gitea_uid :integer
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# sponsor_certification :integer default("0")
# sponsor_num :integer default("0")
# sponsored_num :integer default("0")
# award_time :datetime
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@ -57,8 +55,9 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type)
#

View File

@ -65,7 +65,7 @@ module ProjectOperable
if owner.is_a?(User)
managers.exists?(user_id: user.id)
elsif owner.is_a?(Organization)
managers.exists?(user_id: user.id) || owner.is_only_admin?(user.id)
managers.exists?(user_id: user.id) || owner.is_owner?(user.id) || owner.is_only_admin?(user.id)
else
false
end
@ -94,7 +94,7 @@ module ProjectOperable
end
def operator?(user)
user.admin? || !reporter?(user)
user.admin? || (member?(user.id) && !reporter?(user))
end
def set_developer_role(member, role_name)

View File

@ -1,4 +1,6 @@
class Gitea::Base < Gitea::Database
self.abstract_class = true
class Gitea::Base < ApplicationRecord
db_config = Rails.configuration.database_configuration[Rails.env]["gitea_server"]
raise 'gitea database config missing' if db_config.blank?
establish_connection db_config
end

View File

@ -0,0 +1,9 @@
class Gitea::PublicKey < Gitea::Base
self.inheritance_column = nil # FIX The single-table inheritance mechanism failed
# establish_connection :gitea_db
self.table_name = "public_key"
belongs_to :user, class_name: '::User', primary_key: :gitea_uid, foreign_key: :owner_id, optional: true
end

44
app/models/gitea/pull.rb Normal file
View File

@ -0,0 +1,44 @@
# == Schema Information
#
# Table name: pull_request
#
# id :integer not null, primary key
# type :integer
# status :integer
# conflicted_files :text(65535)
# commits_ahead :integer
# commits_behind :integer
# changed_protected_files :text(65535)
# issue_id :integer
# index :integer
# head_repo_id :integer
# base_repo_id :integer
# head_branch :string(255)
# base_branch :string(255)
# merge_base :string(40)
# has_merged :boolean
# merged_commit_id :string(40)
# merger_id :integer
# merged_unix :integer
#
# Indexes
#
# IDX_pull_request_base_repo_id (base_repo_id)
# IDX_pull_request_has_merged (has_merged)
# IDX_pull_request_head_repo_id (head_repo_id)
# IDX_pull_request_issue_id (issue_id)
# IDX_pull_request_merged_unix (merged_unix)
# IDX_pull_request_merger_id (merger_id)
#
class Gitea::Pull < Gitea::Base
self.inheritance_column = nil # FIX The single-table inheritance mechanism failed
# establish_connection :gitea_db
self.table_name = "pull_request"
serialize :conflicted_files, Array
belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_id, optional: true
end

View File

@ -0,0 +1,13 @@
class Gitea::Webhook < Gitea::Base
serialize :events, JSON
self.inheritance_column = nil
self.table_name = 'webhook'
has_many :tasks, class_name: "Gitea::WebhookTask", foreign_key: :hook_id
belongs_to :project, class_name: "::Project", primary_key: :gpid, foreign_key: :repo_id, optional: true
enum hook_task_type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9}
enum last_status: {waiting: 0, succeed: 1, fail: 2}
enum content_type: {json: 1, form: 2}
end

View File

@ -0,0 +1,13 @@
class Gitea::WebhookTask < Gitea::Base
serialize :payload_content, JSON
serialize :request_content, JSON
serialize :response_content, JSON
self.inheritance_column = nil
self.table_name = 'hook_task'
belongs_to :webhook, class_name: "Gitea::Webhook", foreign_key: :hook_id
enum type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9}
end

View File

@ -10,6 +10,7 @@
# sync_course :boolean default("0")
# sync_subject :boolean default("0")
# sync_shixun :boolean default("0")
# is_local :boolean default("0")
#
# Indexes
#

View File

@ -7,7 +7,6 @@
# content :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# is_secret :boolean default("0")
#
class License < ApplicationRecord

View File

@ -11,7 +11,6 @@
# course_group_id :integer default("0")
# is_collect :integer default("1")
# graduation_group_id :integer default("0")
# is_apply_signature :boolean default("0")
#
# Indexes
#

View File

@ -39,17 +39,15 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# gitea_uid :integer
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# sponsor_certification :integer default("0")
# sponsor_num :integer default("0")
# sponsored_num :integer default("0")
# award_time :datetime
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@ -57,8 +55,9 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type)
#

View File

@ -37,8 +37,6 @@
# rep_identifier :string(255)
# project_category_id :integer
# project_language_id :integer
# license_id :integer
# ignore_id :integer
# praises_count :integer default("0")
# watchers_count :integer default("0")
# issues_count :integer default("0")
@ -52,9 +50,10 @@
# open_devops_count :integer default("0")
# recommend :boolean default("0")
# platform :integer default("0")
# license_id :integer
# ignore_id :integer
# default_branch :string(255) default("master")
# website :string(255)
# order_index :integer default("0")
# lesson_url :string(255)
#
# Indexes
@ -64,8 +63,11 @@
# index_projects_on_invite_code (invite_code)
# index_projects_on_is_public (is_public)
# index_projects_on_lft (lft)
# index_projects_on_license_id (license_id)
# index_projects_on_name (name)
# index_projects_on_platform (platform)
# index_projects_on_project_category_id (project_category_id)
# index_projects_on_project_language_id (project_language_id)
# index_projects_on_project_type (project_type)
# index_projects_on_recommend (recommend)
# index_projects_on_rgt (rgt)
@ -74,8 +76,6 @@
#
class Project < ApplicationRecord
include Matchable
include Publicable
@ -98,10 +98,12 @@ class Project < ApplicationRecord
belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects
belongs_to :project_category, optional: true , :counter_cache => true
belongs_to :project_language, optional: true , :counter_cache => true
belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id
has_many :project_trends, dependent: :destroy
has_many :watchers, as: :watchable, dependent: :destroy
has_many :fork_users, dependent: :destroy
has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy
has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id
has_one :project_educoder, dependent: :destroy
has_one :project_score, dependent: :destroy
@ -120,6 +122,7 @@ class Project < ApplicationRecord
has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy
has_many :pinned_projects, dependent: :destroy
has_many :has_pinned_users, through: :pinned_projects, source: :user
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
after_save :check_project_members, :reset_cache_data
before_save :set_invite_code

View File

@ -8,11 +8,6 @@
# projects_count :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# ancestry :string(255)
#
# Indexes
#
# index_project_categories_on_ancestry (ancestry)
#
class ProjectCategory < ApplicationRecord

View File

@ -37,6 +37,7 @@ class PullRequest < ApplicationRecord
has_many :pull_request_tags, foreign_key: :pull_request_id
has_many :project_trends, as: :trend, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy
has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_id, class_name: 'Gitea::Pull'
scope :merged_and_closed, ->{where.not(status: 0)}
scope :opening, -> {where(status: 0)}
@ -53,8 +54,10 @@ class PullRequest < ApplicationRecord
Project.find_by(id: self.fork_project_id)
end
def bind_gitea_pull_request!(gitea_pull_number)
update_column(:gpid, gitea_pull_number)
def bind_gitea_pull_request!(gitea_pull_number, gitea_pull_id)
update_columns(
gitea_number: gitea_pull_number,
gitea_id: gitea_pull_id)
end
def merge!
@ -67,19 +70,26 @@ class PullRequest < ApplicationRecord
# TODO: sync educoder platform repo's for update some statistics count
def self.update_some_count
PullRequest.includes(:user, :project).select(:id, :user_id, :gpid, :project_id, :fork_project_id).each do |pr|
PullRequest.includes(:user, :project).select(:id, :user_id, :gitea_number, :project_id, :fork_project_id).each do |pr|
puts pr.id
next if pr.gpid.blank?
next if pr.gitea_number.blank?
project = pr.project
next if project.blank?
user = project.owner
next if pr.gpid === 6 || pr.gpid === 7
files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gpid)
next if pr.gitea_number === 6 || pr.gitea_number === 7
files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gitea_number)
pr.update_column(:files_count, files_result['NumFiles']) unless files_result.blank?
commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gpid)
commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gitea_number)
pr.update_column(:commits_count, commits_result.size) unless commits_result.blank?
end
end
def conflict_files
file_names = self&.gitea_pull&.conflicted_files
return [] if file_names.blank?
JSON.parse file_names
end
end

View File

@ -27,7 +27,6 @@
#
# Indexes
#
# index_repositories_on_identifier (identifier)
# index_repositories_on_project_id (project_id)
# index_repositories_on_user_id (user_id)
#

View File

@ -39,17 +39,15 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# gitea_uid :integer
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# sponsor_certification :integer default("0")
# sponsor_num :integer default("0")
# sponsored_num :integer default("0")
# award_time :datetime
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@ -57,8 +55,9 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type)
#
@ -171,6 +170,7 @@ class User < Owner
accepts_nested_attributes_for :is_pinned_projects
has_many :issues, dependent: :destroy, foreign_key: :author_id
has_many :pull_requests, dependent: :destroy
has_many :public_keys, class_name: "Gitea::PublicKey",primary_key: :gitea_uid, foreign_key: :owner_id, dependent: :destroy
# Groups and active users
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
@ -187,7 +187,7 @@ class User < Owner
:show_email, :show_location, :show_department,
:technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true
before_save :update_hashed_password
before_save :update_hashed_password, :set_lastname
after_create do
SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie?
end
@ -792,6 +792,10 @@ class User < Owner
self.laboratory = Laboratory.current if laboratory_id.blank?
end
def set_lastname
self.lastname = self.nickname if changes[:nickname].present?
end
end

View File

@ -12,7 +12,9 @@
#
# Indexes
#
# index_user_actions_on_ip (ip)
# index_user_actions_on_ip (ip)
# index_user_actions_on_user_id (user_id)
# index_user_actions_on_user_id_and_action_type (user_id,action_type)
#
class UserAction < ApplicationRecord

View File

@ -10,10 +10,13 @@
# updated_at :datetime not null
# register_status :integer default("0")
# action_status :integer default("0")
# is_delete :boolean default("0")
# user_id :integer
#
# Indexes
#
# index_user_agents_on_ip (ip) UNIQUE
# index_user_agents_on_ip (ip)
# index_user_agents_on_user_id (user_id)
#
class UserAgent < ApplicationRecord

View File

@ -22,6 +22,9 @@
# school_id :integer
# description :string(255) default("")
# department_id :integer
# honor :text(65535)
# edu_background :integer
# edu_entry_year :integer
# province :string(255)
# city :string(255)
# custom_department :string(255)

View File

@ -46,11 +46,11 @@ class Cache::PlatformProjectLanguagesCountService < ApplicationService
def reset_platform_project_language_count_by_key
return if key.nil?
$redis_cache.hset(platform_project_language_count_key, key, Project.joins(:project_language).where(project_languages: {name: key}).count)
$redis_cache.hset(platform_project_language_count_key, key, ProjectLanguage.where(name: key).projects_count)
end
def reset_platform_project_language_count
Project.joins(:project_language).group("project_languages.name").count.each do |k, v|
ProjectLanguage.where.not(projects_count: 0).group("project_languages.name").sum(:projects_count).each do |k, v|
$redis_cache.hset(platform_project_language_count_key, k, v)
end
end

View File

@ -108,6 +108,7 @@ class Gitea::ClientService < ApplicationService
def full_url(api_rest, action='post')
url = [api_url, api_rest].join('').freeze
url = action === 'get' ? url : URI.escape(url)
url = URI.escape(url) unless url.ascii_only?
puts "[gitea] request url: #{url}"
return url
end

View File

@ -8,7 +8,7 @@ class Gitea::PullRequest::CloseService < Gitea::PullRequest::UpdateService
# number: number of pull request
# token: token of gitea user
# eq:
# Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gpid, pull.base, current_user.gitea_token)
# Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gitea_number, pull.base, current_user.gitea_token)
def initialize(owner, repo, number, base,token=nil)
colse_pull_params = Hash.new.merge(base: base, state: 'closed').compact

View File

@ -3,7 +3,7 @@ class Gitea::PullRequest::GetService < Gitea::ClientService
attr_reader :owner, :repo, :number, :token
#eq:
# Gitea::PullRequest::GetService.call(user.login, repository.identifier, pull.gpid, user.gitea_token)
# Gitea::PullRequest::GetService.call(user.login, repository.identifier, pull.gitea_number, user.gitea_token)
def initialize(owner, repo, number, token=nil)
@owner = owner
@repo = repo

View File

@ -8,7 +8,7 @@ class Gitea::PullRequest::OpenService < Gitea::PullRequest::UpdateService
# number: number of pull request
# token: token of gitea user
# eq:
# Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gpid, pr.base, current_user.gitea_token)
# Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gitea_number, pr.base, current_user.gitea_token)
def initialize(owner, repo, number, base, token=nil)
open_pull_params = Hash.new.merge(base: base, state: 'open').compact

View File

@ -0,0 +1,40 @@
class Gitea::Repository::ArchiveService < Gitea::ClientService
attr_reader :owner, :repo, :archive, :token
def initialize(owner, repo, archive, token=nil)
@owner = owner
@repo = repo
@archive = archive
@token = token
end
def call
response = get(url, params)
response_payload(response)
end
private
def params
Hash.new.merge(token: token)
end
def url
"/repos/#{owner}/#{repo}/archive/#{archive}".freeze
end
def response_payload(response)
status = response.status
body = response&.body
log_error(status, body)
status_payload(status, body)
end
def status_payload(status, body)
case status
when 200 then success
when 404 then error("你操作的链接不存在!")
else error("系统错误!")
end
end
end

View File

@ -0,0 +1,23 @@
class Gitea::Repository::Webhooks::CreateService < Gitea::ClientService
attr_reader :token, :owner, :repo, :params
def initialize(token, owner, repo, params)
@token = token
@owner = owner
@repo = repo
@params = params
end
def call
response = post(url, request_params)
render_response(response)
end
private
def request_params
Hash.new.merge({token: token, data: params})
end
def url
"/repos/#{owner}/#{repo}/hooks".freeze
end
end

View File

@ -0,0 +1,24 @@
class Gitea::Repository::Webhooks::DeleteService < Gitea::ClientService
attr_reader :token, :owner, :repo, :id
def initialize(token, owner, repo, id)
@token = token
@owner = owner
@repo = repo
@id = id
end
def call
response = delete(url, params)
render_response(response)
end
private
def params
Hash.new.merge(token: token)
end
def url
"/repos/#{owner}/#{repo}/hooks/#{id}".freeze
end
end

View File

@ -0,0 +1,27 @@
class Gitea::Repository::Webhooks::TasksService < Gitea::ClientService
attr_reader :token, :owner, :repo, :webhook_id
# ref: The name of the commit/branch/tag. Default the repositorys default branch (usually master)
# repo_name: the name of repository
def initialize(token, owner, repo, webhook_id)
@token = token
@owner = owner
@repo = repo
@webhook_id = webhook_id
end
def call
response = get(url, params)
render_response(response)
end
private
def params
Hash.new.merge(token: user.gitea_token)
end
def url
"/repos/#{owner}/#{repo}/hooks/#{webhook_id}/hook_tasks".freeze
end
end

View File

@ -0,0 +1,24 @@
class Gitea::Repository::Webhooks::TestService < Gitea::ClientService
attr_reader :token, :owner, :repo, :webhook_id
def initialize(token, owner, repo, webhook_id)
@token = token
@owner = owner
@repo = repo
@webhook_id = webhook_id
end
def call
response = post(url, request_params)
render_response(response)
end
private
def request_params
Hash.new.merge({token: token})
end
def url
"/repos/#{owner}/#{repo}/hooks/#{webhook_id}/tests".freeze
end
end

View File

@ -0,0 +1,24 @@
class Gitea::Repository::Webhooks::UpdateService < Gitea::ClientService
attr_reader :token, :owner, :repo, :id, :params
def initialize(token, owner, repo, id, params)
@token = token
@owner = owner
@repo = repo
@id = id
@params = params
end
def call
response = patch(url, data_params)
render_response(response)
end
private
def url
"/repos/#{owner}/#{repo}/hooks/#{id}"
end
def data_params
Hash.new.merge(token: token, data: params).compact
end
end

View File

@ -0,0 +1,21 @@
class Gitea::User::Keys::CreateService < Gitea::ClientService
attr_reader :token, :params
def initialize(token, params)
@token = token
@params = params
end
def call
response = post(url, request_params)
render_response(response)
end
private
def request_params
Hash.new.merge({token: token, data: params})
end
def url
'/user/keys'.freeze
end
end

View File

@ -0,0 +1,23 @@
class Gitea::User::Keys::DeleteService < Gitea::ClientService
attr_reader :token, :key_id
def initialize(token, key_id)
@token = token
@key_id = key_id
end
def call
response = delete(url, params)
render_response(response)
end
private
def params
Hash.new.merge(token: token)
end
def url
"/user/keys/#{key_id}".freeze
end
end

View File

@ -0,0 +1,22 @@
class Gitea::User::Keys::GetService < Gitea::ClientService
attr_reader :token, :key_id
def initialize(token, key_id)
@token = token
@key_id = key_id
end
def call
response = get(url, params)
render_response(response)
end
private
def params
Hash.new.merge({token: token})
end
def url
"/user/keys/#{key_id}".freeze
end
end

View File

@ -0,0 +1,26 @@
class Gitea::User::Keys::ListService < Gitea::ClientService
attr_reader :token, :page, :limit, :fingerprint
def initialize(token, page, limit, fingerprint="")
@token = token
@page = page
@limit = limit
@fingerprint = fingerprint
end
def call
response = get(url, params)
render_response(response)
end
private
def params
Hash.new.merge({token: token, fingerprint: fingerprint, page: page, limit: limit})
end
def url
'/user/keys'.freeze
end
end

View File

@ -8,6 +8,7 @@ class Projects::CreateService < ApplicationService
def call
Rails.logger.info("#############__________project_params______###########{project_params}")
raise Error, "user_id不正确." unless authroize_user_id_success
@project = Project.new(project_params)
ActiveRecord::Base.transaction do
@ -27,6 +28,10 @@ class Projects::CreateService < ApplicationService
private
def authroize_user_id_success
(user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?)
end
def project_params
{
name: params[:name],

View File

@ -8,6 +8,8 @@ class Projects::MigrateService < ApplicationService
end
def call
raise Error, "user_id不正确." unless authroize_user_id_success
@project = Project.new(project_params)
if @project.save!
ProjectUnit.init_types(@project.id, project.project_type)
@ -24,6 +26,9 @@ class Projects::MigrateService < ApplicationService
end
private
def authroize_user_id_success
(user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?)
end
def project_params
{

View File

@ -23,7 +23,7 @@ class PullRequests::CloseService < ApplicationService
def close_gitea_pull
Gitea::PullRequest::CloseService.call(@owner.login, @repo.identifier,
@pull.gpid, @pull.base, current_user.gitea_token)
@pull.gitea_number, @pull.base, current_user.gitea_token)
end
def update_pull_status!

View File

@ -22,7 +22,7 @@ class PullRequests::MergeService < ApplicationService
def gitea_pull_merge!
result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login,
@repo.identifier, @pull.gpid, gitea_merge_pull_params)
@repo.identifier, @pull.gitea_number, gitea_merge_pull_params)
@status, @message = result
end

View File

@ -23,7 +23,7 @@ class PullRequests::OpenService < ApplicationService
def open_gitea_pull
Gitea::PullRequest::OpenService.call(@owner.login, @repo.identifier,
@pull.gpid, @pull.base, @current_user.gitea_token)
@pull.gitea_number, @pull.base, @current_user.gitea_token)
end
def update_pull_status!

View File

@ -83,3 +83,5 @@ json.diff do
end
end
json.status @merge_status
json.message @merge_message

View File

@ -2,6 +2,6 @@ json.total_count @owners.size
json.owners @owners.each do |owner|
json.id owner.id
json.type owner.type
json.name owner.login
json.name owner&.show_real_name
json.avatar_url url_to_avatar(owner)
end

View File

@ -4,8 +4,8 @@ json.array! @branches do |branch|
json.user_can_merge branch['user_can_merge']
json.protected branch['protected']
json.http_url render_http_url(@project)
json.zip_url render_zip_url(@project, branch['name'])
json.tar_url render_tar_url(@project, branch['name'])
json.zip_url render_zip_url(@owner, @repository, branch['name'])
json.tar_url render_tar_url(@owner, @repository, branch['name'])
json.last_commit do
json.sha branch['commit']['id']
json.message branch['commit']['message']

View File

@ -1 +1,2 @@
json.extract! @project, :id, :name,:identifier
json.login @project&.owner.login

View File

@ -0,0 +1,4 @@
json.(webhook, :id, :url, :http_method, :is_active)
json.type webhook.hook_task_type
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,7 @@
json.id @webhook["id"]
json.type @webhook["type"]
json.content_type @webhook["config"]["content_type"]
json.url @webhook["config"]["url"]
json.events @webhook["events"]
json.active @webhook["active"]
json.create_time @webhook["created_at"].to_time.strftime("%Y-%m-%d %H:%M:%S")

View File

@ -0,0 +1,11 @@
json.id @webhook.id
json.(@webhook, :id, :http_method, :content_type, :url, :secret, :last_status, :is_active)
json.type @webhook.hook_task_type
json.create_time Time.at(@webhook.created_unix).strftime("%Y-%m-%d %H:%M:%S")
event = @webhook.events
json.branch_filter event["branch_filter"]
if event["send_everything"]
json.events event["events"].keys.collect{|i| i == "pull_request" ? i + "_only" : i}
else
json.events event["events"].select{|k, v| v}.keys.collect{|i| i == "pull_request" ? i + "_only" : i}
end

View File

@ -0,0 +1,4 @@
json.total_count @webhooks.total_count
json.webhooks @webhooks.each do |webhook|
json.partial! 'detail', webhook: webhook
end

View File

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

View File

@ -0,0 +1,8 @@
if @public_key.present?
json.status 0
json.id @public_key["id"]
json.name @public_key["title"]
json.content @public_key["key"]
json.fingerprint @public_key["fingerprint"]
json.created_time @public_key["created_at"].to_time.strftime("%Y/%m/%d %H:%M")
end

View File

@ -0,0 +1,5 @@
json.total_count @public_keys.total_count
json.public_keys @public_keys do |public_key|
json.(public_key, :id, :name, :content, :fingerprint, :created_unix)
json.created_time Time.at(public_key.created_unix).strftime("%Y/%m/%d %H:%M")
end

View File

@ -32,3 +32,5 @@ json.issue do
json.version @issue.version.try(:name)
json.issue_tags @issue.get_issue_tags
end
json.conflict_files @pull_request.conflict_files

View File

@ -1,6 +1,6 @@
if @project.forge?
file_name = entry['name']
file_type = file_name.to_s.split(".").last
file_type = File.extname(file_name.to_s)[1..-1]
direct_download = download_type(file_type)
image_type = image_type?(file_type)
json.name file_name
@ -11,7 +11,16 @@ if @project.forge?
json.content decode64_content(entry, @owner, @repository, @ref)
json.target entry['target']
json.download_url entry['download_url']
download_url =
if image_type
dir_path = [@owner.login, @repository.identifier, "raw/branch", @ref].join('/')
render_download_image_url(dir_path, entry['path'], decode64_content(entry, @owner, @repository, @ref))
else
entry['download_url']
end
json.download_url download_url
json.direct_download direct_download
json.image_type image_type
json.is_readme_file is_readme?(entry['type'], entry['name'])

View File

@ -42,8 +42,9 @@ if @project.forge?
#json.tags_count @tags_count
#json.branches_count @branches_count
json.commits_count @commits_count
json.zip_url render_zip_url(@project, @ref)
json.tar_url render_tar_url(@project, @ref)
# json.zip_url archive_repositories_path(@owner&.login, @repository, @ref)
json.zip_url render_zip_url(@owner, @repository, @ref)
json.tar_url render_tar_url(@owner, @repository, @ref)
json.entries do
json.array! @entries do |entry|
json.name entry['name']

View File

@ -2,8 +2,8 @@ json.array! @tags do |tag|
if tag.present?
json.name tag['name']
json.id tag['id']
json.zipball_url tag['zipball_url']
json.tarball_url tag['tarball_url']
json.zipball_url render_zip_url(@owner, @repository, tag['name'])
json.tarball_url render_tar_url(@owner, @repository, tag['name'])
json.commit do
json.sha tag['commit']['sha']
end

View File

@ -14,8 +14,8 @@ json.releases do
json.name re["name"]
json.body re["body"]
json.url re["url"]
json.tarball_url re["tarball_url"]
json.zipball_url re["zipball_url"]
json.tarball_url render_tar_url(@owner, @repository, re["tag_name"])
json.zipball_url render_zip_url(@owner, @repository, re["tag_name"])
json.draft re["draft"] ? "草稿" : (re["prerelease"] ? "预发行" : "稳定")
json.created_at format_time(version.created_at.to_s.to_time)
json.published_at format_time(version.created_at.to_s.to_time)
@ -30,8 +30,8 @@ json.releases do
json.name re["name"]
json.body re["body"]
json.url re["url"]
json.tarball_url re["tarball_url"]
json.zipball_url re["zipball_url"]
json.tarball_url render_tar_url(@owner, @repository, re["tag_name"])
json.zipball_url render_zip_url(@owner, @repository, re["tag_name"])
json.draft re["draft"] ? "草稿" : (re["prerelease"] ? "预发行" : "稳定")
json.created_at format_time(version.created_at.to_s.to_time)
json.published_at format_time(version.created_at.to_s.to_time)

View File

@ -7,8 +7,8 @@ json.versions do
json.array! @versions.each.to_a do |version|
json.extract! version, :id, :name, :description, :effective_date,:status,:percent
json.open_issues_count (version.issues_count - version.closed_issues_count)
json.close_issues_count version.closed_issues_count
json.open_issues_count (version.issues.issue_issue.size - version.issues.issue_issue.closed.size)
json.close_issues_count version.issues.issue_issue.closed.size
json.created_at format_time(version.created_on)
json.updated_at format_time(version.updated_on)
json.user_name version.version_user.try(:show_real_name)

View File

@ -1,7 +1,7 @@
json.partial! "commons/success"
json.issues_count @version.issues_count
json.open_issues_count @version.issues_count - @version.closed_issues_count
json.close_issues_count @version.closed_issues_count
json.issues_count @version_issues_size
json.open_issues_count @version_issues_size - @version_close_issues_size
json.close_issues_count @version_close_issues_size
json.limit @limit
json.user_name @version.version_user.try(:show_real_name)
json.user_login @version.version_user.try(:login)

View File

@ -1,6 +1,7 @@
default: &default
# 用户登入的时候设置/登出的时候清空
autologin_cookie_name: 'autologin_trustie'
platform_url: 'http://localhost:3000'
#附件上传路径

View File

@ -17,6 +17,13 @@ default: &default
username: root
password: 123456
# socket: /var/run/mysqld/mysqld.sock
gitea_server:
aadapter: mysql2
database: gitea_development
host: 127.0.0.1
username: root
password: "123456"
encoding: utf8
development:
<<: *default

View File

@ -4,5 +4,5 @@
# Rails.application.config.session_store :active_record_store
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cache_store, :expire_after => 24.hours, :httponly => false, :secure => false, key: '_educoder_session', domain: :all
Rails.application.config.session_store :cache_store, :expire_after => 24.hours, :httponly => true, :secure => false, key: '_educoder_session', domain: :all

View File

@ -71,6 +71,8 @@ Rails.application.routes.draw do
# end
end
resources :public_keys, only: [:index, :create, :destroy]
resources :statistic, only: [:index] do
collection do
get :platform_profile
@ -417,7 +419,6 @@ Rails.application.routes.draw do
member do
get :files
get :detail
get :archive
get :entries
match :sub_entries, :via => [:get, :put]
get :commits
@ -432,6 +433,7 @@ Rails.application.routes.draw do
get 'commits/:sha', to: 'repositories#commit', as: 'commit'
get 'readme'
get 'languages'
get 'archive/:archive', to: 'repositories#archive', as: "archive", constraints: { archive: /.+/, format: /(zip|gzip)/ }
end
end
@ -570,6 +572,12 @@ Rails.application.routes.draw do
post :cancel
end
end
resources :webhooks, except: [:show, :new] do
member do
get :tasks
post :test
end
end
scope do
get(
'/blob/*id/diff',

View File

@ -0,0 +1,7 @@
class AddProjectLanguageIndexToProjects < ActiveRecord::Migration[5.2]
def change
add_index :projects, :project_category_id
add_index :projects, :project_language_id
add_index :projects, :license_id
end
end

View File

@ -0,0 +1,22 @@
class ChangeColumnsNameFromPullRequests < ActiveRecord::Migration[5.2]
def change
rename_column :pull_requests, :pull_request_id, :gitea_id
rename_column :pull_requests, :gpid, :gitea_number
PullRequest.find_each do |pr|
next if pr.gitea_number.blank?
project = pr.project
next if project.blank?
owner = project&.owner
gitea_pull = Gitea::PullRequest::GetService.call(owner.login, project.identifier, pr.gitea_number, owner&.gitea_token)
next if gitea_pull.blank?
pr.update_column(:gitea_id, gitea_pull["id"])
end
end
end

View File

@ -0,0 +1,26 @@
namespace :sync_projects_by_forked_project do
desc "sync projects is_public by forked project"
task is_public: :environment do
count = 0
Project.where.not(forked_from_project_id: nil).group(:forked_from_project_id).count.each do |k, _|
project = Project.find_by_id(k)
need_update_forked_projects = Project.where(forked_from_project_id: k)
need_update_forked_projects.update_all(is_public: project&.is_public)
need_update_forked_repositories = Repository.where(project_id: need_update_forked_projects.ids)
need_update_forked_repositories.update_all(hidden: !project&.is_public)
count +=need_update_forked_projects.size
end
puts "共同步了#{count}个项目"
end
task destroy: :environment do
count = 0
Project.where.not(forked_from_project_id: nil).find_each do |project|
if project.forked_from_project.nil?
project.update(forked_from_project_id: nil)
count +=1
end
end
puts "共同步了#{count}个项目"
end
end

File diff suppressed because one or more lines are too long