Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop

# Conflicts:
#	app/controllers/users_controller.rb
#	app/helpers/application_helper.rb
This commit is contained in:
xiaoxiaoqiong 2022-05-23 18:06:24 +08:00
commit 0ae3544235
60 changed files with 1253 additions and 272 deletions

3
.gitignore vendored
View File

@ -84,4 +84,5 @@ redis_data/
Dockerfile Dockerfile
dump.rdb dump.rdb
.tags* .tags*
ceshi_user.xlsx ceshi_user.xlsx
public/trace_task_results

View File

@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
def create def create
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
result = Admins::ImportUserService.call(params[:file].to_io) result = Admins::ImportUserFromExcelService.call(params[:file].to_io)
render_ok(result) render_ok(result)
rescue Admins::ImportUserService::Error => ex rescue Admins::ImportUserService::Error => ex
render_error(ex) render_error(ex)

View File

@ -9,6 +9,10 @@ class CompareController < ApplicationController
load_compare_params load_compare_params
compare compare
@merge_status, @merge_message = get_merge_message @merge_status, @merge_message = get_merge_message
@page_size = page_size <= 0 ? 1 : page_size
@page_limit = page_limit <=0 ? 15 : page_limit
@page_offset = (@page_size -1) * @page_limit
Rails.logger.info("+========#{@page_size}-#{@page_limit}-#{@page_offset}")
end end
private private
@ -53,4 +57,12 @@ class CompareController < ApplicationController
def gitea_compare(base, head) def gitea_compare(base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token) Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token)
end end
def page_size
params.fetch(:page, 1).to_i
end
def page_limit
params.fetch(:limit, 15).to_i
end
end end

View File

@ -109,7 +109,7 @@ class IssuesController < ApplicationController
def create def create
issue_params = issue_send_params(params) issue_params = issue_send_params(params)
Issues::CreateForm.new({subject:issue_params[:subject]}).validate! Issues::CreateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
@issue = Issue.new(issue_params) @issue = Issue.new(issue_params)
if @issue.save! if @issue.save!
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
@ -223,7 +223,7 @@ class IssuesController < ApplicationController
normal_status(-1, "不允许修改为关闭状态") normal_status(-1, "不允许修改为关闭状态")
else else
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
Issues::UpdateForm.new({subject:issue_params[:subject]}).validate! Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
if @issue.update_attributes(issue_params) if @issue.update_attributes(issue_params)
if @issue&.pull_request.present? if @issue&.pull_request.present?
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?

View File

@ -23,6 +23,7 @@ class JournalsController < ApplicationController
normal_status(-1, "评论内容不能为空") normal_status(-1, "评论内容不能为空")
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Journals::CreateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
journal_params = { journal_params = {
journalized_id: @issue.id , journalized_id: @issue.id ,
journalized_type: "Issue", journalized_type: "Issue",
@ -53,6 +54,9 @@ class JournalsController < ApplicationController
end end
end end
end end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end end
def destroy def destroy
@ -70,7 +74,8 @@ class JournalsController < ApplicationController
def update def update
content = params[:content] content = params[:content]
if content.present? if content.present?
Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
if @journal.update_attribute(:notes, content) if @journal.update_attribute(:notes, content)
normal_status(0, "更新成功") normal_status(0, "更新成功")
else else
@ -79,7 +84,9 @@ class JournalsController < ApplicationController
else else
normal_status(-1, "评论的内容不能为空") normal_status(-1, "评论的内容不能为空")
end end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end end
def get_children_journals def get_children_journals

View File

@ -12,7 +12,7 @@ class OwnersController < ApplicationController
def show def show
@owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id]) @owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id])
return render_ok(type: 'User') unless @owner.present? return render_not_found unless @owner.present?
# 组织 # 组织
if @owner.is_a?(Organization) if @owner.is_a?(Organization)
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition

View File

@ -13,6 +13,8 @@ class ProjectsController < ApplicationController
def menu_list def menu_list
menu = [] menu = []
user_is_admin = current_user.admin? || @project.manager?(current_user)
menu.append(menu_hash_by_name("home")) menu.append(menu_hash_by_name("home"))
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code") menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code")
menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues") menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues")
@ -20,9 +22,11 @@ class ProjectsController < ApplicationController
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge? menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge?
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions") menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge? menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && (current_user.admin? || @project.member?(current_user.id))
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge? menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge?
menu.append(menu_hash_by_name("activity")) menu.append(menu_hash_by_name("activity"))
menu.append(menu_hash_by_name("settings")) if (current_user.admin? || @project.manager?(current_user)) && @project.forge? menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge?
menu.append(menu_hash_by_name("quit")) if !user_is_admin && @project.member(current_user.id) && @project.forge?
render json: menu render json: menu
end end
@ -88,7 +92,7 @@ class ProjectsController < ApplicationController
return @branches = [] unless @project.forge? return @branches = [] unless @project.forge?
# result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier) # result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier) result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier, params[:name])
@branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result["branch_name"]) : result @branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result["branch_name"]) : result
end end
@ -177,6 +181,22 @@ class ProjectsController < ApplicationController
tip_exception(e.message) tip_exception(e.message)
end end
def quit
user_is_admin = current_user.admin? || @project.manager?(current_user)
if !user_is_admin && @project.member(current_user.id) && @project.forge?
ActiveRecord::Base.transaction do
Projects::DeleteMemberInteractor.call(@project.owner, @project, current_user)
SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, current_user.id, @project.id) if Site.has_notice_menu?
render_ok
end
else
render_forbidden('你不能退出该仓库')
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def watch_users def watch_users
watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct
@watchers_count = watchers.size @watchers_count = watchers.size
@ -190,7 +210,7 @@ class ProjectsController < ApplicationController
end end
def fork_users def fork_users
fork_users = @project.fork_users.includes(:user, :project, :fork_project).order("fork_users.created_at desc").distinct fork_users = @project.fork_users.includes(:owner, :project, :fork_project).order("fork_users.created_at desc").distinct
@forks_count = fork_users.size @forks_count = fork_users.size
@fork_users = paginate(fork_users) @fork_users = paginate(fork_users)
end end

View File

@ -29,7 +29,7 @@ class PullRequestsController < ApplicationController
end end
def new def new
@all_branches = Branches::ListService.call(@owner, @project) @all_branches = Branches::ListService.call(@owner, @project, params[:branch_name])
@is_fork = @project.forked_from_project_id.present? @is_fork = @project.forked_from_project_id.present?
@projects_names = [{ @projects_names = [{
project_user_login: @owner.try(:login), project_user_login: @owner.try(:login),
@ -50,7 +50,7 @@ class PullRequestsController < ApplicationController
end end
def get_branches def get_branches
branch_result = Branches::ListService.call(@owner, @project) branch_result = Branches::ListService.call(@owner, @project, params[:name])
render json: branch_result render json: branch_result
# return json: branch_result # return json: branch_result
end end
@ -58,6 +58,7 @@ class PullRequestsController < ApplicationController
def create def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user) # return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
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)
if @gitea_pull_request[:status] == :success if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"]) @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
@ -89,7 +90,7 @@ class PullRequestsController < ApplicationController
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
return normal_status(-1, "title不能超过255个字符") if params[:title].length > 255 Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
merge_params merge_params
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank? @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?

View File

@ -225,7 +225,8 @@ class RepositoriesController < ApplicationController
@path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" @path = Gitea.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)
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha") @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content")
rescue rescue
render json: nil render json: nil
end end
@ -387,4 +388,4 @@ class RepositoriesController < ApplicationController
end end
end end
end end

View File

@ -0,0 +1,18 @@
class Traces::BaseController < ApplicationController
helper_method :observed_logged_user?, :observed_user
def observed_user
@_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
end
def observed_logged_user?
observed_user.id == User.current&.id
end
protected
def check_auth
return render_forbidden unless current_user.admin? || observed_logged_user?
end
end

View File

@ -0,0 +1,83 @@
class Traces::ProjectsController < Traces::BaseController
include OperateProjectAbilityAble
before_action :require_login
before_action :load_project
before_action :authorizate_user_can_edit_project!, except: [:task_results]
def tasks
branch_name = params[:branch_name]
return render_error("无可用检测次数") if @project.user_trace_tasks.size >= 5
return render_error("分支名不能为空!") if branch_name.blank?
@all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier)
return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name)
code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name)
if code == 200
UserTraceTask.create!(
user_id: current_user.id,
project_id: @project.id,
branch_tag: branch_name,
task_id: data["task_id"]
)
render_ok
else
render_error("检测失败 Error:#{error}")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def task_results
limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
return render :json => {left_tasks_count: 5, data: []} if current_user.trace_user.nil?
code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit)
if code == 200
render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size, data: data}
else
render_error("获取检测记录失败 Error:#{error}")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def reload_task
return render_error("project_id错误") if params[:project_id].blank?
branch_name = params[:branch_name]
return render_error("分支名不能为空!") if branch_name.blank?
@all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier)
return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name)
code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id])
if code == 200
UserTraceTask.create!(
user_id: current_user.id,
project_id: @project.id,
branch_tag: branch_name,
task_id: data["task_id"]
)
render_ok
else
render_error("重新检测失败 Error:#{error}")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
def task_pdf
return render_error("task_id错误") if params[:task_id].blank?
result = Trace::PdfReportService.call(current_user.trace_token, params[:task_id])
if result.is_a?(Hash) && result[:code] == 200
redirect_to result[:download_url]
else
render_error("下载报告失败!")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
end

View File

@ -0,0 +1,14 @@
class Traces::TraceUsersController < Traces::BaseController
before_action :require_login
def create
if current_user.trace_token.present?
render_ok
else
render_error(-1, "代码溯源用户初始化失败")
end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end
end

View File

@ -98,6 +98,13 @@ class UsersController < ApplicationController
render_error(-1, '头像修改失败!') render_error(-1, '头像修改失败!')
end end
def get_image
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
redirect_to Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(@user).to_s
end
def me def me
@user = current_user @user = current_user
end end
@ -307,6 +314,7 @@ class UsersController < ApplicationController
:occupation, :technical_title, :occupation, :technical_title,
:school_id, :department_id, :province, :city, :school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description, :custom_department, :identity, :student_id, :description,
:show_super_description, :super_description,
:show_email, :show_location, :show_department] :show_email, :show_location, :show_department]
) )
end end
@ -354,4 +362,4 @@ class UsersController < ApplicationController
end end
end end
end end

View File

@ -14,7 +14,7 @@ class VersionReleasesController < ApplicationController
def new def new
#获取所有的分支 #获取所有的分支
@all_branches = [] @all_branches = []
get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @repository.try(:identifier)).call get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @repository.try(:identifier), params[:branch_name]).call
if get_all_branches && get_all_branches.size > 0 if get_all_branches && get_all_branches.size > 0
get_all_branches.each do |b| get_all_branches.each do |b|
@all_branches.push(b["name"]) @all_branches.push(b["name"])

View File

@ -16,6 +16,7 @@ includes:
- users - users
- projects - projects
- repositories - repositories
- traces
- pulls - pulls
- issues - issues
- organizations - organizations

View File

@ -280,7 +280,7 @@ repo |是| |string |项目标识identifier
### 返回字段说明 ### 返回字段说明
参数 | 类型 | 字段说明 参数 | 类型 | 字段说明
--------- | ----------- | ----------- --------- | ----------- | -----------
menu_name |string|导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置 menu_name |string|导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,services:服务,activity:动态,setting:仓库设置
> 返回的JSON示例: > 返回的JSON示例:
@ -408,7 +408,7 @@ await octokit.request('POST /api/yystopf/ceshi/project_units')
### 请求参数 ### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明 参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ---------- --------- | ------- | ------- | -------- | ----------
|unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑 | |unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,resources:资源库,services:服务 |
### 返回字段说明: ### 返回字段说明:

View File

@ -0,0 +1,217 @@
# Traces
## 代码溯源初始化
用户同意协议后请求的接口,创建代码溯源的账号
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/traces/trace_users.json
```
```javascript
await octokit.request('POST /api/traces/trace_users.json')
```
### HTTP 请求
`POST api/traces/trace_users.json`
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 代码分析结果列表
查询项目下代码分析的结果
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/traces/yystopf/many_branch/task_results.json
```
```javascript
await octokit.request('GET /api/traces/:owner/:repo/task_results.json')
```
### HTTP 请求
`GET api/traces/:owner/:repo/task_results.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner|是|否|string | 项目所有者标识|
repo|是 | 否|string | 项目标识 |
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
{
"data": [
{
"accuracy": "20",
"code_type": "C",
"depth": "2",
"detect_flag": "快速-组件级",
"detect_rule": "快速-组件级,2,20,,开源软件,50,10",
"detect_startdate": "2022-05-10 15:59:46 ",
"detect_status": "fail",
"detectflag": "快速-组件级",
"fail_reason": "Invalid package type",
"file_name": "many_branch.zip",
"license_process": "100",
"licenseparam": "开源软件",
"package_type": "",
"product_name": "84727546110",
"project_id": "6dbc3e42-5857-4ca4-a54d-58fd9dbf6dc5",
"sim_process": "100",
"similarity_process": "2",
"task_id": "15139171-091b-4316-98b1-6068970efa44",
"totalsize": 5,
"uid": "78",
"vuln_process": "",
"vulnlevel": ""
}
]
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 新建分析
用户选择仓库分支进行代码分析的接口
> 示例:
```shell
curl -X POST \
http://localhost:3000/api/traces/yystopf/many_branch/tasks.json
```
```javascript
await octokit.request('POST /api/traces/:owner/:repo/tasks.json')
```
### HTTP 请求
`POST api/traces/:owner/:repo/tasks.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是 | 否 | string | 项目所有者标识 |
repo |是 | 否 | string | 项目标识 |
branch_name|是 | 否| string | 分支名称 |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 重新扫描
对代码分析结果进行再次分析
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/traces/yystopf/many_branch/reload_task.json
```
```javascript
await octokit.request('GET /api/traces/:owner/:repo/reload_task.json')
```
### HTTP 请求
`GET api/traces/:owner/:repo/reload_task.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是 | 否 | string | 项目所有者标识 |
repo |是 | 否 | string | 项目标识 |
project_id|是 | 否| string | 代码分析结果里的project_id |
branch_name|是 | 否| string | 分支名称 |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
## 下载报告
把代码分析的结果下载到本地
> 示例:
```shell
curl -X GET \
http://localhost:3000/api/traces/yystopf/many_branch/task_pdf.json
```
```javascript
await octokit.request('GET /api/traces/:owner/:repo/task_pdf.json')
```
### HTTP 请求
`GET api/traces/:owner/:repo/task_pdf.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
owner |是 | 否 | string | 项目所有者标识 |
repo |是 | 否 | string | 项目标识 |
task_id|是 | 否| string | 代码分析结果里的task_id |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>

View File

@ -1,11 +1,11 @@
class Issues::CreateForm class Issues::CreateForm
include ActiveModel::Model include ActiveModel::Model
attr_accessor :subject attr_accessor :subject, :description
validates :subject, presence: { message: "不能为空" } validates :subject, presence: { message: "不能为空" }
validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" } validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
validates :description, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end end

View File

@ -1,10 +1,12 @@
class Issues::UpdateForm class Issues::UpdateForm
include ActiveModel::Model include ActiveModel::Model
attr_accessor :subject attr_accessor :subject, :description
validates :subject, presence: { message: "不能为空" } validates :subject, presence: { message: "不能为空" }
validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" } validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
validates :description, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end end

View File

@ -0,0 +1,7 @@
class Journals::CreateForm
include ActiveModel::Model
attr_accessor :notes
validates :notes, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -0,0 +1,8 @@
class Journals::UpdateForm
include ActiveModel::Model
attr_accessor :notes
validates :notes, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -147,6 +147,15 @@ module ApplicationHelper
end end
end end
def url_to_avatar_with_platform_url(source)
platform_url = Rails.application.config_for(:configuration)['platform_url']
if platform_url
return Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(source).to_s
else
return url_to_avatar(source).to_s
end
end
# 主页banner图 # 主页banner图
def banner_img(source_type) def banner_img(source_type)
if File.exist?(disk_filename(source_type, "banner")) if File.exist?(disk_filename(source_type, "banner"))

View File

@ -1,170 +1,218 @@
module RepositoriesHelper module RepositoriesHelper
def render_permission(user, project) def render_permission(user, project)
return "Admin" if user&.admin? return "Admin" if user&.admin?
project.get_premission(user) project.get_premission(user)
end end
def render_decode64_content(str) def render_decode64_content(str)
return nil if str.blank? return nil if str.blank?
Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace) Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace)
end end
def download_type(str) def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv) default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv)
default_type.include?(str&.downcase) || str.blank? default_type.include?(str&.downcase) || str.blank?
end end
def image_type?(str) def image_type?(str)
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd) default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
default_type.include?(str&.downcase) default_type.include?(str&.downcase)
end end
def is_readme?(type, str) def is_readme?(type, str)
return false if type != 'file' || str.blank? return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"] readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase) readme_types.include?(str.to_s.downcase)
end end
def render_commit_author(author_json) def render_commit_author(author_json)
return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?) return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?)
if author_json["id"].present? if author_json["id"].present?
return find_user_by_gitea_uid author_json['id'] return find_user_by_gitea_uid author_json['id']
end end
if author_json["id"].nil? && (author_json["name"].present? && author_json["email"].present?) if author_json["id"].nil? && (author_json["name"].present? && author_json["email"].present?)
return find_user_by_login_and_mail(author_json['name'], author_json["email"]) return find_user_by_login_and_mail(author_json['name'], author_json["email"])
end end
end end
def render_cache_commit_author(author_json) def render_cache_commit_author(author_json)
Rails.logger.info author_json['Email'] if author_json["name"].present? && author_json["email"].present?
if author_json["name"].present? && author_json["email"].present? return find_user_in_redis_cache(author_json['name'], author_json['email'])
return find_user_in_redis_cache(author_json['name'], author_json['email']) end
end if author_json["Name"].present? && author_json["Email"].present?
if author_json["Name"].present? && author_json["Email"].present? return find_user_in_redis_cache(author_json['Name'], author_json['Email'])
return find_user_in_redis_cache(author_json['Name'], author_json['Email']) end
end end
end
def readme_render_decode64_content(str, owner, repo, ref, path)
def readme_render_decode64_content(str, owner, repo, ref, path) return nil if str.blank?
return nil if str.blank? begin
begin content = Base64.decode64(str).force_encoding('UTF-8')
content = Base64.decode64(str).force_encoding('UTF-8')
c_regex = /\!\[.*?\]\((.*?)\)/
c_regex = /\!\[.*?\]\((.*?)\)/ src_regex = /src=\"(.*?)\"/
src_regex = /src=\"(.*?)\"/ src2_regex = /src='(.*?)'/
src2_regex = /src='(.*?)'/ ss = content.to_s.scan(c_regex)
ss = content.to_s.scan(c_regex) ss_src = content.scan(src_regex)
ss_src = content.scan(src_regex) ss_src2 = content.scan(src2_regex)
ss_src2 = content.scan(src2_regex) total_images = ss + ss_src + ss_src2
total_images = ss + ss_src + ss_src2 if total_images.length > 0
if total_images.length > 0 total_images.each do |s|
total_images.each do |s| begin
begin image_title = /\"(.*?)\"/
image_title = /\"(.*?)\"/ r_content = s[0]
r_content = s[0] remove_title = r_content.to_s.scan(image_title)
remove_title = r_content.to_s.scan(image_title) # if remove_title.length > 0
# if remove_title.length > 0 # r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
# r_content = r_content.gsub(/#{remove_title[0]}/, "").strip # end
# end path_last = r_content
path_last = r_content path_current = ""
path_current = "" # 相对路径处理
# 相对路径处理 if r_content.start_with?("../")
if r_content.start_with?("../") relative_path_length = r_content.split("../").size - 1
relative_path_length = r_content.split("../").size - 1 path_pre = path.split("/").size - 1 - relative_path_length
path_pre = path.split("/").size - 1 - relative_path_length path_pre = 0 if path_pre < 0
path_pre = 0 if path_pre < 0 path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/")
path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/") path_last = r_content.split("../").last
path_last = r_content.split("../").last elsif r_content.start_with?("/") # 根路径处理
elsif r_content.start_with?("/") # 根路径处理 path_last = r_content[1..r_content.size]
path_last = r_content[1..r_content.size] else
else path_current = path
path_current = path end
end # if r_content.include?("?")
# if r_content.include?("?") # new_r_content = r_content + "&raw=true"
# new_r_content = r_content + "&raw=true" # else
# else # new_r_content = r_content + "?raw=true"
# new_r_content = r_content + "?raw=true" # end
# end new_r_content = r_content
new_r_content = r_content
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:") # new_r_content = "#{path}" + new_r_content
# new_r_content = "#{path}" + new_r_content new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join end
end content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"") rescue
rescue next
next end
end end
end end
end
return content
return content rescue
rescue return str
return str end
end end
end
# author hui.he
# unix_time values for example: 1604382982 def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
def render_format_time_with_unix(unix_time) file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
Time.at(unix_time).strftime("%Y-%m-%d %H:%M") return nil if str.blank?
end content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
# date for example: 2020-11-01T19:57:27+08:00 src_regex = /src=\"(.*?)\"/
def render_format_time_with_date(date) ss = content.to_s.scan(s_regex)
date.to_time.strftime("%Y-%m-%d %H:%M") ss_src = content.to_s.scan(src_regex)
end total_sources = ss + ss_src
total_sources.uniq!
def decode64_content(entry, owner, repo, ref, path=nil) total_sources.each do |s|
if is_readme?(entry['type'], entry['name']) begin
# content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] s_content = s[0]
content = entry['content'] # 链接直接跳过不做替换
path = URI.escape(entry['path']).to_s.downcase.gsub("/readme.md","") next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
readme_render_decode64_content(content, owner, repo, ref, path) ext = File.extname(s_content)[1..-1]
else
file_type = File.extname(entry['name'].to_s)[1..-1] if image_type?(ext) || download_type(ext)
if image_type?(file_type) s_content = File.expand_path(s_content, file_path)
return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] : entry['content'] s_content = s_content.split("#{Rails.root}/")[1]
end # content = content.gsub(s[0], "/#{s_content}")
if download_type(file_type) s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
return entry['content'] content = content.gsub(s[0], s_content)
end else
render_decode64_content(entry['content']) path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
end s_content = File.expand_path(s_content, path)
end s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub(s[0], "/#{s_content}")
def base64_to_image(path, content) end
# generate to https://git.trusite.net/pawm36ozq/-/raw/branch/master/entrn.png" rescue
content = Base64.decode64(content) next
File.open(path, 'wb') { |f| f.write(content) } end
end end
def render_download_image_url(dir_path, file_path, content) return content
full_path = file_path.starts_with?("/") ? [dir_path, file_path].join("") : [dir_path, file_path].join("/") rescue
file_name = full_path.split("/")[-1] return str
# 用户名/项目标识/文件路径 end
dir_path = generate_dir_path(full_path.split("/"+file_name)[0])
# unix_time values for example: 1604382982
file_path = [dir_path, file_name].join('/') def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
puts "##### render_download_image_url file_path: #{file_path}" end
base64_to_image(file_path, content)
file_path = file_path[6..-1] # date for example: 2020-11-01T19:57:27+08:00
File.join(base_url, file_path) def render_format_time_with_date(date)
end date.to_time.strftime("%Y-%m-%d %H:%M")
end
def generate_dir_path(dir_path)
# tmp_dir_path def readme_decode64_content(entry, owner, repo, ref, path=nil)
# eg: jasder/forgeplus/raw/branch/ref Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
dir_path = ["public", tmp_dir, dir_path].join('/') content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
puts "#### dir_path: #{dir_path}" Rails.logger.info("content===#{content}")
unless Dir.exists?(dir_path) # readme_render_decode64_content(content, owner, repo, ref)
FileUtils.mkdir_p(dir_path) ##不成功这里会抛异常 new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end end
dir_path
end def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
def tmp_dir Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
"repo" content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
end Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
end return Base64.decode64(content).force_encoding('UTF-8')
else
file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type)
return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] : entry['content']
end
if download_type(file_type)
return 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

@ -0,0 +1,15 @@
class Admins::NewImportUserFromExcel < BaseImportXlsx
UserData = Struct.new(:login, :email, :password, :nickname)
def read_each(&block)
sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
data = row.map(&method(:cell_value))[0..3]
block.call UserData.new(*data)
end
end
private
def cell_value(obj)
obj&.cell_value
end
end

View File

@ -1,7 +1,7 @@
module CustomRegexp module CustomRegexp
PHONE = /1\d{10}/ PHONE = /1\d{10}/
EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/ EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ #只含有数字、字母、下划线不能以下划线开头和结尾
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/ LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/ PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/

View File

@ -17,7 +17,7 @@
class ForkUser < ApplicationRecord class ForkUser < ApplicationRecord
belongs_to :project belongs_to :project
belongs_to :user belongs_to :owner, class_name: 'Owner', foreign_key: :user_id
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic

View File

@ -6,7 +6,7 @@
# journalized_id :integer default("0"), not null # journalized_id :integer default("0"), not null
# journalized_type :string(30) default(""), not null # journalized_type :string(30) default(""), not null
# user_id :integer default("0"), not null # user_id :integer default("0"), not null
# notes :text(65535) # notes :text(4294967295)
# created_on :datetime not null # created_on :datetime not null
# private_notes :boolean default("0"), not null # private_notes :boolean default("0"), not null
# parent_id :integer # parent_id :integer

View File

@ -141,6 +141,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
navbar.gsub!('devops', '工作流') navbar.gsub!('devops', '工作流')
navbar.gsub!('versions', '里程碑') navbar.gsub!('versions', '里程碑')
navbar.gsub!('resources', '资源库') navbar.gsub!('resources', '资源库')
navbar.gsub!('services', '服务')
if change_count > 1 if change_count > 1
content.sub!('{ifnavbar}', '<br/>') content.sub!('{ifnavbar}', '<br/>')
else else
@ -290,6 +291,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
navbar.gsub!('devops', '工作流') navbar.gsub!('devops', '工作流')
navbar.gsub!('versions', '里程碑') navbar.gsub!('versions', '里程碑')
navbar.gsub!('resources', '资源库') navbar.gsub!('resources', '资源库')
navbar.gsub!('services', '服务')
if change_count > 1 if change_count > 1
content.sub!('{ifnavbar}', '<br/>') content.sub!('{ifnavbar}', '<br/>')
else else

View File

@ -83,6 +83,10 @@ class Organization < Owner
after_save :reset_cache_data after_save :reset_cache_data
def gitea_token
team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user&.gitea_token
end
def reset_cache_data def reset_cache_data
Cache::V2::OwnerCommonService.new(self.id).reset Cache::V2::OwnerCommonService.new(self.id).reset
end end

View File

@ -124,6 +124,7 @@ class Project < ApplicationRecord
has_many :pinned_projects, dependent: :destroy has_many :pinned_projects, dependent: :destroy
has_many :has_pinned_users, through: :pinned_projects, source: :user has_many :has_pinned_users, through: :pinned_projects, source: :user
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
has_many :user_trace_tasks, dependent: :destroy
after_create :incre_user_statistic, :incre_platform_statistic after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members after_save :check_project_members
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data

View File

@ -16,7 +16,7 @@
class ProjectUnit < ApplicationRecord class ProjectUnit < ApplicationRecord
belongs_to :project belongs_to :project
enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7} enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7, services: 8}
validates :unit_type, uniqueness: { scope: :project_id} validates :unit_type, uniqueness: { scope: :project_id}

View File

@ -3,8 +3,8 @@
# Table name: pull_requests # Table name: pull_requests
# #
# id :integer not null, primary key # id :integer not null, primary key
# pull_request_id :integer # gitea_id :integer
# gpid :integer # gitea_number :integer
# user_id :integer # user_id :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
@ -12,7 +12,7 @@
# project_id :integer # project_id :integer
# title :string(255) # title :string(255)
# milestone :integer # milestone :integer
# body :text(65535) # body :text(4294967295)
# head :string(255) # head :string(255)
# base :string(255) # base :string(255)
# issue_id :integer # issue_id :integer

View File

@ -175,6 +175,7 @@ class User < Owner
has_many :system_notification_histories has_many :system_notification_histories
has_many :system_notifications, through: :system_notification_histories has_many :system_notifications, through: :system_notification_histories
has_one :trace_user, dependent: :destroy has_one :trace_user, dependent: :destroy
has_many :user_trace_tasks, dependent: :destroy
# Groups and active users # Groups and active users
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
@ -188,7 +189,7 @@ class User < Owner
attr_accessor :password, :password_confirmation attr_accessor :password, :password_confirmation
delegate :description, :gender, :department_id, :school_id, :location, :location_city, delegate :description, :gender, :department_id, :school_id, :location, :location_city,
:show_email, :show_location, :show_department, :show_email, :show_location, :show_department, :super_description, :show_super_description,
:technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true
before_save :update_hashed_password, :set_lastname before_save :update_hashed_password, :set_lastname

View File

@ -2,35 +2,34 @@
# #
# Table name: user_extensions # Table name: user_extensions
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer not null
# birthday :date # birthday :date
# brief_introduction :string(255) # brief_introduction :string(255)
# gender :integer # gender :integer
# location :string(255) # location :string(255)
# occupation :string(255) # occupation :string(255)
# work_experience :integer # work_experience :integer
# zip_code :integer # zip_code :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# technical_title :string(255) # technical_title :string(255)
# identity :integer # identity :integer
# student_id :string(255) # student_id :string(255)
# teacher_realname :string(255) # teacher_realname :string(255)
# student_realname :string(255) # student_realname :string(255)
# location_city :string(255) # location_city :string(255)
# school_id :integer # school_id :integer
# description :string(255) default("") # description :string(255) default("")
# department_id :integer # department_id :integer
# honor :text(65535) # province :string(255)
# edu_background :integer # city :string(255)
# edu_entry_year :integer # custom_department :string(255)
# province :string(255) # show_email :boolean default("0")
# city :string(255) # show_location :boolean default("0")
# custom_department :string(255) # show_department :boolean default("0")
# show_email :boolean default("0") # super_description :text(4294967295)
# show_location :boolean default("0") # show_super_description :boolean default("0")
# show_department :boolean default("0")
# #
# Indexes # Indexes
# #

View File

@ -0,0 +1,25 @@
# == Schema Information
#
# Table name: user_trace_tasks
#
# id :integer not null, primary key
# user_id :integer
# project_id :integer
# branch_tag :string(255)
# task_id :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_user_trace_tasks_on_project_id (project_id)
# index_user_trace_tasks_on_user_id (user_id)
#
class UserTraceTask < ApplicationRecord
belongs_to :user
belongs_to :project
end

View File

@ -0,0 +1,71 @@
class Admins::ImportUserFromExcelService < ApplicationService
Error = Class.new(StandardError)
attr_reader :file, :result
def initialize(file)
@file = file
@result = { success: 0, fail: [] }
end
def call
raise Error, '文件不存在' if file.blank?
excel = Admins::NewImportUserFromExcel.new(file)
excel.read_each(&method(:save_user))
result
rescue ApplicationImport::Error => ex
raise Error, ex.message
end
private
def save_user(data)
user = find_user(data)
if user.blank?
create_user(data)
result[:success] +=1
else
fail_data = data.as_json
fail_data[:data] = fail_data.values.join(",")
fail_data[:message] = '用户已存在'
result[:fail] << fail_data
end
rescue Exception => ex
fail_data = data.as_json
fail_data[:data] = fail_data.values.join(",")
fail_data[:message] = ex.message
result[:fail] << fail_data
end
def create_user(data)
ActiveRecord::Base.transaction do
username = data.login&.gsub(/\s+/, "")
email = data.email&.gsub(/\s+/, "")
password = data.password
nickname = data.nickname&.gsub(/\s+/, "")
raise Error, "无法使用以下关键词:#{username},请重新命名" if ReversedKeyword.check_exists?(data.login)
Register::RemoteForm.new({username: username, email: email, password: password, platform: 'forge'}).validate!
user = User.new(admin: false, login: username, mail: email, nickname: nickname, platform: 'forge' , type: "User")
user.password = password
user.activate
raise Error, user.errors.full_messages.join(",") unless user.valid?
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
if interactor.success?
gitea_user = interactor.result
result = Gitea::User::GenerateTokenService.call(username, password)
user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id']
UserExtension.create!(user_id: user.id) if user.save!
else
raise interactor.error, 'gitea user create error'
end
user
end
end
def find_user(data)
User.find_by(login: data.login)
end
end

View File

@ -1,17 +1,18 @@
class Branches::ListService < ApplicationService class Branches::ListService < ApplicationService
attr_reader :user, :project attr_reader :user, :project, :name
def initialize(user, project) def initialize(user, project, name=nil)
@user = user @user = user
@project = project @project = project
@name = name
end end
def call def call
all_branches = [] all_branches = []
user_name = user.try(:show_real_name) user_name = user.try(:show_real_name)
identifier = project.repository.try(:identifier) identifier = project.repository.try(:identifier)
get_all_branches = Gitea::Repository::Branches::ListService.new(user, identifier).call get_all_branches = Gitea::Repository::Branches::ListService.new(user, identifier, name).call
all_branches = branch_lists(user_name,user.try(:login), identifier, get_all_branches) if get_all_branches && get_all_branches.size > 0 all_branches = branch_lists(user_name,user.try(:login), identifier, get_all_branches) if get_all_branches && get_all_branches.size > 0
return all_branches return all_branches
end end

View File

@ -1,9 +1,10 @@
class Gitea::Repository::Branches::ListNameService < Gitea::ClientService class Gitea::Repository::Branches::ListNameService < Gitea::ClientService
attr_reader :user, :repo attr_reader :user, :repo, :name
def initialize(user, repo) def initialize(user, repo, name=nil)
@user = user @user = user
@repo = repo @repo = repo
@name = name
end end
def call def call
@ -13,7 +14,7 @@ class Gitea::Repository::Branches::ListNameService < Gitea::ClientService
private private
def params def params
Hash.new.merge(token: user.gitea_token) Hash.new.merge(token: user.gitea_token, name: name)
end end
def url def url

View File

@ -1,9 +1,10 @@
class Gitea::Repository::Branches::ListService < Gitea::ClientService class Gitea::Repository::Branches::ListService < Gitea::ClientService
attr_reader :user, :repo attr_reader :user, :repo, :name
def initialize(user, repo) def initialize(user, repo, name=nil)
@user = user @user = user
@repo = repo @repo = repo
@name = name
end end
def call def call
@ -13,7 +14,7 @@ class Gitea::Repository::Branches::ListService < Gitea::ClientService
private private
def params def params
Hash.new.merge(token: user.gitea_token) Hash.new.merge(token: user.gitea_token, name: name)
end end
def url def url

View File

@ -47,7 +47,7 @@ class Organizations::CreateService < ApplicationService
end end
def create_org_and_extension def create_org_and_extension
@organization = Organization.build(params[:name], params[:nickname], user.gitea_token) @organization = Organization.build(params[:name], params[:nickname])
org_extension = OrganizationExtension.build(organization.id, description, website, org_extension = OrganizationExtension.build(organization.id, description, website,
location, repo_admin_change_team_access, location, repo_admin_change_team_access,
visibility, max_repo_creation) visibility, max_repo_creation)

View File

@ -157,7 +157,7 @@ class PullRequests::CreateService < ApplicationService
raise "head参数不能为空" if @params[:head].blank? raise "head参数不能为空" if @params[:head].blank?
raise "base参数不能为空" if @params[:base].blank? raise "base参数不能为空" if @params[:base].blank?
raise "fork_project_id参数错误" if is_original && !@project.forked_projects.pluck(:id).include?(@params[:fork_project_id].to_i) raise "fork_project_id参数错误" if is_original && !@project.forked_projects.pluck(:id).include?(@params[:fork_project_id].to_i)
raise "merge_user_login参数错误" if is_original && @project.fork_users.joins(:user).where(users: {login: @params[:merge_user_login]}).blank? raise "merge_user_login参数错误" if is_original && @project.fork_users.joins(:owner).where(users: {login: @params[:merge_user_login]}).blank?
raise "分支内容相同,无需创建合并请求" if @params[:head] === @params[:base] && !is_original raise "分支内容相同,无需创建合并请求" if @params[:head] === @params[:base] && !is_original
raise "合并请求已存在" if @project&.pull_requests.where(head: @params[:head], base: @params[:base], status: 0, is_original: is_original, fork_project_id: @params[:fork_project_id]).present? raise "合并请求已存在" if @project&.pull_requests.where(head: @params[:head], base: @params[:base], status: 0, is_original: is_original, fork_project_id: @params[:fork_project_id]).present?
raise @pull_issue.errors.full_messages.join(", ") unless pull_issue.valid? raise @pull_issue.errors.full_messages.join(", ") unless pull_issue.valid?

View File

@ -1,11 +1,11 @@
# 代码溯源 查询检测结果 # 代码溯源 查询检测结果
class Trace::CheckResultService < Trace::ClientService class Trace::CheckResultService < Trace::ClientService
attr_accessor :token, :project_name, :file_name, :page_num, :page_size attr_accessor :token, :project, :file_name, :page_num, :page_size
def initialize(token, project_name=nil, file_name=nil, page_num=1, page_size=15) def initialize(token, project, file_name=nil, page_num=1, page_size=15)
@token = token @token = token
@project_name = project_name @project = project
@file_name = file_name @file_name = file_name
@page_num = page_num @page_num = page_num
@page_size = page_size @page_size = page_size
@ -19,7 +19,7 @@ class Trace::CheckResultService < Trace::ClientService
private private
def request_params def request_params
{ {
product_name: project_name, product_name: Digest::MD5.hexdigest(project&.id.to_s)[0...20],
file_name: file_name, file_name: file_name,
pageNum: page_num, pageNum: page_num,
pageSize: page_size, pageSize: page_size,

View File

@ -11,26 +11,25 @@ class Trace::CheckService < Trace::ClientService
end end
def call def call
result = authed_post(token, url, {data: request_params}) result = http_authed_post(token, url, {data: request_params})
reponse = render_response(result) reponse = render_response(result)
end end
private private
def request_params def request_params
repo = Gitea::Repository::GetService.call(project&.owner&.login, project&.identifier) repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier)
{ {
product_name: project&.name, product_name: Digest::MD5.hexdigest(project&.id.to_s)[0...20],
product_type: project&.category&.name, product_type: project&.project_category&.name || '其他',
code_type: project&.language&.name, code_type: project&.project_language&.name || '其他',
product_desc: project&.description, product_desc: project&.description,
git_url: repo['clone_url'], git_url: repo['clone_url'],
if_branch: if_branch, if_branch: if_branch,
branch_tag: branch_tag branch_tag: branch_tag
} }.compact
end end
def url def url
"/user/check".freeze "/user/check".freeze
end end
end end

View File

@ -12,6 +12,19 @@ class Trace::ClientService < ApplicationService
conn.post(full_url(url), params[:data]) conn.post(full_url(url), params[:data])
end end
def http_authed_post(token, url, params={})
puts "[trace][POST] request params: #{params}"
puts "[trace][POST] request token: #{token}"
url = URI("#{full_url(url)}")
http = Net::HTTP.new(url.host, url.port)
http.read_timeout = 1200
request = Net::HTTP::Post.new(url)
request["Authorization"] = token
form_data = params[:data].stringify_keys.to_a
request.set_form form_data, 'multipart/form-data'
http.request(request)
end
def get(url, params={}) def get(url, params={})
puts "[trace][GET] request params: #{params}" puts "[trace][GET] request params: #{params}"
conn.get do |req| conn.get do |req|
@ -100,11 +113,22 @@ class Trace::ClientService < ApplicationService
end end
def render_response(response) def render_response(response)
status = response.status if response.is_a?(Faraday::Response)
body = JSON.parse(response&.body) status = response.status
body = JSON.parse(response&.body)
log_error(status, body) log_error(status, body)
return [body["code"], body["data"], body["error"]] return [body["code"], body["data"], body["error"]]
end
if response.is_a?(Net::HTTPOK)
status = 200
body = JSON.parse(response&.body)
log_error(status, body)
return [body["code"], body["data"], body["error"]]
end
end end
end end

View File

@ -1,4 +1,7 @@
# 代码溯源 导出pdf # 代码溯源 导出pdf
require 'open-uri'
require 'fileutils'
class Trace::PdfReportService < Trace::ClientService class Trace::PdfReportService < Trace::ClientService
attr_accessor :token, :task_id attr_accessor :token, :task_id
@ -9,15 +12,23 @@ class Trace::PdfReportService < Trace::ClientService
end end
def call def call
result = authed_get(token, url, request_params) content = open("#{domain}#{base_url}#{url}?task_id=#{task_id}", "Authorization" => token)
response = render_response(result) if content.is_a?(Tempfile)
check_file_path
IO.copy_stream(content, "#{save_path}/#{task_id}.pdf")
return {code: 200, download_url: "/trace_task_results/#{task_id}.pdf"}
else
return {code: 404}
end
end end
private private
def request_params def check_file_path
{ FileUtils.mkdir_p save_path
task_id: task_id end
}
def save_path
"public/trace_task_results"
end end
def url def url

View File

@ -45,6 +45,11 @@
<li> <li>
<%= sidebar_item_group('#setting-glcc', 'GLCC配置', icon: 'fire') do %> <%= sidebar_item_group('#setting-glcc', 'GLCC配置', icon: 'fire') do %>
<li><%= sidebar_item(admins_topic_glcc_news_index_path, '新闻稿管理', icon: 'edit', controller: 'admins-topic-glcc_news') %></li> <li><%= sidebar_item(admins_topic_glcc_news_index_path, '新闻稿管理', icon: 'edit', controller: 'admins-topic-glcc_news') %></li>
<li>
<% if EduSetting.get("glcc_apply_informations_admin_url")%>
<%= sidebar_item(EduSetting.get("glcc_apply_informations_admin_url"), '报名列表', icon: 'user', controller: 'root') %>
<% end %>
</li>
<% end %> <% end %>
</li> </li>
<li> <li>

View File

@ -31,7 +31,9 @@
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %> <% end %>
<%= javascript_void_link '导入用户', class: 'btn btn-secondary btn-sm', data: { toggle: 'modal', target: '.admin-import-user-modal'} %> <%= link_to '下载导入模板', "/导入用户模板.xlsx", class: 'btn btn-secondary mr-3' %>
<%= javascript_void_link '导入用户', class: 'btn btn-secondary', data: { toggle: 'modal', target: '.admin-import-user-modal'} %>
</div> </div>

View File

@ -1,7 +1,7 @@
json.commits_count @compare_result['Commits']&.size json.commits_count @compare_result['CommitsCount']
# json.commits @compare_result['Commits'], partial: 'pull_requests/commit', as: :commit # json.commits @compare_result['Commits'], partial: 'pull_requests/commit', as: :commit
json.commits do json.commits do
json.array! @compare_result['Commits'] do |commit| json.array! @compare_result['Commits'][@page_offset...(@page_offset + @page_limit)] do |commit|
json.author do json.author do
json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['Committer']), name: commit['Committer']['Name'] } json.partial! 'repositories/commit_author', locals: { user: render_cache_commit_author(commit['Committer']), name: commit['Committer']['Name'] }
end end

View File

@ -1,7 +1,7 @@
json.count @forks_count json.count @forks_count
json.users do json.users do
json.array! @fork_users.each do |f| json.array! @fork_users.each do |f|
user = f.user.present? ? f.user : Organization.find_by(id: f.user_id) user = f.owner.present? ? f.owner : Organization.find_by(id: f.user_id)
json.id f.fork_project.id json.id f.fork_project.id
json.identifier f.fork_project.identifier json.identifier f.fork_project.identifier
json.name "#{user.try(:show_real_name)}/#{f.fork_project.try(:name)}" json.name "#{user.try(:show_real_name)}/#{f.fork_project.try(:name)}"

View File

@ -9,7 +9,10 @@ if @project.forge?
json.path entry['path'] json.path entry['path']
json.type entry['type'] json.type entry['type']
json.size entry['size'] json.size entry['size']
is_readme = is_readme?(entry['type'], entry['name'])
if is_readme
json.replace_content readme_decode64_content(entry, @owner, @repository, @ref, @path)
end
json.content (direct_download || image_type || is_dir) ? nil : decode64_content(entry, @owner, @repository, @ref, @path) json.content (direct_download || image_type || is_dir) ? nil : decode64_content(entry, @owner, @repository, @ref, @path)
json.target entry['target'] json.target entry['target']
@ -25,7 +28,7 @@ if @project.forge?
json.direct_download direct_download json.direct_download direct_download
json.image_type image_type json.image_type image_type
json.is_readme_file is_readme?(entry['type'], entry['name']) json.is_readme_file is_readme
json.commit do json.commit do
json.partial! 'last_commit', latest_commit: entry['latest_commit'] json.partial! 'last_commit', latest_commit: entry['latest_commit']
end end

View File

@ -22,5 +22,7 @@ json.province @user.province
json.city @user.city json.city @user.city
json.custom_department @user.custom_department json.custom_department @user.custom_department
json.description @user.description json.description @user.description
json.(@user, :show_email, :show_department, :show_location) json.super_description @user.super_description
json.(@user, :show_email, :show_department, :show_location, :show_super_description)
json.message_unread_total @message_unread_total json.message_unread_total @message_unread_total
json.has_trace_user @user.trace_user.present?

View File

@ -13,4 +13,6 @@ json.email @user.show_email ? @user.mail : nil
json.province @user.show_location ? @user.province : nil json.province @user.show_location ? @user.province : nil
json.city @user.show_location ? @user.city : nil json.city @user.show_location ? @user.city : nil
json.custom_department @user.show_department ? @user.custom_department : nil json.custom_department @user.show_department ? @user.custom_department : nil
json.super_description @user.show_super_description ? @user.super_description : nil
json.show_super_description @user.show_super_description
json.description @user.description json.description @user.description

View File

@ -3,5 +3,11 @@
attributes: attributes:
issues/create_form: issues/create_form:
subject: 标题 subject: 标题
description: 描述
issues/update_form: issues/update_form:
subject: 标题 subject: 标题
description: 描述
journals/create_form:
notes: 评论
journals/update_form:
notes: 评论

View File

@ -225,6 +225,7 @@ Rails.application.routes.draw do
get :fan_users get :fan_users
get :hovercard get :hovercard
put :update_image put :update_image
get :get_image
end end
collection do collection do
post :following post :following
@ -426,6 +427,20 @@ Rails.application.routes.draw do
end end
end end
namespace :traces do
resources :trace_users, only: [:create]
scope "/:owner/:repo" do
resource :projects, path: '/', only: [:index] do
member do
post :tasks
get :task_results
get :reload_task
get :task_pdf
end
end
end
end
# Project Area START # Project Area START
scope "/:owner/:repo" do scope "/:owner/:repo" do
scope do scope do
@ -446,6 +461,7 @@ Rails.application.routes.draw do
get :stargazers, to: 'projects#praise_users' get :stargazers, to: 'projects#praise_users'
get :forks, to: 'projects#fork_users' get :forks, to: 'projects#fork_users'
match :about, :via => [:get, :put, :post] match :about, :via => [:get, :put, :post]
post :quit
end end
end end

View File

@ -0,0 +1,6 @@
class AddSuperDescriptionToUserExtensions < ActiveRecord::Migration[5.2]
def change
add_column :user_extensions, :super_description, :text, :limit => 4294967295
add_column :user_extensions, :show_super_description, :boolean, default: false
end
end

View File

@ -0,0 +1,7 @@
class ChangeIssuesDescriptionAndJournalsNotesColumn < ActiveRecord::Migration[5.2]
def change
change_column :issues, :description, :text, :limit => 4294967295
change_column :journals, :notes, :text, :limit => 4294967295
change_column :pull_requests, :body, :text, :limit => 4294967295
end
end

View File

@ -0,0 +1,12 @@
class CreateUserTraceTasks < ActiveRecord::Migration[5.2]
def change
create_table :user_trace_tasks do |t|
t.references :user
t.references :project
t.string :branch_tag
t.string :task_id
t.timestamps
end
end
end

View File

@ -543,6 +543,26 @@
</li> </li>
</ul> </ul>
</li> </li>
<li>
<a href="#traces" class="toc-h1 toc-link" data-title="Traces">Traces</a>
<ul class="toc-list-h2">
<li>
<a href="#ca438fc3ca" class="toc-h2 toc-link" data-title="代码溯源初始化">代码溯源初始化</a>
</li>
<li>
<a href="#bb16c601f1" class="toc-h2 toc-link" data-title="代码分析结果列表">代码分析结果列表</a>
</li>
<li>
<a href="#32497859e0" class="toc-h2 toc-link" data-title="新建分析">新建分析</a>
</li>
<li>
<a href="#7b3a48e274" class="toc-h2 toc-link" data-title="重新扫描">重新扫描</a>
</li>
<li>
<a href="#87775b1430" class="toc-h2 toc-link" data-title="下载报告">下载报告</a>
</li>
</ul>
</li>
<li> <li>
<a href="#pulls" class="toc-h1 toc-link" data-title="Pulls">Pulls</a> <a href="#pulls" class="toc-h1 toc-link" data-title="Pulls">Pulls</a>
<ul class="toc-list-h2"> <ul class="toc-list-h2">
@ -4968,7 +4988,7 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq
<tr> <tr>
<td>menu_name</td> <td>menu_name</td>
<td>string</td> <td>string</td>
<td>导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置</td> <td>导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,services:服务,activity:动态,setting:仓库设置</td>
</tr> </tr>
</tbody></table> </tbody></table>
@ -5131,7 +5151,7 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json
<td></td> <td></td>
<td></td> <td></td>
<td>array</td> <td>array</td>
<td>项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑</td> <td>项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,resources:资源库,services:服务</td>
</tr> </tr>
</tbody></table> </tbody></table>
<h3 id='7447e4874e-2'>返回字段说明:</h3> <h3 id='7447e4874e-2'>返回字段说明:</h3>
@ -9302,6 +9322,289 @@ http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json
<aside class="success"> <aside class="success">
Success Data. Success Data.
</aside> </aside>
<h1 id='traces'>Traces</h1><h2 id='ca438fc3ca'>代码溯源初始化</h2>
<p>用户同意协议后请求的接口,创建代码溯源的账号</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST <span class="se">\</span>
http://localhost:3000/api/traces/trace_users.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">POST /api/traces/trace_users.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http'>HTTP 请求</h3>
<p><code>POST api/traces/trace_users.json</code></p>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
<h2 id='bb16c601f1'>代码分析结果列表</h2>
<p>查询项目下代码分析的结果</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET <span class="se">\</span>
http://localhost:3000/api/traces/yystopf/many_branch/task_results.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">GET /api/traces/:owner/:repo/task_results.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-2'>HTTP 请求</h3>
<p><code>GET api/traces/:owner/:repo/task_results.json</code></p>
<h3 id='1f9ac54b15'>请求参数</h3>
<table><thead>
<tr>
<th>参数</th>
<th>必选</th>
<th>默认</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>owner</td>
<td></td>
<td></td>
<td>string</td>
<td>项目所有者标识</td>
</tr>
<tr>
<td>repo</td>
<td></td>
<td></td>
<td>string</td>
<td>项目标识</td>
</tr>
<tr>
<td>page</td>
<td></td>
<td>1</td>
<td>int</td>
<td>页码</td>
</tr>
<tr>
<td>limit</td>
<td></td>
<td>15</td>
<td>int</td>
<td>每页数量</td>
</tr>
</tbody></table>
<h3 id='90889036d2'>返回字段说明(暂缺)</h3>
<!-- 参数 | 类型 | 字段说明
--------- | ----------- | -----------
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|密钥创建时间| -->
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"data"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"accuracy"</span><span class="p">:</span><span class="w"> </span><span class="s2">"20"</span><span class="p">,</span><span class="w">
</span><span class="nl">"code_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"C"</span><span class="p">,</span><span class="w">
</span><span class="nl">"depth"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2"</span><span class="p">,</span><span class="w">
</span><span class="nl">"detect_flag"</span><span class="p">:</span><span class="w"> </span><span class="s2">"快速-组件级"</span><span class="p">,</span><span class="w">
</span><span class="nl">"detect_rule"</span><span class="p">:</span><span class="w"> </span><span class="s2">"快速-组件级,2,20,,开源软件,50,10"</span><span class="p">,</span><span class="w">
</span><span class="nl">"detect_startdate"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2022-05-10 15:59:46 "</span><span class="p">,</span><span class="w">
</span><span class="nl">"detect_status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fail"</span><span class="p">,</span><span class="w">
</span><span class="nl">"detectflag"</span><span class="p">:</span><span class="w"> </span><span class="s2">"快速-组件级"</span><span class="p">,</span><span class="w">
</span><span class="nl">"fail_reason"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Invalid package type"</span><span class="p">,</span><span class="w">
</span><span class="nl">"file_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"many_branch.zip"</span><span class="p">,</span><span class="w">
</span><span class="nl">"license_process"</span><span class="p">:</span><span class="w"> </span><span class="s2">"100"</span><span class="p">,</span><span class="w">
</span><span class="nl">"licenseparam"</span><span class="p">:</span><span class="w"> </span><span class="s2">"开源软件"</span><span class="p">,</span><span class="w">
</span><span class="nl">"package_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="nl">"product_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"84727546110"</span><span class="p">,</span><span class="w">
</span><span class="nl">"project_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"6dbc3e42-5857-4ca4-a54d-58fd9dbf6dc5"</span><span class="p">,</span><span class="w">
</span><span class="nl">"sim_process"</span><span class="p">:</span><span class="w"> </span><span class="s2">"100"</span><span class="p">,</span><span class="w">
</span><span class="nl">"similarity_process"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2"</span><span class="p">,</span><span class="w">
</span><span class="nl">"task_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"15139171-091b-4316-98b1-6068970efa44"</span><span class="p">,</span><span class="w">
</span><span class="nl">"totalsize"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w">
</span><span class="nl">"uid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"78"</span><span class="p">,</span><span class="w">
</span><span class="nl">"vuln_process"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="nl">"vulnlevel"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
<h2 id='32497859e0'>新建分析</h2>
<p>用户选择仓库分支进行代码分析的接口</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST <span class="se">\</span>
http://localhost:3000/api/traces/yystopf/many_branch/tasks.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">POST /api/traces/:owner/:repo/tasks.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-3'>HTTP 请求</h3>
<p><code>POST api/traces/:owner/:repo/tasks.json</code></p>
<h3 id='1f9ac54b15-2'>请求参数</h3>
<table><thead>
<tr>
<th>参数</th>
<th>必选</th>
<th>默认</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>owner</td>
<td></td>
<td></td>
<td>string</td>
<td>项目所有者标识</td>
</tr>
<tr>
<td>repo</td>
<td></td>
<td></td>
<td>string</td>
<td>项目标识</td>
</tr>
<tr>
<td>branch_name</td>
<td></td>
<td></td>
<td>string</td>
<td>分支名称</td>
</tr>
</tbody></table>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
<h2 id='7b3a48e274'>重新扫描</h2>
<p>对代码分析结果进行再次分析</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET <span class="se">\</span>
http://localhost:3000/api/traces/yystopf/many_branch/reload_task.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">GET /api/traces/:owner/:repo/reload_task.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-4'>HTTP 请求</h3>
<p><code>GET api/traces/:owner/:repo/reload_task.json</code></p>
<h3 id='1f9ac54b15-3'>请求参数</h3>
<table><thead>
<tr>
<th>参数</th>
<th>必选</th>
<th>默认</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>owner</td>
<td></td>
<td></td>
<td>string</td>
<td>项目所有者标识</td>
</tr>
<tr>
<td>repo</td>
<td></td>
<td></td>
<td>string</td>
<td>项目标识</td>
</tr>
<tr>
<td>project_id</td>
<td></td>
<td></td>
<td>string</td>
<td>代码分析结果里的project_id</td>
</tr>
</tbody></table>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
<h2 id='87775b1430'>下载报告</h2>
<p>把代码分析的结果下载到本地</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET <span class="se">\</span>
http://localhost:3000/api/traces/yystopf/many_branch/task_pdf.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">GET /api/traces/:owner/:repo/task_pdf.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-5'>HTTP 请求</h3>
<p><code>GET api/traces/:owner/:repo/task_pdf.json</code></p>
<h3 id='1f9ac54b15-4'>请求参数</h3>
<table><thead>
<tr>
<th>参数</th>
<th>必选</th>
<th>默认</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>owner</td>
<td></td>
<td></td>
<td>string</td>
<td>项目所有者标识</td>
</tr>
<tr>
<td>repo</td>
<td></td>
<td></td>
<td>string</td>
<td>项目标识</td>
</tr>
<tr>
<td>task_id</td>
<td></td>
<td></td>
<td>string</td>
<td>代码分析结果里的task_id</td>
</tr>
</tbody></table>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>
<aside class="success">
Success — a happy kitten is an authenticated kitten!
</aside>
<h1 id='pulls'>Pulls</h1><h2 id='get-a-pull-request'>Get a pull request</h2> <h1 id='pulls'>Pulls</h1><h2 id='get-a-pull-request'>Get a pull request</h2>
<p>获取合并请求详情接口</p> <p>获取合并请求详情接口</p>

Binary file not shown.

View File

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