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

This commit is contained in:
xiaoxiaoqiong
2022-07-11 15:52:57 +08:00
91 changed files with 5332 additions and 1559 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -170,7 +170,10 @@ class ApplicationController < ActionController::Base
# 未授权的捕捉407弹试用申请弹框
def require_login
#6.13 -hs
if request.headers["Authorization"].present?
tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id) if @doorkeeper_token.present?
end
tip_exception(401, "请登录后再操作") unless User.current.logged?
end
@@ -265,8 +268,11 @@ class ApplicationController < ActionController::Base
User.current = user
end
end
# if !User.current.logged? && Rails.env.development?
# User.current = User.find 1
# user = User.find 1
# User.current = user
# start_user_session(user)
# end
@@ -681,7 +687,7 @@ class ApplicationController < ActionController::Base
@project, @owner = Project.find_with_namespace(namespace, id)
if @project and current_user.can_read_project?(@project)
if @project and (current_user.can_read_project?(@project) || controller_path == "projects/project_invite_links")
logger.info "########### has project and can read project"
@project
# elsif @project && current_user.is_a?(AnonymousUser)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,42 @@
class Projects::ProjectInviteLinksController < Projects::BaseController
before_action :require_manager!, except: [:show_link, :redirect_link]
before_action :require_login
def current_link
role = params[:role]
is_apply = params[:is_apply]
return render_error('请输入正确的参数!') unless role.present? && is_apply.present?
@project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id, role: role, is_apply: is_apply)
@project_invite_link = ProjectInviteLink.build!(@project, current_user, role, is_apply) unless @project_invite_link.present?
end
def generate_link
ActiveRecord::Base.transaction do
params_data = link_params.merge({user_id: current_user.id, project_id: @project.id})
Projects::ProjectInviteLinks::CreateForm.new(params_data).validate!
@project_invite_link = ProjectInviteLink.build!(project, user, params_data[:role], params_data[:is_apply])
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def show_link
@project_invite_link = ProjectInviteLink.find_by(sign: params[:invite_sign])
return render_not_found unless @project_invite_link.present?
end
def redirect_link
Projects::LinkJoinService.call(current_user, @project, params[:invite_sign])
render_ok
rescue Exception => e
uid_logger_error(e.message)
normal_status(-1, e.message)
end
private
def link_params
params.require(:project_invite_link).permit(:role, :is_apply)
end
end

View File

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

View File

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

View File

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

View File

@@ -100,7 +100,7 @@ class UsersController < ApplicationController
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)
# 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

View File

@@ -1,13 +1,13 @@
---
title: Trustie API Reference
title: GitLink API Reference
language_tabs: # must be one of https://git.io/vQNgJ
- shell: Shell
- javascript: JavaScript
toc_footers:
- <a href='https://www.trustie.net/login?login=false'>Sign Up for a User</a>
- <a href='https://www.trustie.net'>Powered by Trustie</a>
- <a href='https://www.gitlink.org.cn/login'>Sign In for a User</a>
- <a href='https://www.gitlink.org.cn'>Powered by GitLink</a>
includes:
- licenses
@@ -31,8 +31,8 @@ code_clipboard: true
# Introduction
Welcome to the Trustie API! You can use our API to access Trustie API endpoints, which can get information on projects, repository, and users in our platform.
Welcome to the GitLink API! You can use our API to access GitLink API endpoints, which can get information on projects, repository, and users in our platform.
We have language bindings in Shell,avaScript! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
This example API documentation page was created with [Trustie](https://www.trustie.net). Feel free to edit it and use it as a base for your own API's documentation.
This example API documentation page was created with [GitLink](https://www.gitlink.org.cn). Feel free to edit it and use it as a base for your own API's documentation.

View File

@@ -1,4 +1,278 @@
# Projects
## 获取项目邀请链接(项目管理员)
当前登录管理员用户获取项目邀请链接的接口第一次请求会默认生成role类型为developer和is_apply为true的链接
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/current_link.json
```
```javascript
await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_link.json')
```
### HTTP 请求
`GET /api/:owner/:repo/project_invite_links/current_link.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|role |是| |string |项目权限reporter: 报告者, developer: 开发者manager管理员 |
|is_apply |是| |boolean |是否需要审核 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |
> 返回的JSON示例:
```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 生成项目邀请链接(项目管理员)
当前登录管理员用户生成的项目邀请链接可选role和is_apply参数
> 示例:
```shell
curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/generate_link.json
```
```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_link.json')
```
### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/generate_link.json`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|role |是| |string |项目权限reporter: 报告者, developer: 开发者manager管理员 |
|is_apply |是| |boolean |是否需要审核 |
> 请求的JSON示例
```json
{
"role": "developer",
"is_apply": false
}
```
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |
> 返回的JSON示例:
```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 获取邀请链接信息(被邀请用户)
用户请求邀请链接时,通过该接口来获取链接的信息
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
```
```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
```
### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/show_link.json?invite_sign=xxx`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|invite_sign |是| |string |项目邀请链接的标识 |
### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |
> 返回的JSON示例:
```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 接受项目邀请链接(被邀请用户)
当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核
> 示例:
```shell
curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
```
```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
```
### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/redirect_link.json?invite_sign=xxx`
### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|invite_sign |是| |string |项目邀请链接的标识 |
> 返回的JSON示例:
```json
{
"status": 0,
"message": "success"
}
```
## 申请加入项目
申请加入项目

View File

@@ -26,25 +26,84 @@ await octokit.request('GET /api/jasder/jasder_test.json')
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|name |string|项目名称|
|identifier |string|项目标识|
|is_public |boolean|项目是否公开, true:公开false:私有|
|description |string|项目简介|
|repo_id |int|仓库id|
|repo_identifier|string|仓库标识|
|identifier |string|项目标识|
|name |string|项目名称|
|project_id |int |项目ID |
|repo_id |int |仓库ID|
|issues_count |int |疑修数量|
|pull_requests_count |int |合并请求数量|
|project_identifier |string|项目标识|
|praises_count |int |项目点赞数|
|forked_count |int |项目复刻数|
|watchers_count |int |项目关注数|
|versions_count |int |项目里程碑数量|
|version_releases_count |int |项目版本数|
|version_releasesed_count |int |项目已发行项目版本数|
|contributor_users_count |int |项目贡献者数|
|permission |string|用户权限 Admin: 平台管理员, Manager: 项目管理员, Developer: 项目开发者, Reporter: 项目报告者|
|mirror_url |string|项目镜像地址|
|mirror |bool |是否为镜像项目|
|type |int |项目类型 0: 托管项目1: 镜像项目2: 同步镜像项目|
|forked_from_project_id |int |项目复刻来源项目ID|
|fork_info.fork_form_name |string|项目复刻来源项目的名称|
|fork_info.fork_project_user_login|string|项目复刻来源项目拥有者标识|
|fork_info.fork_project_identifier|string|项目复刻来源项目标识|
|fork_info.fork_project_user_name |string|项目复刻来源项目拥有者名称|
|size |string|项目大小|
|ssh_url |string|项目ssh clone地址|
|clone_url |string|项目http clone地址|
|default_branch |string|项目默认分支|
|empty |bool |项目是否为空|
|full_name |string|项目路径|
|private |bool |项目是否为私有项目|
|author.id |int |项目拥有者ID|
|author.login |string|项目拥有者标识|
|author.type |string|项目拥有者类型|
|author.name |string|项目拥有者名称|
|author.image_url |string|项目拥有者头像地址|
> 返回的JSON示例:
```json
{
"name": "ni项目",
"identifier": "mirror_demo",
"is_public": true,
"description": "my first project mirror_demo",
"repo_id": 75073,
"repo_identifier": "mirror_demo"
"identifier": "hahahah",
"name": "hahahah",
"project_id": 469,
"repo_id": 469,
"issues_count": 2,
"pull_requests_count": 3,
"project_identifier": "hahahah",
"praises_count": 0,
"forked_count": 1,
"watchers_count": 0,
"versions_count": 0,
"version_releases_count": 0,
"version_releasesed_count": 0,
"contributor_users_count": 1,
"permission": "Admin",
"mirror_url": null,
"mirror": false,
"type": 0,
"open_devops": false,
"watched": false,
"praised": false,
"status": 1,
"forked_from_project_id": null,
"size": "2.1 MB",
"ssh_url": "virus@127.0.0.1:10081:yystopf/hahahah.git",
"clone_url": "http://127.0.0.1:10081/yystopf/hahahah.git",
"default_branch": "master",
"empty": false,
"full_name": "yystopf/hahahah",
"private": false,
"author": {
"id": 2,
"login": "yystopf",
"type": "User",
"name": "heh",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
```
@@ -75,25 +134,36 @@ await octokit.request('GET /api/jasder/jasder_test/simple.json')
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |id |
|name |string|项目名称|
|identifier |string|项目标识|
|is_public |boolean|项目是否公开, true:公开false:私有|
|description |string|项目简介|
|repo_id |int|仓库id|
|repo_identifier|string|仓库标识|
|id |int |id |
|name |string|项目名称|
|platform |string|项目平台|
|identifier |string|项目标识|
|repo_id |int |仓库id|
|open_devops |bool |是否开启工作流|
|type |int |项目类型 0: 托管项目1: 镜像项目2: 同步镜像项目|
|author.login |string|项目拥有者标识|
|author.type |string|项目拥有者类型|
|author.name |string|项目拥有者名称|
|author.image_url|string|项目拥有者头像地址|
> 返回的JSON示例:
```json
{
"name": "ni项目",
"identifier": "mirror_demo",
"is_public": true,
"description": "my first project mirror_demo",
"repo_id": 75073,
"repo_identifier": "mirror_demo"
"identifier": "hahahah",
"name": "hahahah",
"platform": "forge",
"id": 469,
"repo_id": 469,
"open_devops": false,
"type": 0,
"author": {
"login": "yystopf",
"name": "heh",
"type": "User",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
```
@@ -125,9 +195,13 @@ await octokit.request('GET /api/yystopf/ceshi/detail.json')
--------- | ----------- | -----------
|content |string |仓库简介 |
|website |string |仓库网址 |
|readme |string |readme文件
|lesson_url |string |课程地址 |
|identifier |string |项目标识 |
|invite_code |string |项目邀请码 |
|name |string |项目名称 |
|description |string |项目描述 |
|project_id |int |项目ID |
|repo_id |int |仓库ID|
|issues_count |int |项目issue数量|
|pull_requests_count |int |项目合并请求数量|
|project_identifier |int |项目标识|
@@ -137,7 +211,7 @@ await octokit.request('GET /api/yystopf/ceshi/detail.json')
|versions_count |int |项目里程碑数量|
|version_releases_count |int |项目发行版数量|
|version_releasesed_count |int |项目发行版已发行数量|
|permission |string |项目权限|
|permission |string |项目权限, Admin: 平台管理员Manager: 项目管理员, Developer: 项目开发者, Reporter: 项目报告者|
|mirror_url |string |镜像地址|
|mirror |bool |是否为镜像项目|
|type |int |项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目|
@@ -145,59 +219,49 @@ await octokit.request('GET /api/yystopf/ceshi/detail.json')
|watched |bool |是否关注|
|praised |bool |是否点赞|
|status |int |项目状态|
|forked_from_project_id |int |fork项目id|
|fork_info |object |fork项目信息|
|forked_from_project_id |int |项目复刻来源项目id|
|fork_info.fork_form_name |string |项目复刻来源项目的名称|
|fork_info.fork_project_user_login|string |项目复刻来源项目拥有者标识|
|fork_info.fork_project_identifier|string |项目复刻来源项目标识|
|fork_info.fork_project_user_name |string |项目复刻来源项目拥有者名称|
|size |string |仓库大小|
|ssh_url |string |项目ssh地址|
|clone_url |string |项目克隆地址|
|ssh_url |string |项目ssh克隆地址|
|clone_url |string |项目http克隆地址|
|default_branch |string |仓库默认分支|
|empty |bool |仓库是否为空|
|full_name |string |仓库全称|
|private |bool |仓库是否为私有项目|
|license_name |string |许可证名称|
|release_versions.list.name |string |项目issue数量|
|release_versions.list.tag_name |string |发行版标签名称|
|release_versions.list.created_at |string |发行版创建时间|
|release_versions.total_count |int |发行版数量|
|branches.list.name |string |分支名称|
|branches.total_count |int |分支数量|
|tags.list.name |string |标签名称|
|tags.total_count |int |标签数量|
|contributors.list.contributions|int |贡献数量|
|contributors.list.login |string |贡献者登录名|
|contributors.list.name |string |贡献者用户名称|
|contributors.list.image_url |string |贡献者头像|
|languages |object |项目语言占比|
|author.id |int |项目拥有者ID|
|author.login |string |项目拥有者标识|
|author.type |string |项目拥有者类型|
|author.name |string |项目拥有者名称|
|author.image_url |string |项目拥有者头像地址|
> 返回的JSON示例:
```json
{
"content": "仓库简介",
"website": "仓库网址",
"readme": {
"type": "file",
"encoding": "base64",
"size": 9,
"name": "README.md",
"path": "README.md",
"content": "# ceshi\n\n",
"sha": ""
},
"identifier": "ceshi",
"name": "测试项目",
"project_id": 2,
"repo_id": 2,
"issues_count": 0,
"pull_requests_count": 0,
"project_identifier": "ceshi",
"content": null,
"website": null,
"lesson_url": null,
"identifier": "hahahah",
"invite_code": "8zfKtM",
"name": "hahahah",
"description": null,
"project_id": 469,
"repo_id": 469,
"issues_count": 2,
"pull_requests_count": 2,
"project_identifier": "hahahah",
"praises_count": 0,
"forked_count": 0,
"forked_count": 1,
"watchers_count": 0,
"versions_count": 0,
"version_releases_count": 0,
"version_releasesed_count": 0,
"permission": "Reporter",
"permission": "Admin",
"mirror_url": null,
"mirror": false,
"type": 0,
@@ -205,71 +269,23 @@ await octokit.request('GET /api/yystopf/ceshi/detail.json')
"watched": false,
"praised": false,
"status": 1,
"forked_from_project_id": 1,
"fork_info": {
"fork_form_name": "测试项目",
"fork_project_user_login": "ceshi_org",
"fork_project_identifier": "ceshi",
"fork_project_user_name": "ceshi_org"
},
"size": "25.0 KB",
"ssh_url": "virus@localhost:yystopf/ceshi.git",
"clone_url": "http://localhost:10080/yystopf/ceshi.git",
"forked_from_project_id": null,
"size": "2.1 MB",
"ssh_url": "virus@127.0.0.1:10081:yystopf/hahahah.git",
"clone_url": "http://127.0.0.1:10081/yystopf/hahahah.git",
"default_branch": "master",
"empty": false,
"full_name": "yystopf/ceshi",
"full_name": "yystopf/hahahah",
"private": false,
"license_name": "gnu-javamail-exception",
"release_versions": {
"list": [
{
"id": 2,
"name": "vvvv",
"tag_name": "v1.1",
"created_at": "2019-07-18 10:16"
}
],
"total_count": 1
},
"branches": {
"list": [
{
"name": "master"
}
],
"total_count": 1
},
"tags": {
"list": [
{
"name": "v1.1"
},
{
"name": "v1.0"
}
],
"total_count": 2
},
"contributors": {
"list": [
{
"contributions": 1,
"gid": 2,
"login": "yystopf",
"type": "User",
"name": "yystopf",
"image_url": "avatars/User/b"
}
],
"total_count": 1
},
"languages": {
"HTML": "50.9%",
"Ruby": "25.6%",
"JavaScript": "21.4%",
"CSS": "1.3%",
"CoffeeScript": "0.7%",
"Shell": "0.1%"
"license_name": null,
"branches_count": 1201,
"tags_count": 0,
"author": {
"id": 2,
"login": "yystopf",
"type": "User",
"name": "heh",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
```
@@ -392,6 +408,162 @@ await octokit.request('GET /api/yystopf/csfjkkj/tags.json')
]
```
## 仓库分支列表
仓库分支列表
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/csfjkkj/branches.json
```
```javascript
await octokit.request('GET /api/yystopf/csfjkkj/branches.json')
```
### HTTP 请求
`GET /api/:owner/:repo/branches.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|name |string|分支名称|
|http_url |string|分支http地址|
|zip_url |string|分支zip包下载地址|
|tar_url |string|分支tar包下载地址|
> 返回的JSON示例:
```json
[
{
"name": "master",
"http_url": "http://127.0.0.1:10081/yystopf/hahahah.git",
"zip_url": "http://localhost:3000/api/yystopf/hahahah/archive/master.zip",
"tar_url": "http://localhost:3000/api/yystopf/hahahah/archive/master.tar.gz"
},
{
"name": "touch-10",
"http_url": "http://127.0.0.1:10081/yystopf/hahahah.git",
"zip_url": "http://localhost:3000/api/yystopf/hahahah/archive/touch-10.zip",
"tar_url": "http://localhost:3000/api/yystopf/hahahah/archive/touch-10.tar.gz"
},
{
"name": "touch-100",
"http_url": "http://127.0.0.1:10081/yystopf/hahahah.git",
"zip_url": "http://localhost:3000/api/yystopf/hahahah/archive/touch-100.zip",
"tar_url": "http://localhost:3000/api/yystopf/hahahah/archive/touch-100.tar.gz"
}
]
```
## 仓库贡献者列表
仓库贡献者列表
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/csfjkkj/contributors.json
```
```javascript
await octokit.request('GET /api/yystopf/csfjkkj/contributors.json')
```
### HTTP 请求
`GET /api/:owner/:repo/contributors.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|list.contributions |int |贡献者commit数量|
|list.login |string|贡献者标识|
|list.type |string|贡献者类型|
|list.name |string|贡献者昵称|
|list.image_url |string|贡献者头像地址|
> 返回的JSON示例:
```json
{
"list": [
{
"contributions": 2411,
"login": "yystopf",
"type": "User",
"name": "heh",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
{
"contributions": 6,
"login": "testforge3",
"type": null,
"name": "testforge3",
"image_url": "system/lets/letter_avatars/2/T/132_143_60/120.png"
}
],
"total_count": 2
}
```
## 仓库开发语言
仓库开发语言组成
> 示例:
```shell
curl -X GET http://localhost:3000/api/yystopf/csfjkkj/languages.json
```
```javascript
await octokit.request('GET /api/yystopf/csfjkkj/languages.json')
```
### HTTP 请求
`GET /api/:owner/:repo/languages.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|owner |是| |string |用户登录名 |
|repo |是| |string |项目标识identifier |
### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|key |string |语言类型|
|value |string |语言占比|
> 返回的JSON示例:
```json
{
"Go": "99.0%",
"Shell": "0.4%",
"Smarty": "0.4%",
"Makefile": "0.2%"
}
```
## 编辑仓库信息
编辑仓库信息
@@ -1115,15 +1287,15 @@ await octokit.request('GET /api/yystopf/csfjkkj/contributors.json')
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
await octokit.request('GET /api/v1/yystopf/ceshi/webhooks.json')
```
### HTTP 请求
`GET /api/:owner/:repo/webhooks.json`
`GET /api/v1/:owner/:repo/webhooks.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
@@ -1139,7 +1311,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
|url |string|地址|
|http_method |string|请求方式|
|is_active |bool |是否激活|
|type |string|类型|
|last_status |string|最后一次推送的状态|
|create_time |string|创建时间|
@@ -1155,7 +1326,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"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"
},
@@ -1164,7 +1334,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "http://localhost:3000",
"http_method": "GET",
"is_active": true,
"type": "gitea",
"last_status": "succeed",
"create_time": "2021-07-26 10:03:45"
},
@@ -1173,7 +1342,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "http://localhost:10081",
"http_method": "POST",
"is_active": true,
"type": "gitea",
"last_status": "waiting",
"create_time": "2021-07-26 16:56:53"
},
@@ -1182,7 +1350,6 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
"url": "http://localhost:3001",
"http_method": "POST",
"is_active": true,
"type": "gitea",
"last_status": "fail",
"create_time": "2021-07-26 16:58:23"
}
@@ -1200,15 +1367,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks.json')
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/edit.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks/3.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
await octokit.request('GET /api/v1/yystopf/ceshi/webhooks/3.json')
```
### HTTP 请求
`GET /api/:owner/:repo/webhooks/:id/edit.json`
`GET /api/v1/:owner/:repo/webhooks/:id.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
@@ -1226,36 +1393,21 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
|content_type |string|POST Content Type|
|http_method |string|请求方式|
|secret| |string|密钥|
|is_active |bool |是否激活|
|type |string|类型|
|last_status |string|最后一次推送的状态, waiting 等待,fail 失败,succeed 成功|
|active |bool |是否激活|
|branch_filter |string|分支过滤|
|events |string|触发条件|
|create_time |string|创建时间|
|create_at |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示例:
@@ -1266,31 +1418,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
"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",
"active": true,
"create_at": "2021-07-26 10:03",
"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"
]
}
```
@@ -1305,15 +1441,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json')
```shell
curl -X POST \
http://localhost:3000/api/yystopf/ceshi/webhooks.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks.json
```
```javascript
await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
await octokit.request('POST /api/v1/yystopf/ceshi/webhooks.json')
```
### HTTP 请求
`POST /api/:owner/:repo/webhooks.json`
`POST /api/v1/:owner/:repo/webhooks.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
@@ -1321,7 +1457,6 @@ await octokit.request('POST /api/yystopf/ceshi/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 |密钥文本|
@@ -1335,24 +1470,11 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
--------- | ------- | ------- |
|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示例:
@@ -1385,15 +1507,22 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
```json
{
"id": 18,
"type": "gitea",
"id": 68,
"content_type": "json",
"url": "http://localhost:10000",
"http_method": "GET",
"url": "http://127.0.0.1:3000",
"events": [
"push"
"create",
"delete",
"push",
"pull_request",
"pull_request_assign",
"pull_request_review_approved",
"pull_request_review_rejected"
],
"active": true,
"create_time": "2021-07-26 18:53:43"
"branch_filter": "*",
"created_at": "2022-06-23 15:52"
}
```
<aside class="success">
@@ -1407,15 +1536,15 @@ await octokit.request('POST /api/yystopf/ceshi/webhooks.json')
```shell
curl -X PATCH \
http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks/7.json
```
```javascript
await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
await octokit.request('PATCH /api/v1/yystopf/ceshi/webhooks/7.json')
```
### HTTP 请求
`PATCH /api/:owner/:repo/webhooks/:id.json`
`PATCH /api/v1/:owner/:repo/webhooks/68.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
@@ -1424,7 +1553,6 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
|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 |密钥文本|
@@ -1438,24 +1566,11 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
--------- | ------- | ------- |
|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示例:
@@ -1478,8 +1593,22 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
```json
{
"status": 0,
"message": "success"
"id": 68,
"content_type": "json",
"http_method": "GET",
"url": "http://127.0.0.1:3000",
"events": [
"create",
"delete",
"push",
"pull_request",
"pull_request_assign",
"pull_request_review_approved",
"pull_request_review_rejected"
],
"active": true,
"branch_filter": "*",
"created_at": "2022-06-23 15:52"
}
```
<aside class="success">
@@ -1494,15 +1623,15 @@ await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json')
```shell
curl -X DELETE \
http://localhost:3000/api/yystopf/ceshi/webhooks/7.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks/7.json
```
```javascript
await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json')
await octokit.request('DELETE /api/v1/yystopf/ceshi/webhooks/7.json')
```
### HTTP 请求
`DELETE /api/:owner/:repo/webhooks/:id.json`
`DELETE /api/v1/:owner/:repo/webhooks/:id.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
@@ -1532,15 +1661,15 @@ await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json')
```shell
curl -X GET \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/tasks.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks/3/hooktasks.json
```
```javascript
await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
await octokit.request('GET /api/v1/yystopf/ceshi/webhooks/3/hooktasks.json')
```
### HTTP 请求
`GET /api/:owner/:repo/webhooks/:id/tasks.json`
`GET /api/v1/:owner/:repo/webhooks/:id/hooktasks.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明
@@ -1568,7 +1697,7 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
```json
{
"total_count": 6,
"tasks": [
"hooktasks": [
{
"id": 20,
"type": "gitea",
@@ -1744,15 +1873,15 @@ await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json')
```shell
curl -X POST \
http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json
http://localhost:3000/api/v1/yystopf/ceshi/webhooks/3/tests.json
```
```javascript
await octokit.request('POST /api/yystopf/ceshi/webhooks/3/test.json')
await octokit.request('POST /api/v1/yystopf/ceshi/webhooks/3/tests.json')
```
### HTTP 请求
`POST /api/:owner/:repo/webhooks/:id/test.json`
`POST /api/v1/:owner/:repo/webhooks/:id/tests.json`
### 请求参数:
参数 | 必选 | 默认 | 类型 | 字段说明

View File

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

View File

@@ -0,0 +1,8 @@
class Projects::ProjectInviteLinks::CreateForm < BaseForm
attr_accessor :user_id, :project_id, :role, :is_apply
validates :user_id, :project_id, :role, presence: true
validates :role, inclusion: { in: %w(manager developer reporter), message: "请输入正确的权限." }
validates :is_apply, inclusion: {in: [true, false], message: "请输入是否需要管理员审核."}
end

View File

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

View File

@@ -1,218 +1,217 @@
module RepositoriesHelper
def render_permission(user, project)
return "Admin" if user&.admin?
project.get_premission(user)
end
def render_decode64_content(str)
return nil if str.blank?
Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace)
end
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.include?(str&.downcase) || str.blank?
end
def image_type?(str)
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
default_type.include?(str&.downcase)
end
def is_readme?(type, str)
return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX
end
def render_commit_author(author_json)
return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?)
if author_json["id"].present?
return find_user_by_gitea_uid author_json['id']
end
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"])
end
end
def render_cache_commit_author(author_json)
if author_json["name"].present? && author_json["email"].present?
return find_user_in_redis_cache(author_json['name'], author_json['email'])
end
if author_json["Name"].present? && author_json["Email"].present?
return find_user_in_redis_cache(author_json['Name'], author_json['Email'])
end
end
def readme_render_decode64_content(str, owner, repo, ref, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')
c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
src2_regex = /src='(.*?)'/
ss = content.to_s.scan(c_regex)
ss_src = content.scan(src_regex)
ss_src2 = content.scan(src2_regex)
total_images = ss + ss_src + ss_src2
if total_images.length > 0
total_images.each do |s|
begin
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
# if remove_title.length > 0
# r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
# end
path_last = r_content
path_current = ""
# 相对路径处理
if r_content.start_with?("../")
relative_path_length = r_content.split("../").size - 1
path_pre = path.split("/").size - 1 - relative_path_length
path_pre = 0 if path_pre < 0
path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/")
path_last = r_content.split("../").last
elsif r_content.start_with?("/") # 根路径处理
path_last = r_content[1..r_content.size]
else
path_current = path
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
# 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
end
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
rescue
next
end
end
end
return content
rescue
return str
end
end
# author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank?
content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(s_regex)
ss_src = content.to_s.scan(src_regex)
total_sources = ss + ss_src
total_sources.uniq!
total_sources.each do |s|
begin
s_content = s[0]
# 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1]
if image_type?(ext) || download_type(ext)
s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}")
s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
content = content.gsub(s[0], s_content)
else
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub(s[0], "/#{s_content}")
end
rescue
next
end
end
return content
rescue
return str
end
# unix_time values for example: 1604382982
def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
end
# date for example: 2020-11-01T19:57:27+08:00
def render_format_time_with_date(date)
date.to_time.strftime("%Y-%m-%d %H:%M")
end
def readme_decode64_content(entry, owner, repo, ref, path=nil)
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end
def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
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
module RepositoriesHelper
def render_permission(user, project)
return "Admin" if user&.admin?
project.get_premission(user)
end
def render_decode64_content(str)
return nil if str.blank?
Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace)
end
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.include?(str&.downcase) || str.blank?
end
def image_type?(str)
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
default_type.include?(str&.downcase)
end
def is_readme?(type, str)
return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX
end
def render_commit_author(author_json)
return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?)
if author_json["id"].present?
return find_user_by_gitea_uid author_json['id']
end
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"])
end
end
def render_cache_commit_author(author_json)
if author_json["name"].present? && author_json["email"].present?
return find_user_in_redis_cache(author_json['name'], author_json['email'])
end
if author_json["Name"].present? && author_json["Email"].present?
return find_user_in_redis_cache(author_json['Name'], author_json['Email'])
end
end
def readme_render_decode64_content(str, owner, repo, ref, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')
c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
src2_regex = /src='(.*?)'/
ss = content.to_s.scan(c_regex)
ss_src = content.scan(src_regex)
ss_src2 = content.scan(src2_regex)
total_images = ss + ss_src + ss_src2
if total_images.length > 0
total_images.each do |s|
begin
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
# if remove_title.length > 0
# r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
# end
path_last = r_content
path_current = ""
# 相对路径处理
if r_content.start_with?("../")
relative_path_length = r_content.split("../").size - 1
path_pre = path.split("/").size - 1 - relative_path_length
path_pre = 0 if path_pre < 0
path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/")
path_last = r_content.split("../").last
elsif r_content.start_with?("/") # 根路径处理
path_last = r_content[1..r_content.size]
else
path_current = path
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
# 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
end
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
rescue
next
end
end
end
return content
rescue
return str
end
end
# author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank?
content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(s_regex)
ss_src = content.to_s.scan(src_regex)
total_sources = ss + ss_src
total_sources.uniq!
total_sources.each do |s|
begin
s_content = s[0]
# 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1]
if (image_type?(ext) || download_type(ext)) && !ext.blank?
s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}")
s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
content = content.gsub(s[0], s_content)
else
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub('('+s[0]+')', '('+"/#{s_content}"+')')
end
rescue
next
end
end
return content
rescue
return str
end
# unix_time values for example: 1604382982
def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
end
# date for example: 2020-11-01T19:57:27+08:00
def render_format_time_with_date(date)
date.to_time.strftime("%Y-%m-%d %H:%M")
end
def readme_decode64_content(entry, owner, repo, ref, path=nil)
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
# Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end
def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
# Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
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

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

View File

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

View File

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

View File

@@ -2,24 +2,27 @@
#
# Table name: forge_applied_projects
#
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# role :integer default("0")
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# role :integer default("0")
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# project_invite_link_id :integer
#
# Indexes
#
# index_forge_applied_projects_on_project_id (project_id)
# index_forge_applied_projects_on_user_id (user_id)
# index_forge_applied_projects_on_project_id (project_id)
# index_forge_applied_projects_on_project_invite_link_id (project_invite_link_id)
# index_forge_applied_projects_on_user_id (user_id)
#
class AppliedProject < ApplicationRecord
self.table_name = "forge_applied_projects"
belongs_to :user
belongs_to :project
belongs_to :project_invite_link, optional: true
has_many :applied_messages, as: :applied, dependent: :destroy
# has_many :forge_activities, as: :forge_act, dependent: :destroy

View File

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

View File

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

View File

@@ -61,6 +61,7 @@ class MessageTemplate::CustomTip < MessageTemplate
end
title.gsub!('{platform}', PLATFORM)
content.gsub!('{platform}', PLATFORM)
content.gsub!('{baseurl}', base_url)
return title, content
rescue => e

View File

@@ -125,6 +125,7 @@ class Project < ApplicationRecord
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 :user_trace_tasks, dependent: :destroy
has_many :project_invite_links, dependent: :destroy
after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
@@ -138,7 +139,7 @@ class Project < ApplicationRecord
delegate :content, to: :project_detail, allow_nil: true
delegate :name, to: :license, prefix: true, allow_nil: true
validate :validate_sensitive_string
validate :validate_sensitive_string, on: [:create, :update]
def self.all_visible(user_id=nil)
user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql
@@ -184,7 +185,7 @@ class Project < ApplicationRecord
forked_project = self.forked_from_project
if forked_project.present?
forked_project.decrement(:forked_count, 1)
forked_project.save
forked_project.update_column(:forked_count, forked_project.forked_count)
end
end

View File

@@ -0,0 +1,59 @@
# == Schema Information
#
# Table name: project_invite_links
#
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# role :integer default("4")
# is_apply :boolean default("1")
# sign :string(255)
# expired_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_project_invite_links_on_project_id (project_id)
# index_project_invite_links_on_sign (sign)
# index_project_invite_links_on_user_id (user_id)
#
class ProjectInviteLink < ApplicationRecord
default_scope { where("expired_at > ?", Time.now).or(where(expired_at: nil)) }
belongs_to :project
belongs_to :user
has_many :applied_projects
scope :with_project_id, -> (project_id) {where(project_id: project_id)}
scope :with_user_id, -> (user_id) {where(user_id: user_id)}
enum role: {manager: 3, developer: 4, reporter: 5}
before_create :set_old_data_expired_at
def self.random_hex_sign
hex = (SecureRandom.hex(32))
return hex unless ProjectInviteLink.where(sign: hex).exists?
end
def self.build!(project, user, role="developer", is_apply=true)
self.create!(
project_id: project&.id,
user_id: user&.id,
role: role,
is_apply: is_apply,
sign: random_hex_sign,
expired_at: Time.now + 3.days
)
end
private
def set_old_data_expired_at
ProjectInviteLink.where(user_id: self.user_id, project_id: self.project, role: self.role, is_apply: self.is_apply).update_all(expired_at: Time.now)
end
end

View File

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

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

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

View File

@@ -181,7 +181,7 @@ class User < Owner
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
scope :like, lambda { |keywords|
sql = "CONCAT(lastname, firstname) LIKE :search OR nickname LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search"
where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
where(sql, :search => "%#{keywords.strip}%") unless keywords.blank?
}
scope :simple_select, -> {select(:id, :login, :lastname,:firstname, :nickname, :gitea_uid, :type)}
@@ -567,7 +567,8 @@ class User < Owner
return '游客' unless logged?
name = lastname + firstname
name = name.blank? ? (nickname.blank? ? login : nickname) : name
name.gsub(/\s+/, '').strip #6.11 -hs
# name.gsub(/\s+/, '').strip #6.11 -hs
name.strip
end
def only_real_name
@@ -684,6 +685,21 @@ class User < Owner
raise text
end
def self.authenticate!(login, password)
user = self.where("login = ? or mail = ? or phone = ? ", login.to_s.gsub(" ",''),login.to_s.gsub(" ",''),login.downcase.to_s.gsub(" ",'')).limit(1).first
return (user.check_password?(password) ? user : nil) unless user.nil?
nil
end
# Generate public/private keys
def generate_keys
key_size = (Rails.env == 'test' ? 512 : 2048)
serialized_private_key = OpenSSL::PKey::RSA::generate(key_size).to_s
serialized_public_key = OpenSSL::PKey::RSA.new(serialized_private_key)
[serialized_private_key, serialized_public_key]
end
def show_real_name
name = lastname + firstname
if name.blank?

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,86 @@
class Projects::LinkJoinService < ApplicationService
Error = Class.new(StandardError)
attr_reader :user, :project, :invite_sign, :params
def initialize(user, project, invite_sign, params={})
@user = user
@project = project
@invite_sign = invite_sign
@params = params
end
def call
ActiveRecord::Base.transaction do
validate!
if invite_link.is_apply
# 如果需要申请才能加入,创建一条申请记录
create_applied_project!
else
# 如果不需要申请,直接为项目添加该成员
create_member!
end
end
end
private
def validate!
raise Error, 'invite_sign必须存在!' if invite_sign.blank?
raise Error, '邀请链接不存在!' unless invite_link.present?
raise Error, '邀请链接已失效!' unless invite_user_in_project
raise Error, '您已是仓库成员' if project.member?(user.id)
raise Error, '您的申请管理员正在审核中,请勿重复申请!' if user.applied_projects.exists?(applied_project_params)
end
def applied_project_params
{
status: 'common',
project: project,
role: role_value,
project_invite_link_id: invite_link&.id
}
end
def create_applied_project!
user.applied_projects.find_or_create_by!(status: 'common', project: project, role: role_value, project_invite_link_id: invite_link&.id)
end
def create_member!
Projects::AddMemberInteractor.call(project.owner, project, user, permission)
end
def invite_link
ProjectInviteLink.find_by(project_id: project.id, sign: invite_sign)
end
def invite_user_in_project
in_project = project.member?(invite_link.user)
invite_link.update_column(:expired_at, Time.now) unless in_project
in_project
end
def role_value
@_role ||=
case invite_link&.role
when 'manager' then 3
when 'developer' then 4
when 'reporter' then 5
else
5
end
end
def permission
case invite_link&.role
when 'manager'
'admin'
when 'developer'
'write'
when 'reporter'
'read'
else
'read'
end
end
end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
json.id project.id
json.identifier project.identifier
json.name project.name
json.description project.description
json.is_public project.is_public
json.owner do
json.partial! "/users/user_simple", locals: {user: project.owner}
end

View File

@@ -0,0 +1,12 @@
json.(project_invite_link, :id, :role, :is_apply, :sign)
json.expired_at format_time(project_invite_link&.expired_at)
json.user do
json.partial! "/users/user_simple", locals: {user: project_invite_link.user}
end
if project_invite_link&.project.present?
json.project do
json.partial! "/projects/detail", locals: {project: project_invite_link.project}
end
else
json.project nil
end

View File

@@ -0,0 +1 @@
json.partial! 'detail', locals: { project_invite_link: @project_invite_link }

View File

@@ -0,0 +1 @@
json.partial! 'detail', locals: { project_invite_link: @project_invite_link }

View File

@@ -0,0 +1 @@
json.partial! 'detail', locals: { project_invite_link: @project_invite_link }

View File

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

View File

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