FIX Merge master branch

This commit is contained in:
Jasder 2020-12-25 15:10:50 +08:00
commit 837aa1ea9e
416 changed files with 13468 additions and 9548 deletions

22
.trustie-pipeline.yml Normal file
View File

@ -0,0 +1,22 @@
kind: pipeline
name: default
platform:
os: linux
arch: arm64
steps:
- name: install
image: ruby:2.4.5
commands:
- gem install bundler
- bundle -v
- bundle install --jobs=1 --retry=1
- name: test
image: ruby:2.4.5
volumes:
- name: bundle
path: /usr/local/bundle
commands:
- rake

View File

@ -1,8 +1,6 @@
source 'https://gems.ruby-china.com'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.3.7'
gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'puma', '~> 3.11'
@ -19,8 +17,6 @@ gem 'kaminari', '~> 1.1', '>= 1.1.1'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'gitlab', path: 'lib/gitlab-cli'
gem 'chinese_pinyin'
gem 'rack-cors'
@ -74,6 +70,7 @@ group :development do
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem "annotate", "~> 2.6.0"
end
group :test do

View File

@ -1,10 +1,3 @@
PATH
remote: lib/gitlab-cli
specs:
gitlab (3.2.0)
httparty
terminal-table
GEM
remote: https://gems.ruby-china.com/
specs:
@ -61,6 +54,9 @@ GEM
public_suffix (>= 2.0.2, < 5.0)
ancestry (3.0.7)
activerecord (>= 3.2.0)
annotate (2.6.5)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
archive-zip (0.12.0)
io-like (~> 0.3.0)
arel (9.0.0)
@ -138,9 +134,6 @@ GEM
harmonious_dictionary (0.0.1)
hashie (3.6.0)
htmlentities (4.3.4)
httparty (0.18.0)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (1.8.2)
concurrent-ruby (~> 1.0)
io-like (0.3.1)
@ -177,9 +170,6 @@ GEM
mimemagic (~> 0.3.2)
maruku (0.7.3)
method_source (0.9.2)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2019.1009)
mimemagic (0.3.4)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
@ -402,8 +392,6 @@ GEM
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thor (1.0.1)
thread_safe (0.3.6)
tilt (2.0.10)
@ -437,6 +425,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 6.0)
acts_as_list
ancestry
annotate (~> 2.6.0)
awesome_print
axlsx (~> 3.0.0.pre)
axlsx_rails (~> 0.5.2)
@ -452,7 +441,6 @@ DEPENDENCIES
enumerize
faraday (~> 0.15.4)
font-awesome-sass (= 4.7.0)
gitlab!
grape-entity (~> 0.7.1)
groupdate (~> 4.1.0)
harmonious_dictionary (~> 0.0.1)
@ -502,8 +490,5 @@ DEPENDENCIES
web-console (>= 3.3.0)
wkhtmltopdf-binary
RUBY VERSION
ruby 2.3.7p456
BUNDLED WITH
2.1.4

4938
README.md

File diff suppressed because it is too large Load Diff

4016
api_document.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -110,33 +110,33 @@ class AccountsController < ApplicationController
# params[:login] 邮箱或者手机号
# params[:code] 验证码
# code_type 1注册手机验证码 8邮箱注册验证码
# 本地forge注册入口
def register
begin
# 查询验证码是否正确;type只可能是1或者8
type = phone_mail_type(params[:login].strip)
code = params[:code].strip
# code = params[:code].strip
if type == 1
uid_logger("start register by phone: type is #{type}")
pre = 'p'
email = nil
phone = params[:login]
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
# verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last
# TODO: 暂时限定邮箱注册
return normal_status(-1, '只支持邮箱注册')
else
uid_logger("start register by email: type is #{type}")
pre = 'm'
email = params[:login]
phone = nil
verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last
return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login])
return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL
# verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last
end
uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
# uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}")
# check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60)
# todo 上线前请删除万能验证码"513231"
unless code == "513231" && request.subdomain == "test-newweb"
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
end
return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD
code = generate_identifier User, 8, pre
@ -146,23 +146,20 @@ class AccountsController < ApplicationController
# 现在因为是验证码,所以在注册的时候就可以激活
@user.activate
# 必须要用save操作密码的保存是在users中
if @user.save!
# todo user_extension
UserExtension.create!(user_id: @user.id)
# 注册完成手机号或邮箱想可以奖励500金币
# RewardGradeService.call(
# @user,
# container_id: @user.id,
# container_type: pre == 'p' ? 'Phone' : 'Mail',
# score: 500
# )
# 注册时,记录是否是引流用户
ip = request.remote_ip
ua = UserAgent.find_by_ip(ip)
ua.update_column(:agent_type, UserAgent::USER_REGISTER) if ua
successful_authentication(@user)
# session[:user_id] = @user.id
normal_status("注册成功")
interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]})
if interactor.success?
gitea_user = interactor.result
result = Gitea::User::GenerateTokenService.new(login, params[:password]).call
@user.gitea_token = result['sha1']
@user.gitea_uid = gitea_user['id']
if @user.save!
UserExtension.create!(user_id: @user.id)
successful_authentication(@user)
normal_status("注册成功")
end
else
tip_exception(-1, interactor.error)
end
rescue Exception => e
uid_logger_error(e.message)

View File

@ -6,6 +6,12 @@ class Admins::LaboratoriesController < Admins::BaseController
@laboratories = paginate laboratories.preload(:laboratory_users)
end
def new
respond_to do |format|
format.js
end
end
def create
Admins::CreateLaboratoryService.call(create_params)
render_ok

View File

@ -1,4 +1,11 @@
class Admins::LaboratorySettingsController < Admins::BaseController
def new
respond_to do |format|
format.js
end
end
def show
@laboratory = current_laboratory
end

View File

@ -10,7 +10,7 @@ class ApplicationController < ActionController::Base
include LoggerHelper
include LoginHelper
include RegisterHelper
protect_from_forgery prepend: true, unless: -> { request.format.json? }
before_action :check_sign
@ -343,7 +343,8 @@ class ApplicationController < ActionController::Base
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
user = User.find 1
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
user = User.find 36480
User.current = user
cookies.signed[:user_id] = user.id
end
@ -384,11 +385,7 @@ class ApplicationController < ActionController::Base
end
def current_user
if Rails.env.development?
User.current = User.find 1
else
User.current
end
User.current
end
## 默认输出json
@ -744,12 +741,12 @@ class ApplicationController < ActionController::Base
namespace = params[:owner]
id = params[:repo] || params[:id]
@project = Project.find_with_namespace(namespace, id)
@project, @owner = Project.find_with_namespace(namespace, id)
if @project and current_user.can_read_project?(@project)
logger.info "########### has project and can read project"
@project
elsif current_user.is_a?(AnonymousUser)
elsif @project && current_user.is_a?(AnonymousUser)
logger.info "###########This is AnonymousUser"
@project = nil if !@project.is_public?
render_forbidden and return
@ -762,7 +759,7 @@ class ApplicationController < ActionController::Base
end
def load_repository
@repository ||= load_project.repository
@repository ||= load_project&.repository
end
private

View File

@ -2,7 +2,7 @@
#
# 文件上传
class AttachmentsController < ApplicationController
before_action :require_login, :check_auth, except: [:show]
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
before_action :find_file, only: %i[show destroy]
before_action :attachment_candown, only: [:show]
skip_before_action :check_sign, only: [:show, :create]
@ -28,6 +28,15 @@ class AttachmentsController < ApplicationController
update_downloads(@file)
end
def get_file
normal_status(-1, "参数缺失") if params[:download_url].blank?
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
response = Faraday.get(url)
filename = params[:download_url].to_s.split("/").pop()
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
end
def create
# 1. 本地存储
# 2. 上传到云
@ -107,6 +116,26 @@ class AttachmentsController < ApplicationController
end
end
# 附件为视频时,点击播放
def preview_attachment
attachment = Attachment.find_by(id: params[:id])
dir_path = "#{Rails.root}/public/preview"
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
if params[:status] == "preview"
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
else
normal_status(-1, "出现错误,请稍后重试")
end
else
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
normal_status(1, "操作成功")
else
normal_status(-1, "出现错误,请稍后重试")
end
end
end
private
def find_file
@file =

View File

@ -0,0 +1,48 @@
class Ci::BaseController < ApplicationController
include Ci::DbConnectable
before_action :require_login
before_action :connect_to_ci_database, if: -> { current_user && !current_user.is_a?(AnonymousUser) && !current_user.devops_uninit? }
before_action :connect_to_ci_database, only: :load_repo
def load_repo
namespace = params[:owner]
id = params[:repo] || params[:id]
@ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id)
end
private
def authorize_access_project!
unless @project.manager?(current_user)
return render_forbidden
end
end
def authenticate_manager!
unless @project.manager?(current_user)
return render_forbidden
end
end
def authenticate_admin!
return render_forbidden unless current_user.admin?
end
def authorize_owner!
unless @project.owner?(current_user)
return render_forbidden
end
end
def find_cloud_account
@cloud_account ||= current_user.ci_cloud_account
@cloud_account.blank? ? nil : @cloud_account
end
def load_ci_user
@ci_user ||= Ci::User.find_by(user_login: params[:owner])
@ci_user.blank? ? raise("未找到相关的记录") : @ci_user
end
end

View File

@ -0,0 +1,54 @@
class Ci::BuildsController < Ci::BaseController
include RepositoriesHelper
before_action :load_project
before_action :authorize_owner!, only: [:restart, :stop]
before_action :load_repo
before_action :find_cloud_account, except: [:index, :show]
def index
@user = current_user
scope = @repo.builds
scope = Ci::Builds::ListQuery.call(@repo, params)
@total_count = scope.map(&:build_id).size
@builds = paginate scope
end
def show
@build = @repo.builds.includes(stages: [:steps]).find_by(build_number: params[:build])
end
def restart
result = Ci::Drone::API.new(@ci_user.user_hash, @cloud_account.drone_url, @repo.repo_namespace, @repo.repo_name, number: params[:build]).restart
render json: result
end
def stop
result = Ci::Drone::API.new(@ci_user.user_hash, @cloud_account.drone_url, @repo.repo_namespace, @repo.repo_name, number: params[:build]).stop
render json: result
end
def logs
# TODO **待优化**
# 因直接操作ci库如下查询待优化可直接根据log id查询即可
build = @repo.builds.find_by(build_number: params[:build])
return render_not_found("Couldn't found build with 'number'= #{params[:build]}") if build.blank?
stage = build.stages.includes(steps: [:log]).find_by(stage_number: params[:stage])
return render_not_found("Couldn't found build with 'number'= #{params[:stage]}") if stage.blank?
step = stage.steps.find_by(step_number: params[:step])
return render_not_found("Couldn't found build with 'number'= #{params[:step]}") if step.blank?
log = step.log
result = log.blank? ? nil : (log.log_data[0..5].include?('null') ? nil : JSON.parse(log.log_data))
# result = Ci::Drone::API.new(@user.user_hash, @cloud_account.drone_url, @repo.repo_namespace, @repo.repo_name, build: params[:build], stage: params[:stage], step: params[:step]).logs
render json: result
end
end

View File

@ -0,0 +1,101 @@
class Ci::CloudAccountsController < Ci::BaseController
include Ci::CloudAccountManageable
skip_before_action :connect_to_ci_database, only: %i[create bind]
before_action :load_project, only: %i[create activate]
before_action :authorize_owner!, only: %i[create activate]
before_action :load_repo, only: %i[activate]
before_action :find_cloud_account, only: %i[show oauth_grant]
before_action :validate_params!, only: %i[create bind]
before_action only: %i[create bind] do
connect_to_ci_database(master_db: true)
end
def create
flag, msg = check_bind_cloud_account!
return render_error(msg) if flag === true
ActiveRecord::Base.transaction do
@cloud_account = bind_account!
if @cloud_account.blank?
render_error('激活失败, 请检查你的云服务器信息是否正确.')
raise ActiveRecord::Rollback
else
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
render_ok(redirect_url: @cloud_account.authenticate_url)
end
end
rescue Exception => ex
render_error(ex.message)
end
def activate
return render_error('请先认证') unless current_user.ci_certification?
begin
@cloud_account = Ci::CloudAccount.find params[:id]
ActiveRecord::Base.transaction do
if @repo
return render_error('该项目已经激活') if @repo.repo_active?
@repo.activate!(@ci_user.user_id)
else
@repo = Ci::Repo.auto_create!(@ci_user, @project)
@user.update_column(:user_syncing, false)
end
result = bind_hook!(current_user, @cloud_account, @repo)
@project.update_columns(open_devops: true, gitea_webhook_id: result['id'])
@cloud_account.update_column(:ci_user_id, @ci_user.user_id)
end
render_ok
rescue Exception => ex
render_error(ex.message)
end
end
def show
end
def bind
flag, msg = check_bind_cloud_account!
return render_error(msg) if flag === true
ActiveRecord::Base.transaction do
@cloud_account = bind_account!
if @cloud_account.blank?
render_error('激活失败, 请检查你的云服务器信息是否正确.')
raise ActiveRecord::Rollback
else
current_user.set_drone_step!(User::DEVOPS_UNVERIFIED)
end
end
rescue Exception => ex
render_error(ex.message)
end
def unbind
ActiveRecord::Base.transaction do
unbind_account!
render_ok
end
rescue Exception => ex
render_error(ex.message)
end
def oauth_grant
password = params[:password].to_s
return render_error('你输入的密码不正确.') unless current_user.check_password?(password)
oauth = current_user.oauths.last
return render_error("服务器出小差了.") if oauth.blank?
result = gitea_oauth_grant!(password, oauth)
return render_error('授权失败.') unless result === true
current_user.set_drone_step!(User::DEVOPS_CERTIFICATION)
end
private
def validate_params!
Ci::CreateCloudAccountForm.new(devops_params).validate!
end
end

View File

@ -0,0 +1,20 @@
class Ci::LanguagesController < Ci::BaseController
# TODO 需要开启权限认证只有该项目devops初始化成功后才能获取语言列表
before_action :find_langugae, only: :show
def index
@languages = Ci::Language.by_usage_amount_desc
end
def show
end
def common
@languages = Ci::Language.six_common
end
private
def find_langugae
@language = Ci::Language.find params[:id]
end
end

View File

@ -0,0 +1,73 @@
class Ci::ProjectsController < Ci::BaseController
include RepositoriesHelper
include Ci::CloudAccountManageable
before_action :load_project
before_action :load_repo, only: [:update_trustie_pipeline, :activate, :deactivate]
before_action :authorize_owner!, only: [:authorize]
before_action :find_cloud_account, only: [:authorize, :activate, :deactivate]
def authorize
@user = current_user
end
# get .trustie-pipeline.yml file
def get_trustie_pipeline
file_path_uri = URI.parse('.trustie-pipeline.yml')
interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: params[:ref] || "master")
if interactor.success?
file = interactor.result
return render json: {} if file[:status]
json = {name: file['name'], path: file['path'], sha: file['sha'], content: render_decode64_content(file['content'])}
render json: json
end
end
def update_trustie_pipeline
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, params[:owner], params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
render_result(1, "更新成功")
else
render_error(interactor.error)
end
end
def activate
return render_error('你还未认证') unless current_user.ci_certification?
begin
ActiveRecord::Base.transaction do
if @repo
return render_error('该项目已经激活') if @repo.repo_active?
if @project.ci_reactivate?
@project.ci_reactivate!(@repo)
return render_ok
end
@repo.activate!(@ci_user.user_id)
else
@repo = Ci::Repo.auto_create!(@ci_user, @project)
@ci_user.update_column(:user_syncing, false)
end
result = bind_hook!(current_user, @cloud_account, @repo)
@project.update_columns(open_devops: true, gitea_webhook_id: result['id'])
@project.increment!(:open_devops_count)
@cloud_account.update_column(:ci_user_id, @ci_user.user_id)
end
render_ok
rescue Exception => ex
render_error(ex.message)
end
end
def deactivate
return render_error('该项目已经取消激活') if !@repo.repo_active?
@project.update_column(:open_devops, false)
@repo.deactivate!
render_ok
end
end

View File

@ -0,0 +1,15 @@
class CompareController < ApplicationController
# skip_before_action :require_login
before_action :load_repository
def index
end
def show
base_ref = Addressable::URI.unescape(params[:base])
@ref = head_ref = Addressable::URI.unescape(params[:head]&.split('.json')[0])
@compare_result = Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base_ref, head_ref)
# render json: @compare_result
end
end

View File

@ -0,0 +1,138 @@
module Ci::CloudAccountManageable
extend ActiveSupport::Concern
included do
end
def bind_account!
# 1. 保存华为云服务器帐号
create_params = devops_params.merge(ip_num: IPAddr.new(devops_params[:ip_num].strip).to_i, secret: Ci::CloudAccount.encrypted_secret(devops_params[:secret]))
cloud_account = Ci::CloudAccount.new(create_params)
cloud_account.user = current_user
cloud_account.save!
# 2. 生成oauth2应用程序的client_id和client_secrete
gitea_oauth = Gitea::Oauth2::CreateService.call(current_user.gitea_token, {name: "pipeline-#{SecureRandom.hex(8)}", redirect_uris: ["#{cloud_account.drone_url}/login"]})
logger.info "######### gitea_oauth: #{gitea_oauth}"
oauth = Oauth.new(client_id: gitea_oauth['client_id'],
client_secret: gitea_oauth['client_secret'],
redirect_uri: gitea_oauth['redirect_uris'],
gitea_oauth_id: gitea_oauth['id'],
user_id: current_user.id)
oauth.save!
# 创建数据ci端数据库
database_result = auto_create_database!(@connection, "#{current_user.login}_drone")
logger.info "[CI::DbConnectable] auto_create_database's result: #{database_result}"
# 初始化表结构
sub_connection = connect_to_ci_database
auto_create_table_structure!(sub_connection)
rpc_secret = SecureRandom.hex 16
logger.info "######### rpc_secret: #{rpc_secret}"
# 3. 创建drone server
drone_server_cmd = Ci::Drone::Server.new(current_user.login, oauth.client_id, oauth.client_secret, cloud_account.drone_host, rpc_secret).generate_cmd
logger.info "######### drone_server_cmd: #{drone_server_cmd}"
# 4. 创建drone client
drone_client_cmd = Ci::Drone::Client.new(oauth.client_id, cloud_account.drone_ip, rpc_secret).generate_cmd
logger.info "######### drone_client_cmd: #{drone_client_cmd}"
# 5. 登录远程服务器启动drone服务
result = Ci::Drone::Start.new(cloud_account.account, cloud_account.visible_secret, cloud_account.drone_ip, drone_server_cmd, drone_client_cmd).run
logger.info "######### result: #{result}"
redirect_url = "#{cloud_account.drone_url}/login"
logger.info "######### redirect_url: #{redirect_url}"
return nil unless result.present?
result && !result.blank? ? cloud_account : nil
end
def unbind_account!
cloud_account = current_user.ci_cloud_account
return render_error('你未绑定CI服务器') if current_user.devops_step == User::DEVOPS_UNINIT || cloud_account.blank?
cloud_account.destroy! unless cloud_account.blank?
@connection.execute("DROP DATABASE IF EXISTS #{current_user.login}_drone") # TOTO drop drone database
current_user.unbind_account!
end
def bind_hook!(user, cloud_account, repo)
hook_params = {
active: true,
config: {
content_type: "json",
url: cloud_account.drone_url + "/hook?secret=#{repo.repo_signer}"
},
type: "gitea"
}
result = Gitea::Hooks::CreateService.call(user.gitea_token, user.login, repo.repo_name, hook_params)
result[:status].present? ? nil : result
end
def check_bind_cloud_account!
return [true, "你已经绑定了云帐号."] unless current_user.ci_cloud_account.blank?
ip_num = IPAddr.new(devops_params[:ip_num]).to_i
Ci::CloudAccount.exists?(ip_num: ip_num) ? [true, "#{devops_params[:ip_num]}服务器已被使用."] : [false, nil]
end
def gitea_auto_create_auth_grant!(gitea_oauth_id)
connection = Gitea::Database.set_connection.connection
unix_time = Time.now.to_i
# 目前直接操作db可以建立对应的model进行操作
sql = "INSERT INTO oauth2_grant ( user_id, application_id, counter, created_unix, updated_unix ) VALUES ( #{current_user.gitea_uid}, #{gitea_oauth_id}, 0, #{unix_time}, #{unix_time} );"
connection.execute(sql)
end
def gitea_oauth_grant!(password, oauth)
gitea_auto_create_auth_grant!(oauth&.gitea_oauth_id)
state = SecureRandom.hex(8)
# redirect_uri eg:
# https://localhost:3000/login/oauth/authorize?client_id=94976481-ad0e-4ed4-9247-7eef106007a2&redirect_uri=http%3A%2F%2F121.69.81.11%3A80%2Flogin&response_type=code&state=9cab990b9cfb1805
redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login")
grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{oauth&.client_id}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}"
logger.info "[gitea] grant_url: #{grant_url}"
conn = Faraday.new(url: grant_url) do |req|
req.request :url_encoded
req.adapter Faraday.default_adapter
req.basic_auth(current_user.login, password)
end
response = conn.get
logger.info "[gitea] response headers: #{response.headers}"
drone_oauth_user!(response.headers.to_h['location'], state)
end
def drone_oauth_user!(url, state)
logger.info "[drone] drone_oauth_user url: #{url}"
conn = Faraday.new(url: url) do |req|
req.request :url_encoded
req.adapter Faraday.default_adapter
req.headers["cookie"] = "_session_=#{SecureRandom.hex(28)}; _oauth_state_=#{state}"
end
response = conn.get
logger.info "[drone] response headers: #{response.headers}"
response.headers['location'].include?('error') ? false : true
end
private
def devops_params
params.permit(:account, :secret, :ip_num)
end
end

View File

@ -0,0 +1,40 @@
module Ci::DbConnectable
extend ActiveSupport::Concern
included do
end
# Dynamically sets the database connection.
def connect_to_ci_database(options={})
master_db = options[:master_db] || false
config = Rails.application.config_for(:configuration).symbolize_keys!
db_config = config[:ci_db_server].symbolize_keys!
raise 'ci database config missing' if db_config.blank?
req_params = {
host: db_config[:host],
username: db_config[:username],
password: db_config[:password],
port: db_config[:port]
}
req_params = req_params.merge(database: "#{current_user.login}_#{db_config[:database]}") unless master_db === true
db_params = Ci::Database.get_connection_params(req_params)
@connection = Ci::Database.set_connection(db_params).connection
end
def auto_create_database!(connection, database)
Rails.logger.info "[CI::DbConnectable] auto_create_database's connection: #{connection}"
connection.execute("CREATE DATABASE IF NOT EXISTS #{database}")
end
def auto_create_table_structure!(connection)
Rails.logger.info "[CI::DbConnectable] auto_create_table_structure's connection: #{connection}"
sqls = Ci::Schema.statement.split(';').map(&:strip).reject { |e| e.to_s.empty? }
sqls.each do |sql|
con_result = connection.execute(sql)
Rails.logger.info "=============> ci create tabels result: #{con_result}"
end
end
end

View File

@ -17,7 +17,7 @@ module LoginHelper
:expires => 1.month.from_now,
:path => '/',
:secure => false,
:httponly => false
:httponly => true
}
if edu_setting('cookie_domain').present?
cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain'))
@ -51,11 +51,16 @@ module LoginHelper
Rails.logger.info("####################__User.current_id______######{current_user.try(:id)}###___#{current_user&.logged?}")
if User.current.logged?
if autologin = cookies.delete(autologin_cookie_name)
user = User.current
autologin =
if edu_setting('cookie_domain').present?
cookies.delete(autologin_cookie_name, domain: edu_setting('cookie_domain'))
else
cookies.delete(autologin_cookie_name)
end
User.current.delete_autologin_token(autologin)
end
User.current.delete_session_token(session[:tk])
user.delete_autologin_token(autologin)
user.delete_session_token(session[:tk])
self.logged_user = nil
end
@ -68,7 +73,7 @@ module LoginHelper
# Sets the logged in user
def logged_user=(user)
# reset_session
reset_session
if user && user.is_a?(User)
Rails.logger.info("########________logged_user___________###########{user.id}")
@ -111,4 +116,34 @@ module LoginHelper
false
end
end
# TODO 同步token到trustie平台保持同步登录状态
def sync_user_token_to_trustie(login, token_value)
config = Rails.application.config_for(:configuration).symbolize_keys!
token = config[:sync_token]
api_host = config[:sync_url]
return if api_host.blank?
url = "#{api_host}/api/v1/users/sync_user_token"
sync_json = {
"token": token,
"login": login,
"user_token": token_value
}
uri = URI.parse(url)
if api_host
http = Net::HTTP.new(uri.hostname, uri.port)
if api_host.include?("https://")
http.use_ssl = true
end
http.send_request('POST', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'})
end
end
end

View File

@ -1,7 +1,7 @@
module RegisterHelper
extend ActiveSupport::Concern
def autologin_register(username, email, password, platform= '')
def autologin_register(username, email, password, platform= 'forge')
result = {message: nil, user: nil}
email ||= "#{username@example.org}"

View File

@ -4,18 +4,18 @@ class HooksController < ApplicationController
before_action :check_user
before_action :set_repository
def index
hooks_response = Gitea::Hooks::ListService.new(@user, @repository.try(:identifier)).call
if hooks_response.status == 200
def index
hooks_response = Gitea::Hooks::ListService.new(@user.gitea_token, @user.login, @repository.try(:identifier)).call
if hooks_response.status == 200
lists = JSON.parse(hooks_response.body)
@hooks_size = lists.size
@hooks = paginate(lists)
else
else
normal_status(-1, "出现错误")
end
end
def create
def create
#根据gitea的api
# hook_params = {
# active: true,
@ -36,17 +36,17 @@ class HooksController < ApplicationController
# content_type: params[:content_type].to_i,
# secret: params[:secret],
# events: {
# push_only: params[:push_only] || false, # 是否为推送事件
# send_everything: params[:send_everything] || false, #是否为所有事件
# push_only: params[:push_only] || false, # 是否为推送事件
# send_everything: params[:send_everything] || false, #是否为所有事件
# choose_events: params[:choose_events] || false, #是否为自定义事件
# branch_filter: params[:branch_filter] || "*",
# events: {
# create: params[:create] || false, #创建分支/标签
# delete: params[:delete] || false, #删除分支/标签
# fork: params[:fork] || false, #仓库被派生
# delete: params[:delete] || false, #删除分支/标签
# fork: params[:fork] || false, #仓库被派生
# issues: params[:issues] || false, #工单
# issue_comment: params[:issue_comment] || false, #评论
# push: params[:push] || false # 推送
# issue_comment: params[:issue_comment] || false, #评论
# push: params[:push] || false # 推送
# pull_request: params[:pull_request] || false #合并请求
# repository: params[:repository] || false #仓库
# release: params[:release] || false #版本发布
@ -58,28 +58,28 @@ class HooksController < ApplicationController
Gitea::Hooks::CreateService.new(@user, @repository.try(:identifier), hook_params).call #创建gitea的hook功能
Gitea::Hooks::CreateService.new(user, p.try(:identifier), hook_params).call #创建gitea的hook功能
end
end
def update
def update
hook_params = params[:hook_params]
response = Gitea::Hooks::UpdateService.new(@user, @repository.try(:identifier), hook_params, params[:id]).call
if response.status == 200
if response.status == 200
normal_status(1, "更新成功")
else
else
normal_status(-1, "更新失败")
end
end
end
def destroy
def destroy
response = Gitea::Hooks::DestroyService.new(@user, @repository.try(:identifier), params[:id]).call
if response.status == 204
normal_status(1, "删除成功")
else
else
normal_status(-1, "删除失败")
end
end
end
private
private
def set_repository
@repository = @project.repository
@ -88,9 +88,9 @@ class HooksController < ApplicationController
normal_status(-1, "用户不存在") unless @user.present?
end
def check_user
unless @project.user_id == current_user.id
tip_exception(403, "您没有权限进入")
def check_user
unless @project.user_id == current_user.id
tip_exception(403, "您没有权限进入")
end
end
end

View File

@ -105,9 +105,6 @@ class IssuesController < ApplicationController
normal_status(-1, "标题不能为空")
elsif params[:subject].to_s.size > 255
normal_status(-1, "标题不能超过255个字符")
elsif (params[:issue_type].to_s == "2")
return normal_status(-1, "悬赏的奖金必须大于0") if params[:token].to_i == 0
else
issue_params = issue_send_params(params)
@ -137,17 +134,16 @@ class IssuesController < ApplicationController
end
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
# normal_status(0, "创建成功",)
render :json => { status: 0, message: "创建成功", id: @issue.id}
render json: {status: 0, message: "创建成", id: @issue.id}
else
normal_status(-1, @issue.errors.messages.values[0][0])
end
end
end
def edit
# @all_branches = get_branches
# @issue_chosen = issue_left_chosen(@project, @issue.id)
@issue_attachments = @issue.attachments
end
@ -204,7 +200,6 @@ class IssuesController < ApplicationController
else
normal_status(-1, @issue.errors.messages.values[0][0])
end
end
def show
@ -306,6 +301,9 @@ class IssuesController < ApplicationController
if type == 5
@issue&.project_trends&.update_all(action_type: "close")
@issue.issue_times.update_all(end_time: Time.now)
if @issue.issue_type.to_s == "2"
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))
end
if @issue.issue_classify.to_s == "pull_request"
@issue&.pull_request&.update_attribute(:status, 2)
end
@ -399,17 +397,6 @@ class IssuesController < ApplicationController
tracker_array
end
def get_branches
all_branches = []
get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @project&.repository.try(:identifier)).call
if get_all_branches && get_all_branches.size > 0
get_all_branches.each do |b|
all_branches.push(b["name"])
end
end
all_branches
end
def issue_send_params(params)
{
subject: params[:subject],

View File

@ -2,7 +2,7 @@ class MainController < ApplicationController
protect_from_forgery except: :index
skip_before_action :check_sign
skip_before_action :user_setup
# skip_before_action :setup_laboratory
skip_before_action :setup_laboratory
def first_stamp
render :json => { status: 0, message: Time.now.to_i }

View File

@ -7,7 +7,7 @@ class Oauth::EducoderController < Oauth::BaseController
token = params[:token]
::OauthEducoderForm.new({login: login, token: token, callback_url: callback_url}).validate!
open_user= OpenUsers::Educoder.find_by(uid: login)
if open_user.present? && open_user.user.present? && open_user.user.email_binded?
@ -17,15 +17,15 @@ class Oauth::EducoderController < Oauth::BaseController
redirect_to callback_url
else
Rails.logger.info "######## open user not exits"
user = User.find_by('login = ? or mail = ?', login, mail)
user = User.find_by(login: login) || User.find_by(mail: mail)
if user.is_a?(User)
if user.is_a?(User) && !user.is_a?(AnonymousUser)
OpenUsers::Educoder.create!(user: user, uid: login)
successful_authentication(user)
redirect_to callback_url
else
redirect_to oauth_register_path(login: login, callback_url: callback_url)
redirect_to oauth_register_path(login: login, mail: mail, callback_url: callback_url)
end
end
rescue WechatOauth::Error => ex

View File

@ -40,8 +40,5 @@ class PraiseTreadController < ApplicationController
end
private
def render_result
end
end

View File

@ -6,16 +6,6 @@ class ProjectCategoriesController < ApplicationController
end
def group_list
# if current_user&.logged?
# projects = Project.list_user_projects(current_user.id)
# else
# projects = Project.visible
# end
@project_children_categories = ProjectCategory.descendants
projects = Project.no_anomory_projects.visible
categories = projects.joins(:project_category).where(project_categories: {ancestry: nil}).group("project_categories.name", "project_categories.id").size.keys.to_h
extra_category_id = categories.delete("其他")
categories = categories.merge({"其他": extra_category_id}) if extra_category_id.present? #其他的放在最后面
@category_group_list = categories
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc)
end
end

View File

@ -2,16 +2,26 @@ class ProjectsController < ApplicationController
include ApplicationHelper
include OperateProjectAbilityAble
include ProjectsHelper
before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users]
before_action :load_project, except: %i[index group_type_list migrate create]
before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about]
before_action :load_project, except: %i[index group_type_list migrate create recommend]
before_action :authorizate_user_can_edit_project!, only: %i[update]
before_action :project_public?, only: %i[fork_users praise_users watch_users]
def index
scope = Projects::ListQuery.call(params)
@projects = kaminari_paginate(scope)
@total_count = @projects.total_count
# @projects = kaminari_paginate(scope)
@projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, owner: :user_extension)
category_id = params[:category_id]
@total_count =
if category_id.blank?
ps = ProjectStatistic.first
ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
else
cate = ProjectCategory.find_by(id: category_id)
cate&.projects_count || 0
end
end
def create
@ -34,7 +44,7 @@ class ProjectsController < ApplicationController
end
def branches
@branches = Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call
@branches = @project.forge? ? Gitea::Repository::Branches::ListService.new(@owner, @project.identifier).call : []
end
def group_type_list
@ -52,9 +62,13 @@ class ProjectsController < ApplicationController
ActiveRecord::Base.transaction do
# Projects::CreateForm.new(project_params).validate!
private = params[:private]
gitea_params = {
private: private,
default_branch: params[:default_branch]
}
if [true, false].include? private
new_project_params = project_params.merge(is_public: !private)
Gitea::Repository::UpdateService.new(@project.owner, @project.repository.identifier, {private: private}).call
Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
@project.repository.update_column(:hidden, private)
end
@project.update_attributes!(new_project_params)
@ -95,13 +109,44 @@ class ProjectsController < ApplicationController
end
def fork_users
fork_users = @project.fork_users.includes(:user, :project).order("fork_users.created_at desc").distinct
fork_users = @project.fork_users.includes(:user, :project, :fork_project).order("fork_users.created_at desc").distinct
@forks_count = fork_users.size
@fork_users = paginate(fork_users)
end
def simple
json_response(@project)
json_response(@project, current_user)
end
def recommend
@projects = Project.recommend.includes(:repository, :project_category, owner: :user_extension).limit(5)
end
def about
@project_detail = @project.project_detail
@attachments = Array(@project_detail&.attachments) if request.get?
ActiveRecord::Base.transaction do
if request.post?
require_login
authorizate_user_can_edit_project!
unless @project_detail.present?
@project_detail = ProjectDetail.new(
content: params[:content],
project_id: @project.id)
else
@project_detail.content = params[:content]
end
if @project_detail.save!
attachment_ids = Array(params[:attachment_ids])
@attachments = Attachment.where(id: attachment_ids)
@attachments.update_all(
container_id: @project_detail.id,
container_type: @project_detail.model_name.name,
author_id: current_user.id,
description: "")
end
end
end
end

View File

@ -0,0 +1,43 @@
class ProtectedBranchesController < ApplicationController
include OperateProjectAbilityAble
before_action :require_login
before_action :load_repository
before_action :authorizate_user_can_edit_project!
def index
scope = @repository.protected_branches
@total_count = scope.size
@protected_branches = paginate(scope)
end
def create
@protected_branch = ProtectedBranches::CreateService.call(@repository, @owner, params)
render_protected_branch_json
end
def update
@protected_branch = ProtectedBranches::UpdateService.call(@repository, @owner, params)
end
def destroy
ProtectedBranches::DestroyService.call(@repository, @owner, params[:branch_name])
render_ok
end
def show
@protected_branch = ProtectedBranches::GetService.call(@repository, @owner, params)
end
def edit
@branch, @protected_branch = ProtectedBranches::EditService.call(@repository, @owner, params[:branch_name])
end
private
def render_protected_branch_json
@protected_branch.persisted? ? @protected_branch : render_error('创建失败!')
end
end

View File

@ -1,9 +1,8 @@
class PullRequestsController < ApplicationController
before_action :require_login, except: [:index, :show]
before_action :require_login, except: [:index, :show, :files, :commits]
before_action :load_repository
before_action :set_user, only: [:new, :get_branches]
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos]
# before_action :get_relatived, only: [:edit]
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits]
before_action :load_pull_request, only: [:files, :commits]
include TagChosenHelper
include ApplicationHelper
@ -24,11 +23,11 @@ class PullRequestsController < ApplicationController
end
def new
@all_branches = PullRequests::BranchesService.new(@user, @project).call
@all_branches = Branches::ListService.call(@owner, @project)
@is_fork = @project.forked_from_project_id.present?
@projects_names = [{
project_user_login: @user.try(:login),
project_name: "#{@user.try(:show_real_name)}/#{@repository.try(:identifier)}",
project_user_login: @owner.try(:login),
project_name: "#{@owner.try(:show_real_name)}/#{@repository.try(:identifier)}",
project_id: @project.identifier,
id: @project.id
}]
@ -45,66 +44,20 @@ class PullRequestsController < ApplicationController
end
def get_branches
branch_result = PullRequests::BranchesService.new(@user, @project).call
branch_result = Branches::ListService.call(@owner, @project)
render json: branch_result
# return json: branch_result
end
def create
if params[:title].nil?
normal_status(-1, "名称不能为空")
elsif params[:issue_tag_ids].nil?
normal_status(-1, "标签不能为空")
else
ActiveRecord::Base.transaction do
begin
merge_params
pull_issue = Issue.new(@issue_params)
if pull_issue.save!
pr_params = {
user_id: current_user.try(:id),
project_id: @project.id,
issue_id: pull_issue.id,
fork_project_id: params[:fork_project_id],
is_original: params[:is_original]
}
local_requests = PullRequest.new(@local_params.merge(pr_params))
if local_requests.save
remote_pr_params = @local_params
remote_pr_params = remote_pr_params.merge(head: "#{params[:merge_user_login]}:#{params[:head]}").compact if local_requests.is_original && params[:merge_user_login]
gitea_request = Gitea::PullRequest::CreateService.call(current_user.try(:gitea_token), @project.owner, @repository.try(:identifier), remote_pr_params.except(:milestone))
if gitea_request && local_requests.update_attributes(gpid: gitea_request["number"])
if params[:issue_tag_ids].present?
params[:issue_tag_ids].each do |tag|
IssueTagsRelate.create!(issue_id: pull_issue.id, issue_tag_id: tag)
end
end
if params[:assigned_to_id].present?
Tiding.create!(user_id: params[:assigned_to_id], trigger_user_id: current_user.id,
container_id: local_requests.id, container_type: 'PullRequest',
parent_container_id: @project.id, parent_container_type: "Project",
tiding_type: 'pull_request', status: 0)
end
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
if params[:title].to_s.include?("WIP:")
pull_issue.custom_journal_detail("WIP", "", "这个合并请求被标记为尚未完成的工作。完成后请从标题中移除WIP:前缀。", current_user&.id)
end
# render :json => { status: 0, message: "PullRequest创建成功", id: pull_issue.id}
normal_status(0, "PullRequest创建成功")
else
normal_status(-1, "PullRequest创建失败")
end
else
normal_status(-1, local_requests.errors.messages.values[0][0])
end
else
normal_status(-1, pull_issue.errors.messages.values[0][0])
end
rescue => e
normal_status(-1, e.message)
raise ActiveRecord::Rollback
end
ActiveRecord::Base.transaction do
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"])
render_ok
else
render_error("create pull request error: #{@gitea_pull_request[:status]}")
raise ActiveRecord::Rollback
end
end
end
@ -226,11 +179,11 @@ class PullRequestsController < ApplicationController
elsif target_head === target_base && !is_original
normal_status(-2, "分支内容相同,无需创建合并请求")
else
can_merge = @project&.pull_requests.where(user_id: current_user&.id, head: target_head, base: target_base, status: 0, is_original: is_original, fork_project_id: params[:fork_project_id])
can_merge = @project&.pull_requests.where(head: target_head, base: target_base, status: 0, is_original: is_original, fork_project_id: params[:fork_project_id])
if can_merge.present?
render json: {
status: -2,
message: "在这些分支之间的合并请求已存在:<a href='/projects/#{@project.id}/merge/#{can_merge.first.id}/Messagecount''>#{can_merge.first.try(:title)}</a>",
message: "在这些分支之间的合并请求已存在:<a href='/projects/#{@owner.login}/#{@project.identifier}/pulls/#{can_merge.first.id}/Messagecount''>#{can_merge.first.try(:title)}</a>",
}
else
normal_status(0, "可以合并")
@ -239,9 +192,19 @@ class PullRequestsController < ApplicationController
end
def files
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gpid)
# render json: @files_result
end
def commits
@commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gpid)
# render json: @commits_result
end
private
def set_user
@user = @project.owner
def load_pull_request
@pull_request = PullRequest.find params[:id]
end
def find_pull_request

View File

@ -13,7 +13,7 @@ class RepositoriesController < ApplicationController
def show
@user = current_user
@repo = @project.repository
@result = Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
@result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil
@project_fork_id = @project.try(:forked_from_project_id)
if @project_fork_id.present?
@fork_project = Project.find_by(id: @project_fork_id)
@ -26,60 +26,85 @@ class RepositoriesController < ApplicationController
def entries
@project.increment!(:visits)
@project_owner = @project.owner
@entries = Gitea::Repository::Entries::ListService.new(@project_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}/"
if @project.educoder?
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
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}/"
end
end
def top_counts
@result = Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
@result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
end
def sub_entries
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success?
@sub_entries = interactor.result
@sub_entries = [] << @sub_entries unless @sub_entries.is_a? Array
@sub_entries = @sub_entries.sort_by{ |hash| hash['type'] }
if @project.educoder?
if params[:type] === 'file'
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
logger.info "######### sub_entries: #{@sub_entries}"
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
tmp_entries = [{
"content" => @sub_entries['data']['content'],
"type" => "blob"
}]
@sub_entries = {
"trees"=>tmp_entries,
"commits" => [{}]
}
else
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
end
else
render_error(interactor.error)
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success?
result = interactor.result
@sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result
else
render_error(interactor.error)
end
end
end
def commits
@project_owner = @project.owner
@hash_commit = Gitea::Repository::Commits::ListService.new(@project_owner.login, @project.identifier,
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
end
def commit
@commit = Gitea::Repository::Commits::GetService.new(@repository.user.login, @repository.identifier, params[:sha], current_user.gitea_token).call
@sha = params[:sha]
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true})
end
def tags
@tags = Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}).call
@tags = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
end
def edit
end
def create_file
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @project.owner.login, content_params)
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
if interactor.success?
@file = interactor.result
create_new_pr(params)
# create_new_pr(params)
else
render_error(interactor.error)
end
end
def update_file
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @project.owner.login, params.merge(identifier: @project.identifier))
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
create_new_pr(params)
# TODO: 是否创建pr
# create_new_pr(params)
render_result(1, "更新成功")
else
render_error(interactor.error)
@ -87,7 +112,7 @@ class RepositoriesController < ApplicationController
end
def delete_file
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @project.owner.login, params.merge(identifier: @project.identifier))
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
if interactor.success?
@file = interactor.result
render_result(1, "文件删除成功")
@ -133,8 +158,8 @@ class RepositoriesController < ApplicationController
end
def get_statistics
@branches_count = Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
@tags_count = Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
end
def get_ref
@ -142,9 +167,9 @@ class RepositoriesController < ApplicationController
end
def get_latest_commit
latest_commit = project_commits
@latest_commit = latest_commit[:body][0] if latest_commit.present?
@commits_count = latest_commit[:total_count] if latest_commit.present?
latest_commit = @project.educoder? ? nil : project_commits
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
end
def content_params
@ -154,6 +179,10 @@ class RepositoriesController < ApplicationController
new_branch: params[:new_branch],
content: params[:content],
message: params[:message],
committer: {
email: current_user.mail,
name: current_user.login
},
identifier: @project.identifier
}
end
@ -208,14 +237,14 @@ class RepositoriesController < ApplicationController
issue_type: "1",
tracker_id: 2,
status_id: 1,
priority_id: 1
priority_id: params[:priority_id] || "2"
}
@pull_issue = Issue.new(issue_params)
if @pull_issue.save!
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
if local_requests.save
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @project.owner, @project.try(:identifier), requests_params).call
if gitea_request && local_requests.update_attributes(gpid: gitea_request["number"])
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"])
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
end
end

View File

@ -1,8 +1,11 @@
class UsersController < ApplicationController
include Ci::DbConnectable
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users]
before_action :require_login, only: %i[me list]
before_action :connect_to_ci_database, only: :get_user_info, if: -> { current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification? }
skip_before_action :check_sign, only: [:attachment_show]
def list

View File

@ -139,7 +139,7 @@ class VersionReleasesController < ApplicationController
body: params[:body],
draft: params[:draft] || false,
name: params[:name],
prerelease: params[:prerelease],
prerelease: params[:prerelease] || false,
tag_name: params[:tag_name],
target_commitish: params[:target_commitish] || "master" #分支
}

View File

@ -0,0 +1,10 @@
class Ci::CreateCloudAccountForm
include ActiveModel::Model
attr_accessor :ip_num, :account, :secret
# validates :project_id, :account, :secret, presence: true
validates :account, :secret, presence: true
validates :ip_num, presence: true, format: { with: CustomRegexp::IP, multiline: true, message: 'IP 地址格式不对' }
end

View File

@ -0,0 +1,19 @@
class ProtectedBranches::CreateForm < BaseForm
attr_accessor :repository, :branch_name, :can_push, :enable_whitelist, :whitelist_user_i_ds,
:whitelist_team_i_ds, :enable_merge_whitelist, :whitelist_deploy_keys, :merge_whitelist_user_i_ds,
:merge_whitelist_team_i_ds, :enable_status_check, :status_check_contexts, :approvals_whitelist_user_i_ds,
:approvals_whitelist_team_i_ds, :required_approvals, :enable_approvals_whitelist, :block_on_rejected_reviews,
:dismiss_stale_approvals, :require_signed_commits, :protected_file_patterns, :block_on_outdated_branch
validates :repo_id, :branch_name, presence: true
validate do
check_branch_name!
end
def check_branch_name!
protected_branch_exists = repository.protected_branches.exists?(branch_name)
raise "Protected branch '#{branch_name}' already exists" if protected_branch_exists
end
end

View File

@ -436,4 +436,9 @@ module ApplicationHelper
def find_user_by_login(login)
User.find_by_login login
end
def render_base64_decoded(str)
return nil if str.blank?
Base64.decode64 str
end
end

View File

@ -0,0 +1,11 @@
module Ci::BuildsHelper
def format_utc_time(unix_time)
return nil if unix_time == 0
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
end
def render_duartion_time(end_time, start_time)
return nil if end_time == 0 || start_time == 0
game_spend_time(end_time - start_time)
end
end

View File

@ -0,0 +1,2 @@
module Ci::LanguagesHelper
end

View File

@ -0,0 +1,2 @@
module CompareHelper
end

View File

@ -0,0 +1,2 @@
module DevOpsHelper
end

View File

@ -1,2 +1,18 @@
module MembersHelper
def get_user_token(user_login,reponame)
query_params = {
type: "query",
chain_params: {
reponame: reponame,
username: user_login
}
}
response = Gitea::Chain::ChainGetService.new(query_params).call
if response.status == 200
return JSON.parse(response.body)["balance"].to_i
else
return 0
end
end
end

View File

@ -28,8 +28,10 @@ module ProjectsHelper
(User.find_by_login identifier) || (User.find_by_mail identifier)
end
def json_response(project)
repo = project.repository
def json_response(project, user)
# repo = project.repository
repo = Repository.includes(:mirror).select(:id, :mirror_url).find_by(project: project)
tmp_json = {}
unless project.common?
tmp_json = tmp_json.merge({
@ -41,16 +43,48 @@ module ProjectsHelper
end
tmp_json = tmp_json.merge({
identifier: project.identifier,
identifier: render_identifier(project),
name: project.name,
platform: project.platform,
id: project.id,
repo_id: repo.id,
open_devops: (user.blank? || user.is_a?(AnonymousUser)) ? false : project.open_devops?,
type: project.numerical_for_project_type,
author: {
login: project.owner.login,
name: project.owner.real_name,
image_url: url_to_avatar(project.owner)
}
author: render_owner(project)
}).compact
render json: tmp_json
end
def render_owner(project)
if project.educoder?
{
login: project.project_educoder.owner,
name: project.project_educoder.owner,
image_url: project.project_educoder.image_url
}
else
{
login: @owner.login,
name: @owner.real_name,
image_url: url_to_avatar(@owner)
}
end
end
def render_identifier(project)
project.educoder? ? project.project_educoder&.repo_name&.split('/')[1] : project.identifier
end
def render_author(project)
project.educoder? ? project.project_educoder&.repo_name&.split('/')[0] : project.owner.login
end
def render_educoder_avatar_url(project_educoder)
[Rails.application.config_for(:configuration)['educoder']['cdn_url'], project_educoder&.image_url].join('/')
end
def render_avatar_url(owner)
['images', url_to_avatar(owner)].join('/')
end
end

View File

@ -0,0 +1,2 @@
module ProtectedBranchesHelper
end

View File

@ -1,11 +1,17 @@
module RepositoriesHelper
def render_permission(user, project)
return "Admin" if user&.admin?
return "Owner" if user === project.owner
project.get_premission(user)
end
def render_decode64_content(str)
return nil if str.blank?
Base64.decode64(str).force_encoding('UTF-8')
Base64.decode64(str).force_encoding("UTF-8")
end
def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx)
default_type.include?(str&.downcase)
end
@ -44,7 +50,7 @@ module RepositoriesHelper
end
if r_content.include?("?")
new_r_content = r_content + "&raw=true"
else
else
new_r_content = r_content + "?raw=true"
end
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
@ -56,4 +62,14 @@ module RepositoriesHelper
return content
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
end

View File

@ -1,4 +1,143 @@
module TagChosenHelper
def get_associated_data(project)
issue_comment_users_array = []
cost_time_array = []
all_issues = []
{
"assign_user": render_cache_collaborators(project),
"tracker": render_cache_trackers,
"issue_status": render_cache_issue_statuses,
"priority": render_cache_issue_priorities,
"issue_version": render_cache_milestones(project),
"start_date": "",
"due_date": "",
"joins_users": issue_comment_users_array,
"cost_time_users": cost_time_array,
# "total_cost_time": Time.at(all_cost_time).utc.strftime('%H h %M min %S s'),
# "be_depended_issues": be_depended_issues_array,
# "depended_issues":depended_issues_array,
# "estimated_hours": issue_info[7],
"done_ratio": render_complete_percentage,
"issue_tag": render_issue_tags(project),
"issue_type": render_issue_species,
"all_issues": all_issues
}
end
def render_cache_trackers
cache_key = "all_trackers/#{Tracker.maximum('id')}"
Rails.cache.fetch(cache_key) do
Tracker.select(:id, :name, :position).collect do |event|
{
id: event.id,
name: event.name,
position: event.position,
is_chosen: '0'
}
end
end
end
def render_cache_issue_statuses
cache_key = "all_issue_statuses/#{IssueStatus.maximum('id')}"
Rails.cache.fetch(cache_key) do
IssueStatus.select(:id, :name, :position).collect do |event|
{
id: event.id,
name: event.name,
position: event.position,
is_chosen: '0'
}
end
end
end
def render_cache_issue_priorities
cache_key = "all_issue_priorities/#{IssuePriority.maximum('id')}"
Rails.cache.fetch(cache_key) do
IssuePriority.select(:id, :name, :position).collect do |event|
{
id: event.id,
name: event.name,
position: event.position,
is_chosen: '0'
}
end
end
end
def render_complete_percentage
completion_nums = %w(0 10 20 30 40 50 60 70 80 90 100)
completion_nums.collect do |event|
{
id: event.to_i,
name: event + "%",
is_chosen: '0'
}
end
end
def render_issue_species
species = %W(普通 悬赏)
species.collect do |event|
{
id: event.to_i + 1,
token: nil,
is_chosen: '0'
}
end
end
def render_issue_tags(project)
# project.issue_tags.last&.cache_key
cache_key = "all_issue_tags/#{project.issue_tags.maximum('updated_at')}"
Rails.cache.fetch(cache_key) do
project.issue_tags.select(:id, :name, :color).collect do |event|
{
id: event.id,
name: event.name,
color: event.color,
is_chosen: '0'
}
end
end
end
def render_cache_milestones(project)
cache_key = "all_milestones/#{project.versions.maximum('updated_on')}"
Rails.cache.fetch(cache_key) do
project.versions.select(:id, :name, :status).collect do |event|
{
id: event.id,
name: event.name,
status: event.status,
is_chosen: '0'
}
end
end
end
def render_cache_collaborators(project)
cache_key = "all_collaborators/#{project.members.maximum('created_on')}"
Rails.cache.fetch(cache_key) do
project.members.includes(:user).collect do |event|
{
id: event.user&.id,
name: event.user&.show_real_name,
avatar_url: url_to_avatar(event.user),
is_chosen: '0'
}
end
end
end
def issue_left_chosen(project,issue_id)
issue_info = Array.new(11)
@ -205,4 +344,4 @@ module TagChosenHelper
# be_depended_issues_array
# end
end
end

View File

@ -9,7 +9,8 @@ module Gitea
attr_reader :error, :result
def initialize(token, owner, params)
@owner = owner
@token = token
@owner = owner
@params = params
end
@ -58,6 +59,7 @@ module Gitea
file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank?
file_params = file_params.merge(content: Base64.encode64(@params[:content]))
file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank?
file_params = file_params.merge(committer: @params[:committer])
file_params
end
end

View File

@ -22,7 +22,7 @@ module Gitea
def run
Gitea::UserForm.new(params).validate!
response = Gitea::User::RegisterService.new(params).call
response = Gitea::User::RegisterService.call(params.merge(token: token))
render_result(response)
rescue Exception => exception
Rails.logger.info "Exception ===========> #{exception.message}"
@ -41,5 +41,12 @@ module Gitea
def render_result(response)
@result = response
end
def token
{
username: Gitea.gitea_config[:access_key_id],
password: Gitea.gitea_config[:access_key_secret]
}
end
end
end

View File

@ -0,0 +1,44 @@
module Repositories::ProtectedBranches
class DeleteInteractor
def self.call(user, identifier, filepath, **args)
interactor = new(user, identifier, filepath, **args)
interactor.run
interactor
end
attr_reader :error, :result
def initialize(user, identifier, filepath, **args)
@user = user
@identifier = identifier
@filepath = filepath
@args = args
end
def success?
@error.nil?
end
def result
end
def run
rescue Exception => exception
fail!(exception.message)
end
private
attr_reader :user, :identifier, :filepath, :args
def fail!(error)
@error = error
end
def render_result(response)
@result = response
end
end
end

View File

@ -0,0 +1,24 @@
class PostChainJob < ApplicationJob
queue_as :default
def perform(chain_params)
status = false
chain_type = chain_params[:type].to_s
reponame = chain_params[:chain_params][:reponame]
5.times do |i|
if status
break
else
response = Gitea::Chain::ChainPostService.new(chain_params).call
if response.status == 200
reponse_body = response&.body
messages = reponse_body.present? ? JSON.parse(reponse_body) : "success"
status = true
Rails.logger.info("################_repository__#{reponame}______create_chain_success_try:_#{i+1}_message__:#{messages}__")
else
Rails.logger.info("########_repository__#{reponame}______create_chain_failed__try:_#{i+1}_")
end
end
end
end
end

View File

@ -0,0 +1,73 @@
require 'uri'
require 'net/http'
class SyncEducoderShixunJob < ApplicationJob
queue_as :default
def perform(url, private_token, page, per_page)
uri = URI("#{url}?page=#{page}&per_page=#{per_page}&private_token=#{private_token}")
puts "-------url: #{uri}"
response = Net::HTTP.get_response(uri)
result = JSON.parse(response.body)
if result['status'] != 0
puts "======= 接口请求失败!"
return
end
result['data']['repositories'].each do |re|
next if re['repo_name'].blank?
next if ProjectEducoder.exists?(repo_name: re['repo_name'])
language = ProjectLanguage.find_by_name re['language']
language = ProjectLanguage.create!(name: re['language']) if language.blank?
category = ProjectCategory.find_by_name re['category']
category = ProjectCategory.create!(name: re['category']) if category.blank?
project_params =
{
name: re['name'],
# user_id: params[:user_id],
description: re['description'],
project_category_id: category.id,
project_language_id: language.id,
is_public: true,
# ignore_id: params[:ignore_id],
# license_id: params[:license_id],
identifier: re['repo_name'],
platform: Project.platforms[:educoder]
}
project = Project.new(project_params)
ActiveRecord::Base.transaction do
if project.save!
repo_params =
{
hidden: false,
project_id: project.id,
identifier: re['repo_name']
}
ProjectEducoder.create!(
project_id: project.id,
owner: re['username'],
repo_name: re['repo_name'],
forked_count: re['forked_count'],
commit_count: re['commit_count'],
image_url: re['image_url'])
repo = Repository.new(repo_params)
repo.save!
puts "项目: #{re['name']} 同步成功"
else
puts "项目: #{re['name']} 同步失败"
end
end
end
end
end

View File

@ -8,7 +8,7 @@ class SyncProjectsJob < ApplicationJob
SyncLog.sync_log("==========begin to sync #{sync_params[:type]} to forge============")
SyncLog.sync_log("==========sync_params:#{sync_params}============")
begin
begin
url = "#{gitea_main}/sync_forges" #trustie上的相关路由
uri = URI.parse(url)
http = Net::HTTP.new(uri.hostname, uri.port)
@ -85,7 +85,7 @@ class SyncProjectsJob < ApplicationJob
new_target = target_type.constantize.new(re[:target_params].merge(user_id: u_id))
end
end
if !is_exists && new_target.save!
SyncLog.sync_log("***【#{target_type}】. create_success---------------")
if re[:journals].present?
@ -112,10 +112,8 @@ class SyncProjectsJob < ApplicationJob
SyncLog.sync_log("=========***【#{target_type}】creat_had_erros:#{e}===================")
next
end
end
end
def create_journals(target_jsons, target_type,issue_id)
@ -127,7 +125,7 @@ class SyncProjectsJob < ApplicationJob
if re[:target_params].present?
u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first
is_exists = Journal.exists?(user_id: u_id, journalized_id: re[:target_params][:journalized_id], created_on: re[:target_params][:created_on].to_s.to_time)
if is_exists
SyncLog.sync_log("***00000. Journal:#{re[:target_params][:id]}-is exists--------------")
else
@ -142,7 +140,7 @@ class SyncProjectsJob < ApplicationJob
end
else
SyncLog.sync_log("***111222. journal_create failed---------------")
end
end
end
@ -181,4 +179,4 @@ class SyncProjectsJob < ApplicationJob
SyncLog.sync_log("***111222. end_to_create_target---------------")
end
end
end

31
app/libs/ci/database.rb Normal file
View File

@ -0,0 +1,31 @@
module Ci
class Database < ActiveRecord::Base
self.abstract_class = true
# Dynamically sets the database connection.
def self.set_connection(params)
puts "[Ci::Database] set db connection params: #{params}"
establish_connection(
adapter: params[:adapter],
database: params[:database],
port: params[:port].to_i,
host: params[:host],
username: params[:username],
password: params[:password],
encoding: "utf8"
)
end
def self.get_connection_params(connect_to)
params = Hash.new
params[:adapter] = "mysql2"
params[:host] = connect_to[:host].to_s
params[:username] = connect_to[:username].to_s
params[:password] = connect_to[:password].to_s
params[:database] = connect_to[:database].to_s
params[:port] = connect_to[:port] || "43306"
params[:encoding] = "utf8"
return params
end
end
end

81
app/libs/ci/drone/api.rb Normal file
View File

@ -0,0 +1,81 @@
class Ci::Drone::API < Ci::Drone::Request
attr_reader :drone_token, :endpoint, :owner, :repo, :options
# drone_token:
# owner: repo's owner name or login
# repo: repo's identifier
def initialize(drone_token, endpoint, owner, repo, options={})
@drone_token = drone_token
@endpoint = endpoint
@owner = owner
@repo = repo
@options = options
end
# Build List
# GET api/repos/{owner}/{name}/builds
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier)
def builds
get(endpoint, "api/repos/#{owner}/#{repo}/builds", drone_token: drone_token)
end
# Build Info
# GET api/repos/{owner}/{name}/builds/{number}
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, project.owner.login, project.identifier, number: number).build
def build
get(endpoint, "api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token)
end
# Update .trustie-pipeline.yml file
# PATCH api/repos/{owner}/{name}\
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, project.owner.login, project.identifier, config_path: config_path).config_yml
def config_yml
patch(endpoint, "/api/repos/#{owner}/#{repo}", drone_token: drone_token, config_path: options[:config_path])
end
# Activate user's project with Drone CI
# POST api/repos/{owner}/{name}
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, project.owner.login, project.identifier).activate
def activate
post(endpoint, "/api/repos/#{owner}/#{repo}", drone_token: drone_token)
end
# Build Restart
# POST api/repos/{owner}/{name}/builds/{number}
# Restart the specified build. Please note this api requires read and write access to the repository and the request parameter {build} is not the build id but the build number.
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).restart
def restart
post(endpoint, "/api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token)
end
# Build Stop
# DELETE api/repos/{owner}/{name}/builds/{number}
# Stop the specified build. Please note this api requires administrative privileges and the request parameter {build} is not the build id but the build number.
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).stop
def stop
delete(endpoint, "/api/repos/#{owner}/#{repo}/builds/#{options[:number]}", drone_token: drone_token)
end
# Build Logs
# GET /api/repos/{owner}/{repo}/builds/{build}/logs/{stage}/{step}
# Please note this api requires read access to the repository.
# eq:
# Ci::Drone::API.new(cloud_account.drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, build: build, stage: stage, step: step).logs
def logs
get(endpoint, "/api/repos/#{owner}/#{repo}/builds/#{options[:build]}/logs/#{options[:stage]}/#{options[:step]}", drone_token: drone_token)
end
# Synchronize the currently authenticated users repository list.
# POST /api/user/repos
# eq:
# Ci::Drone::API.new(drone_token, cloud_account.drone_url, @repo.user.login, @repo.identifier, number: number).sync
def sync_repos
post(endpoint, "/api/users/repos", drone_token: drone_token)
end
end

25
app/libs/ci/drone/ci.rb Normal file
View File

@ -0,0 +1,25 @@
class Ci::Drone::Ci
attr_reader :host, :username, :password, :gitea_username
# host: drone server's ip
# username: drone server's account
# password: drone server's password
# eq:
# DevOps::Drone::Ci.new(@cloud_account.drone_ip, @cloud_account.account, @cloud_account.visible_secret, current_user.login).get_token
def initialize(host, username, password, gitea_username)
@host = host
@username = username
@password = password
@gitea_username = gitea_username
end
def get_token
puts "--------- sshpass -p #{password} ssh -o 'StrictHostKeyChecking no' #{username}@#{host} '#{cmd}'"
`sshpass -p #{password} ssh -o "StrictHostKeyChecking no" #{username}@#{host} "#{cmd}"`
end
private
def cmd
"cd ..; cd var/lib/drone/; sqlite3 database.sqlite; .dump; select user_hash from users where user_login=#{gitea_username};"
end
end

View File

@ -0,0 +1,25 @@
class Ci::Drone::Client
attr_reader :client_id, :drone_ip, :rpc_secret
# client_id: user's client_id from oauth
# drone_ip: 云服务器IP地址, eq: 173.65.32.21
# eq:
# DevOps::Drone::Client.new(current_user.oauth.client_id, 'drone_ip').generate_cmd
def initialize(client_id, drone_ip, rpc_secret)
@client_id = client_id
@drone_ip = drone_ip
@rpc_secret = rpc_secret
end
def generate_cmd
"docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock \
-e DRONE_RPC_HOST=#{drone_ip}:80 \
-e DRONE_RPC_SECRET=#{rpc_secret} \
-e DRONE_RUNNER_NAME=#{drone_ip} \
--restart always \
--name drone-agent--#{client_id} \
--net='bridge' \
drone/drone-runner-docker:1"
end
end

View File

@ -0,0 +1,14 @@
class Ci::Drone::Error < StandardError
attr_reader :code
def initialize(code, message)
super message
@code = code
end
class << self
def parse(result)
new(result['errcode'], result['errmsg'])
end
end
end

View File

@ -0,0 +1,108 @@
class Ci::Drone::Request
# Converts the response body to an ObjectifiedHash.
def self.parse(body)
body = decode(body)
if body.is_a? Hash
ObjectifiedHash.new body
elsif body.is_a? Array
body.collect! { |e| ObjectifiedHash.new(e) }
elsif body == true
body
else
raise Error::Parsing.new "Couldn't parse a response body"
end
end
# Decodes a JSON response into Ruby object.
def self.decode(response)
begin
JSON.load response
rescue JSON::ParserError
raise Error::Parsing.new "The response is not a valid JSON"
end
end
def get(endpoint, path, options={})
validate_request_params!(endpoint)
request(:get, endpoint, path, options)
end
def post(endpoint, path, options={})
validate_request_params!(endpoint)
request(:post, endpoint, path, options)
end
def put(endpoint, path, options={})
validate_request_params!(endpoint)
request(:put, endpoint, path, options)
end
def patch(endpoint, path, options={})
validate_request_params!(endpoint)
request(:patch, endpoint, path, options)
end
def delete(endpoint, path, options={})
validate_request_params!(endpoint)
request(:delete, endpoint, path, options)
end
private
def request(method, endpoint, path, **params)
Rails.logger.info("[drone] request: #{method} #{path} #{params.except(:drone_token).inspect}")
client ||= begin
Faraday.new(url: endpoint) do |req|
req.request :url_encoded
req.headers['Content-Type'] = 'application/json'
req.response :logger # 显示日志
req.adapter Faraday.default_adapter
req.authorization :Bearer, params[:drone_token]
req.headers['Authorization']
end
end
response = client.public_send(method, path) do |req|
req.body = params.except(:drone_token).to_json
end
json_response(response)
end
# Checks the response code for common errors.
# Returns parsed response for successful requests.
def validate(response)
# case response.code
# when 400; raise Error::BadRequest.new error_message(response)
# when 401; raise Error::Unauthorized.new error_message(response)
# when 403; raise Error::Forbidden.new error_message(response)
# when 404; raise Error::NotFound.new error_message(response)
# when 405; raise Error::MethodNotAllowed.new error_message(response)
# when 406; raise Error::DataNotAccepted.new error_message(response)
# when 409; raise Error::Conflict.new error_message(response)
# when 500; raise Error::InternalServerError.new error_message(response)
# when 502; raise Error::BadGateway.new error_message(response)
# when 503; raise Error::ServiceUnavailable.new error_message(response)
# end
response.parsed_response
end
# Checks a base_uri and params for requests.
def validate_request_params!(endpoint)
raise "Please set an endpoint to API" unless endpoint
end
def error_message(response)
"Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \
"Request URI: #{response.request.base_uri}#{response.request.path}"
end
def json_response(response)
result = JSON.parse(response.body)
status = response.status
Rails.logger.info("[drone] response:#{status} #{result.inspect}")
response.status != 200 ? result.merge!(status: response.status) : result
end
end

View File

@ -0,0 +1,62 @@
class Ci::Drone::Server
attr_reader :user_login, :client_id, :client_secret, :drone_host, :rpc_secret
# client_id: user's client_id from oauth
# client_secret: user's client_id from oauth
# drone_host: 云服务器地址eq: 173.53.21.31:80
# eg:
# DevOps::Drone::Server.new(current_user.login, current_user.oauth.client_id, current_user.oauth.client_secret, 'drone_host').generate_cmd
def initialize(user_login, client_id, client_secret, drone_host, rpc_secret)
@user_login = user_login
@client_id = client_id
@drone_host = drone_host
@rpc_secret = rpc_secret
@client_secret = client_secret
end
# TODO 一下代码方便测试,正式环境请移除
# docker rm -f `docker ps -qa`
def generate_cmd
"service docker start; docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-e DRONE_DATABASE_DRIVER=mysql \
-e DRONE_DATABASE_DATASOURCE=#{database_username}:'#{database_password}'@tcp\\(#{database_host}:#{database_port}\\)/#{user_login}_drone?parseTime=true \
-e DRONE_GITEA_SERVER=#{gitea_url} \
-e DRONE_GITEA_CLIENT_ID=#{client_id} \
-e DRONE_GITEA_CLIENT_SECRET=#{client_secret} \
-e DRONE_RPC_SECRET=#{rpc_secret} \
-e DRONE_SERVER_HOST=#{drone_host} \
-e DRONE_SERVER_PROTO=http \
-p '80:80' \
--restart=always \
--detach=true \
--name=drone-server-#{client_id} \
--net='bridge' \
drone/drone:1"
end
private
def gitea_url
Gitea.gitea_config[:domain]
end
def database_username
database_config[Rails.env]["ci_server_db"]["username"]
end
def database_password
database_config[Rails.env]["ci_server_db"]["password"]
end
def database_host
database_config[Rails.env]["ci_server_db"]["host"]
end
def database_port
database_config[Rails.env]["ci_server_db"]["port"] || 3306
end
def database_config
Rails.configuration.database_configuration
end
end

View File

@ -0,0 +1,22 @@
class Ci::Drone::Start
attr_reader :drone_username, :drone_password, :drone_host, :drone_server_cmd, :drone_client_cmd
# drone_username="XXXX" 云服务器登录用户名
# drone_password="XXXXX" 云服务器用户密码
# drone_host="" 云服务器地址
# eq:
# drone_server_cmd = DevOps::Drone::Server.new('client_id', 'client_secret', 'drone_url').generate_cmd
# drone_client_cmd = DevOps::Drone::Client.new('client_id', 'server_url').generate_cmd
# DevOps::Drone::Start.new(drone_username, drone_password, 'drone_host', drone_server_cmd, drone_client_cmd).run
def initialize(drone_username, drone_password, drone_host, drone_server_cmd, drone_client_cmd)
@drone_username = drone_username
@drone_password = drone_password
@drone_host = drone_host
@drone_server_cmd = drone_server_cmd
@drone_client_cmd = drone_client_cmd
end
def run
`sshpass -p #{drone_password} ssh -o "StrictHostKeyChecking no" #{drone_username}@#{drone_host} "#{drone_server_cmd} && #{drone_client_cmd}"`
end
end

260
app/libs/ci/schema.rb Normal file
View File

@ -0,0 +1,260 @@
module Ci::Schema
class << self
def statement
sqls = <<-SQL
CREATE TABLE IF NOT EXISTS `repos` (
`repo_id` int(11) NOT NULL AUTO_INCREMENT,
`repo_uid` varchar(250) DEFAULT NULL,
`repo_user_id` int(11) DEFAULT NULL,
`repo_namespace` varchar(250) DEFAULT NULL,
`repo_name` varchar(250) DEFAULT NULL,
`repo_slug` varchar(250) DEFAULT NULL,
`repo_scm` varchar(50) DEFAULT NULL,
`repo_clone_url` varchar(2000) DEFAULT NULL,
`repo_ssh_url` varchar(2000) DEFAULT NULL,
`repo_html_url` varchar(2000) DEFAULT NULL,
`repo_active` tinyint(1) DEFAULT NULL,
`repo_private` tinyint(1) DEFAULT NULL,
`repo_visibility` varchar(50) DEFAULT NULL,
`repo_branch` varchar(250) DEFAULT NULL,
`repo_counter` int(11) DEFAULT NULL,
`repo_config` varchar(500) DEFAULT NULL,
`repo_timeout` int(11) DEFAULT NULL,
`repo_trusted` tinyint(1) DEFAULT NULL,
`repo_protected` tinyint(1) DEFAULT NULL,
`repo_synced` int(11) DEFAULT NULL,
`repo_created` int(11) DEFAULT NULL,
`repo_updated` int(11) DEFAULT NULL,
`repo_version` int(11) DEFAULT NULL,
`repo_signer` varchar(50) DEFAULT NULL,
`repo_secret` varchar(50) DEFAULT NULL,
PRIMARY KEY (`repo_id`),
UNIQUE KEY `repo_slug` (`repo_slug`),
UNIQUE KEY `repo_uid` (`repo_uid`)
) ENGINE=InnoDB AUTO_INCREMENT=137 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `builds` (
`build_id` int(11) NOT NULL AUTO_INCREMENT,
`build_repo_id` int(11) DEFAULT NULL,
`build_config_id` int(11) DEFAULT NULL,
`build_trigger` varchar(250) DEFAULT NULL,
`build_number` int(11) DEFAULT NULL,
`build_parent` int(11) DEFAULT NULL,
`build_status` varchar(50) DEFAULT NULL,
`build_error` varchar(500) DEFAULT NULL,
`build_event` varchar(50) DEFAULT NULL,
`build_action` varchar(50) DEFAULT NULL,
`build_link` varchar(1000) DEFAULT NULL,
`build_timestamp` int(11) DEFAULT NULL,
`build_title` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`build_message` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`build_before` varchar(50) DEFAULT NULL,
`build_after` varchar(50) DEFAULT NULL,
`build_ref` varchar(500) DEFAULT NULL,
`build_source_repo` varchar(250) DEFAULT NULL,
`build_source` varchar(500) DEFAULT NULL,
`build_target` varchar(500) DEFAULT NULL,
`build_author` varchar(500) DEFAULT NULL,
`build_author_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`build_author_email` varchar(500) DEFAULT NULL,
`build_author_avatar` varchar(1000) DEFAULT NULL,
`build_sender` varchar(500) DEFAULT NULL,
`build_deploy` varchar(500) DEFAULT NULL,
`build_params` varchar(2000) DEFAULT NULL,
`build_started` int(11) DEFAULT NULL,
`build_finished` int(11) DEFAULT NULL,
`build_created` int(11) DEFAULT NULL,
`build_updated` int(11) DEFAULT NULL,
`build_version` int(11) DEFAULT NULL,
PRIMARY KEY (`build_id`),
UNIQUE KEY `build_repo_id` (`build_repo_id`,`build_number`)
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `cron` (
`cron_id` int(11) NOT NULL AUTO_INCREMENT,
`cron_repo_id` int(11) DEFAULT NULL,
`cron_name` varchar(50) DEFAULT NULL,
`cron_expr` varchar(50) DEFAULT NULL,
`cron_next` int(11) DEFAULT NULL,
`cron_prev` int(11) DEFAULT NULL,
`cron_event` varchar(50) DEFAULT NULL,
`cron_branch` varchar(250) DEFAULT NULL,
`cron_target` varchar(250) DEFAULT NULL,
`cron_disabled` tinyint(1) DEFAULT NULL,
`cron_created` int(11) DEFAULT NULL,
`cron_updated` int(11) DEFAULT NULL,
`cron_version` int(11) DEFAULT NULL,
PRIMARY KEY (`cron_id`),
UNIQUE KEY `cron_repo_id` (`cron_repo_id`,`cron_name`),
CONSTRAINT `cron_ibfk_1` FOREIGN KEY (`cron_repo_id`) REFERENCES `repos` (`repo_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `latest` (
`latest_repo_id` int(11) NOT NULL DEFAULT '0',
`latest_build_id` int(11) DEFAULT NULL,
`latest_type` varchar(50) NOT NULL DEFAULT '',
`latest_name` varchar(500) NOT NULL DEFAULT '',
`latest_created` int(11) DEFAULT NULL,
`latest_updated` int(11) DEFAULT NULL,
`latest_deleted` int(11) DEFAULT NULL,
PRIMARY KEY (`latest_repo_id`,`latest_type`,`latest_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `logs` (
`log_id` int(11) NOT NULL,
`log_data` mediumblob,
PRIMARY KEY (`log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `migrations` (
`name` varchar(255) DEFAULT NULL,
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `nodes` (
`node_id` int(11) NOT NULL AUTO_INCREMENT,
`node_uid` varchar(500) DEFAULT NULL,
`node_provider` varchar(50) DEFAULT NULL,
`node_state` varchar(50) DEFAULT NULL,
`node_name` varchar(50) DEFAULT NULL,
`node_image` varchar(500) DEFAULT NULL,
`node_region` varchar(100) DEFAULT NULL,
`node_size` varchar(100) DEFAULT NULL,
`node_os` varchar(50) DEFAULT NULL,
`node_arch` varchar(50) DEFAULT NULL,
`node_kernel` varchar(50) DEFAULT NULL,
`node_variant` varchar(50) DEFAULT NULL,
`node_address` varchar(500) DEFAULT NULL,
`node_capacity` int(11) DEFAULT NULL,
`node_filter` varchar(2000) DEFAULT NULL,
`node_labels` varchar(2000) DEFAULT NULL,
`node_error` varchar(2000) DEFAULT NULL,
`node_ca_key` blob,
`node_ca_cert` blob,
`node_tls_key` blob,
`node_tls_cert` blob,
`node_tls_name` varchar(500) DEFAULT NULL,
`node_paused` tinyint(1) DEFAULT NULL,
`node_protected` tinyint(1) DEFAULT NULL,
`node_created` int(11) DEFAULT NULL,
`node_updated` int(11) DEFAULT NULL,
`node_pulled` int(11) DEFAULT NULL,
PRIMARY KEY (`node_id`),
UNIQUE KEY `node_name` (`node_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `orgsecrets` (
`secret_id` int(11) NOT NULL AUTO_INCREMENT,
`secret_namespace` varchar(50) DEFAULT NULL,
`secret_name` varchar(200) DEFAULT NULL,
`secret_type` varchar(50) DEFAULT NULL,
`secret_data` blob,
`secret_pull_request` tinyint(1) DEFAULT NULL,
`secret_pull_request_push` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`secret_id`),
UNIQUE KEY `secret_namespace` (`secret_namespace`,`secret_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `perms` (
`perm_user_id` int(11) NOT NULL DEFAULT '0',
`perm_repo_uid` varchar(250) NOT NULL DEFAULT '',
`perm_read` tinyint(1) DEFAULT NULL,
`perm_write` tinyint(1) DEFAULT NULL,
`perm_admin` tinyint(1) DEFAULT NULL,
`perm_synced` int(11) DEFAULT NULL,
`perm_created` int(11) DEFAULT NULL,
`perm_updated` int(11) DEFAULT NULL,
PRIMARY KEY (`perm_user_id`,`perm_repo_uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `secrets` (
`secret_id` int(11) NOT NULL AUTO_INCREMENT,
`secret_repo_id` int(11) DEFAULT NULL,
`secret_name` varchar(500) DEFAULT NULL,
`secret_data` blob,
`secret_pull_request` tinyint(1) DEFAULT NULL,
`secret_pull_request_push` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`secret_id`),
UNIQUE KEY `secret_repo_id` (`secret_repo_id`,`secret_name`),
CONSTRAINT `secrets_ibfk_1` FOREIGN KEY (`secret_repo_id`) REFERENCES `repos` (`repo_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `stages` (
`stage_id` int(11) NOT NULL AUTO_INCREMENT,
`stage_repo_id` int(11) DEFAULT NULL,
`stage_build_id` int(11) DEFAULT NULL,
`stage_number` int(11) DEFAULT NULL,
`stage_name` varchar(100) DEFAULT NULL,
`stage_kind` varchar(50) DEFAULT NULL,
`stage_type` varchar(50) DEFAULT NULL,
`stage_status` varchar(50) DEFAULT NULL,
`stage_error` varchar(500) DEFAULT NULL,
`stage_errignore` tinyint(1) DEFAULT NULL,
`stage_exit_code` int(11) DEFAULT NULL,
`stage_limit` int(11) DEFAULT NULL,
`stage_os` varchar(50) DEFAULT NULL,
`stage_arch` varchar(50) DEFAULT NULL,
`stage_variant` varchar(10) DEFAULT NULL,
`stage_kernel` varchar(50) DEFAULT NULL,
`stage_machine` varchar(500) DEFAULT NULL,
`stage_started` int(11) DEFAULT NULL,
`stage_stopped` int(11) DEFAULT NULL,
`stage_created` int(11) DEFAULT NULL,
`stage_updated` int(11) DEFAULT NULL,
`stage_version` int(11) DEFAULT NULL,
`stage_on_success` tinyint(1) DEFAULT NULL,
`stage_on_failure` tinyint(1) DEFAULT NULL,
`stage_depends_on` text,
`stage_labels` text,
PRIMARY KEY (`stage_id`),
UNIQUE KEY `stage_build_id` (`stage_build_id`,`stage_number`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `stages_unfinished` (
`stage_id` int(11) NOT NULL,
PRIMARY KEY (`stage_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `steps` (
`step_id` int(11) NOT NULL AUTO_INCREMENT,
`step_stage_id` int(11) DEFAULT NULL,
`step_number` int(11) DEFAULT NULL,
`step_name` varchar(100) DEFAULT NULL,
`step_status` varchar(50) DEFAULT NULL,
`step_error` varchar(500) DEFAULT NULL,
`step_errignore` tinyint(1) DEFAULT NULL,
`step_exit_code` int(11) DEFAULT NULL,
`step_started` int(11) DEFAULT NULL,
`step_stopped` int(11) DEFAULT NULL,
`step_version` int(11) DEFAULT NULL,
PRIMARY KEY (`step_id`),
UNIQUE KEY `step_stage_id` (`step_stage_id`,`step_number`)
) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_login` varchar(250) DEFAULT NULL,
`user_email` varchar(500) DEFAULT NULL,
`user_admin` tinyint(1) DEFAULT NULL,
`user_machine` tinyint(1) DEFAULT NULL,
`user_active` tinyint(1) DEFAULT NULL,
`user_avatar` varchar(2000) DEFAULT NULL,
`user_syncing` tinyint(1) DEFAULT NULL,
`user_synced` int(11) DEFAULT NULL,
`user_created` int(11) DEFAULT NULL,
`user_updated` int(11) DEFAULT NULL,
`user_last_login` int(11) DEFAULT NULL,
`user_oauth_token` varchar(500) DEFAULT NULL,
`user_oauth_refresh` varchar(500) DEFAULT NULL,
`user_oauth_expiry` int(11) DEFAULT NULL,
`user_hash` varchar(500) DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_login` (`user_login`),
UNIQUE KEY `user_hash` (`user_hash`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
SQL
sqls
end
end
end

View File

@ -5,4 +5,5 @@ module CustomRegexp
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
URL = /\Ahttps?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]\z/
end
IP = /^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
end

View File

@ -0,0 +1,12 @@
module Gitea
class Database < ActiveRecord::Base
self.abstract_class = true
def self.set_connection
gitea_server_config = Rails.configuration.database_configuration[Rails.env]["gitea_server"]
raise 'gitea database config missing' if gitea_server_config.blank?
establish_connection gitea_server_config
end
end
end

View File

@ -1,5 +1,23 @@
# == Schema Information
#
# Table name: applied_messages
#
# id :integer not null, primary key
# user_id :integer
# applied_id :integer
# applied_type :string(255)
# viewed :integer default("0")
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# name :string(255)
# applied_user_id :integer
# role :integer
# project_id :integer
#
class AppliedMessage < ApplicationRecord
belongs_to :user
belongs_to :applied, polymorphic: true
end
end

View File

@ -1,3 +1,14 @@
# == Schema Information
#
# Table name: applied_projects
#
# id :integer not null, primary key
# project_id :integer not null
# user_id :integer not null
# role :integer default("0")
# status :integer default("0")
#
class AppliedProject < ApplicationRecord
belongs_to :user
belongs_to :project

View File

@ -1,3 +1,26 @@
# == Schema Information
#
# Table name: apply_actions
#
# id :integer not null, primary key
# user_id :integer
# reason :string(255)
# container_id :integer
# container_type :string(255)
# dealer_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# status :integer default("0")
# apply_reason :text(65535)
# noticed :boolean default("0")
# ip_addr :string(255)
# reject_description :string(255)
#
# Indexes
#
# index_apply_actions_on_user_id (user_id)
#
# 申请消息
class ApplyAction < ApplicationRecord
belongs_to :user
@ -27,4 +50,4 @@ class ApplyAction < ApplicationRecord
belong_container_id: container_id, belong_container_type: belong_container_type)
end
end
end
end

View File

@ -1,3 +1,23 @@
# == Schema Information
#
# Table name: apply_user_authentications
#
# id :integer not null, primary key
# user_id :integer
# status :integer
# auth_type :integer
# remarks :string(255)
# dealer :integer
# deal_time :datetime
# created_at :datetime not null
# updated_at :datetime not null
# is_delete :boolean default("0")
#
# Indexes
#
# index_apply_user_authentications_on_user_id (user_id)
#
# status0 审核中 1 同意 2 拒绝 3 撤销
# auth_type1 实名认证, 2 职业认证
class ApplyUserAuthentication < ApplicationRecord

View File

@ -1,3 +1,42 @@
# == Schema Information
#
# Table name: attachments
#
# id :integer not null, primary key
# container_id :integer
# container_type :string(30)
# filename :string(255) default(""), not null
# disk_filename :string(255) default(""), not null
# filesize :integer default("0"), not null
# content_type :string(255) default("")
# digest :string(60) default(""), not null
# downloads :integer default("0"), not null
# author_id :integer default("0"), not null
# created_on :datetime
# description :text(65535)
# disk_directory :string(255)
# attachtype :integer default("1")
# is_public :integer default("1")
# copy_from :integer
# quotes :integer default("0")
# is_publish :integer default("1")
# publish_time :datetime
# resource_bank_id :integer
# unified_setting :boolean default("1")
# cloud_url :string(255) default("")
# course_second_category_id :integer default("0")
# delay_publish :boolean default("0")
#
# Indexes
#
# index_attachments_on_author_id (author_id)
# index_attachments_on_container_id_and_container_type (container_id,container_type)
# index_attachments_on_course_second_category_id (course_second_category_id)
# index_attachments_on_created_on (created_on)
# index_attachments_on_is_public (is_public)
# index_attachments_on_quotes (quotes)
#
class Attachment < ApplicationRecord
include BaseModel
include Publicable

View File

@ -1,3 +1,22 @@
# == Schema Information
#
# Table name: attachment_group_settings
#
# id :integer not null, primary key
# attachment_id :integer
# course_group_id :integer
# course_id :integer
# publish_time :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_attachment_group_settings_on_attachment_id (attachment_id)
# index_attachment_group_settings_on_course_group_id (course_group_id)
# index_attachment_group_settings_on_course_id (course_id)
#
class AttachmentGroupSetting < ActiveRecord::Base
belongs_to :attachment
# belongs_to :course_group

View File

@ -1,3 +1,31 @@
# == Schema Information
#
# Table name: attachment_histories
#
# id :integer not null, primary key
# container_id :integer
# container_type :string(255)
# filename :string(255) default("")
# disk_filename :string(255) default("")
# filesize :integer default("0")
# content_type :string(255) default("")
# digest :string(60) default("")
# downloads :integer default("0")
# author_id :integer
# created_on :datetime
# description :text(65535)
# disk_directory :string(255)
# attachtype :integer
# is_public :integer
# copy_from :integer
# quotes :integer
# version :integer
# attachment_id :integer
# is_publish :integer default("1")
# publish_time :date
# cloud_url :string(255) default("")
#
class AttachmentHistory < ApplicationRecord
include Publishable
include Publicable

View File

@ -1,3 +1,20 @@
# == Schema Information
#
# Table name: bidding_users
#
# id :integer not null, primary key
# project_package_id :integer
# user_id :integer
# status :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_bidding_users_on_project_package_id (project_package_id)
# index_bidding_users_on_user_id (user_id)
#
class BiddingUser < ApplicationRecord
include AASM
@ -21,4 +38,4 @@ class BiddingUser < ApplicationRecord
def status_text
I18n.t("bidding_user.status.#{status}")
end
end
end

5
app/models/ci.rb Normal file
View File

@ -0,0 +1,5 @@
module Ci
# def self.table_name_prefix
# 'ci_'
# end
end

14
app/models/ci/build.rb Normal file
View File

@ -0,0 +1,14 @@
class Ci::Build < Ci::RemoteBase
self.primary_key = 'build_id'
belongs_to :repo, foreign_key: :build_repo_id
has_many :stages, foreign_key: "stage_build_id", dependent: :destroy
scope :successed, ->{ by_status('success') }
scope :failed, -> { by_status('failure') }
scope :running, -> { by_status('running') }
scope :errored, -> { by_status('error') }
scope :pending, -> { by_status('pending') }
scope :killed, -> { by_status('killed') }
scope :by_status, ->(status) { where(build_status: status) }
end

View File

@ -0,0 +1,47 @@
# == Schema Information
#
# Table name: ci_cloud_accounts
#
# id :integer not null, primary key
# user_id :integer not null
# ip_num :integer
# account :string(255)
# secret :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# ci_user_id :integer
#
# Indexes
#
# dev_ops_cloud_accounts_p_u_ip (user_id,ip_num)
#
class Ci::CloudAccount < Ci::LocalBase
belongs_to :user
belongs_to :ci_user, class_name: 'Ci::User', foreign_key: :ci_user_id, optional: true
def drone_host
[drone_ip, ":80"].join
end
def drone_ip
IPAddr.new(self.ip_num, Socket::AF_INET).to_s
end
def drone_url
["http://", self.drone_host].join
end
def visible_secret
Base64.decode64(secret)
end
def self.encrypted_secret(str)
Base64.encode64(str.strip).gsub(/\n/, '')
end
def authenticate_url
[drone_url, '/login'].join
end
end

28
app/models/ci/language.rb Normal file
View File

@ -0,0 +1,28 @@
# == Schema Information
#
# Table name: ci_languages
#
# id :integer not null, primary key
# name :string(255) not null
# content :text(65535) not null
# usage_amount :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# cover_id :integer
#
class Ci::Language < Ci::LocalBase
# before_save :encode_content
belongs_to :cover, class_name: "Attachment", foreign_key: :cover_id, optional: true
scope :six_common, -> { limit(6).by_usage_amount_desc }
scope :without_content, -> { select(column_names - ['content']) }
scope :by_usage_amount_desc, -> { order(usage_amount: :desc) }
private
def encode_content
self.content = Base64.encode64 content
end
end

View File

@ -0,0 +1,7 @@
class Ci::LocalBase < ApplicationRecord
self.abstract_class = true
def self.table_name_prefix
"ci_"
end
end

5
app/models/ci/log.rb Normal file
View File

@ -0,0 +1,5 @@
class Ci::Log < Ci::RemoteBase
self.primary_key = nil
belongs_to :step, class_name: 'Ci::Step', foreign_key: :log_id
end

20
app/models/ci/perm.rb Normal file
View File

@ -0,0 +1,20 @@
class Ci::Perm < Ci::RemoteBase
self.primary_key = nil
belongs_to :user, class_name: 'Ci::User', foreign_key: :perm_user_id
belongs_to :repo, class_name: 'Ci::Repo', foreign_key: :perm_repo_uid
def self.auto_create!(user, repo)
perm = new(
perm_user_id: user.user_id,
perm_repo_uid: repo.repo_id,
perm_read: true,
perm_write: true,
perm_admin: true,
perm_synced: 0,
perm_created: Time.now.to_i,
perm_updated: Time.now.to_i
)
perm.save!
end
end

View File

@ -0,0 +1,8 @@
class Ci::RemoteBase < Ci::Database
self.abstract_class = true
def generate_code
[*'a'..'z',*'0'..'9',*'A'..'Z'].sample(32).join
end
end

64
app/models/ci/repo.rb Normal file
View File

@ -0,0 +1,64 @@
class Ci::Repo < Ci::RemoteBase
self.primary_key = 'repo_id'
belongs_to :user, foreign_key: :repo_user_id
has_one :perm, foreign_key: :perm_repo_uid
has_many :builds, foreign_key: :build_repo_id, dependent: :destroy
def self.find_with_namespace(namespace_path, identifier)
logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} "
user = Ci::User.find_by_user_login namespace_path
repo = Ci::Repo.where(repo_namespace: namespace_path, repo_name: identifier).first
[user, repo]
end
def activate!(ci_user_id)
update(repo_active: 1,
repo_signer: generate_code,
repo_secret: generate_code,
repo_user_id: ci_user_id,
repo_timeout: 60,
repo_config: '.trustie-pipeline.yml',
repo_updated: Time.now.to_i)
end
def self.auto_create!(user, project)
repo = new(
repo_user_id: user.user_id,
repo_namespace: project.owner.login,
repo_name: project.identifier,
repo_slug: "#{project.owner.login}/#{project.identifier}",
repo_scm: "git",
repo_ssh_url: "",
repo_html_url: "",
repo_clone_url: project.repository.url,
repo_active: 1,
repo_private: true,
repo_visibility: 'private',
repo_branch: 'master',
repo_counter: 0,
repo_trusted: false,
repo_protected: false,
repo_synced: 0,
repo_version: 1,
repo_timeout: 60,
repo_config: '.trustie-pipeline.yml',
repo_created: Time.now.to_i,
repo_updated: Time.now.to_i
)
repo.repo_signer = repo.generate_code
repo.repo_secret = repo.generate_code
if repo.save!
Ci::Perm.auto_create!(user, repo)
repo.update_column(:repo_uid, repo.id)
repo
end
end
def deactivate!
update_column(:repo_active, 0)
end
end

6
app/models/ci/stage.rb Normal file
View File

@ -0,0 +1,6 @@
class Ci::Stage < Ci::RemoteBase
self.primary_key = 'stage_id'
belongs_to :build, foreign_key: :stage_build_id
has_many :steps, foreign_key: "step_stage_id", dependent: :destroy
end

6
app/models/ci/step.rb Normal file
View File

@ -0,0 +1,6 @@
class Ci::Step < Ci::RemoteBase
self.primary_key = 'step_id'
belongs_to :stage, foreign_key: :step_stage_id
has_one :log, class_name: 'Ci::Log', foreign_key: :log_id
end

68
app/models/ci/user.rb Normal file
View File

@ -0,0 +1,68 @@
# == Schema Information
#
# Table name: users
#
# id :integer not null
# login :string(255) default(""), not null
# hashed_password :string(40) default(""), not null
# firstname :string(30) default(""), not null
# lastname :string(255) default(""), not null
# mail :string(60)
# admin :boolean default("0"), not null
# status :integer default("1"), not null
# last_login_on :datetime
# language :string(5) default("")
# auth_source_id :integer
# created_on :datetime
# updated_on :datetime
# type :string(255)
# identity_url :string(255)
# mail_notification :string(255) default(""), not null
# salt :string(64)
# gid :integer
# visits :integer default("0")
# excellent_teacher :integer default("0")
# excellent_student :integer default("0")
# phone :string(255)
# authentication :boolean default("0")
# grade :integer default("0")
# experience :integer default("0")
# nickname :string(255)
# show_realname :boolean default("1")
# professional_certification :boolean default("0")
# ID_number :string(255)
# certification :integer default("0")
# homepage_teacher :boolean default("0")
# homepage_engineer :boolean default("0")
# is_test :integer default("0")
# ecoder_user_id :integer default("0")
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
#
# Indexes
#
# index_users_on_ecoder_user_id (ecoder_user_id)
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#
class Ci::User < Ci::RemoteBase
self.primary_key = 'user_id'
has_many :repos, foreign_key: :repo_user_id, dependent: :destroy
has_many :perms, foreign_key: :perm_user_id, dependent: :delete_all
has_one :ci_cloud_account, class_name: 'Ci::CloudAccount', foreign_key: :ci_user_id
end

View File

@ -1,3 +1,23 @@
# == Schema Information
#
# Table name: composes
#
# id :integer not null, primary key
# user_id :integer
# title :string(255)
# description :text(65535)
# show_mode :integer default("0")
# compose_mode :boolean default("0")
# compose_users_count :integer default("0")
# compose_projects_count :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_composes_on_user_id_and_show_mode_and_compose_mode (user_id,show_mode,compose_mode)
#
class Compose < ApplicationRecord
#组织
belongs_to :user

View File

@ -1,3 +1,20 @@
# == Schema Information
#
# Table name: compose_projects
#
# id :integer not null, primary key
# user_id :integer
# project_id :integer
# compose_id :integer
# position :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_compose_projects_on_user_id_and_project_id_and_compose_id (user_id,project_id,compose_id)
#
class ComposeProject < ApplicationRecord
#组织的项目记录表
belongs_to :compose

View File

@ -1,3 +1,19 @@
# == Schema Information
#
# Table name: compose_users
#
# id :integer not null, primary key
# user_id :integer
# compose_id :integer
# is_manager :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_compose_users_on_user_id_and_compose_id (user_id,compose_id)
#
class ComposeUser < ApplicationRecord
belongs_to :compose
belongs_to :user

View File

@ -0,0 +1,46 @@
module Droneable
extend ActiveSupport::Concern
included do
end
def devops_uninit?
self.devops_step === User::DEVOPS_UNINIT
end
def devops_unverified?
self.devops_step === User::DEVOPS_UNVERIFIED
end
def devops_certification?
self.devops_step === User::DEVOPS_CERTIFICATION
end
def set_drone_step!(step)
self.update_column(:devops_step, step)
end
def ci_certification?
return false if self.is_a?(AnonymousUser)
devops_certification? && Ci::User.exists?(user_login: self.login)
end
def unbind_account!
user_projects = self.projects
user_projects.update_all(open_devops: false, open_devops_count: 0)
set_drone_step!(User::DEVOPS_UNINIT)
# TODO
# 删除用户项目下的与ci相关的所有webhook
user_projects.select(:id, :identifier, :gitea_webhook_id).each do |project|
if project.gitea_webhook_id
result = Gitea::Hooks::DestroyService.call(self.gitea_token, self.login, project.identifier, project.gitea_webhook_id)
project.update_column(:gitea_webhook_id, nil) if result.status == 204
end
end
end
module ClassMethods
end
end

View File

@ -5,6 +5,7 @@ module Matchable
scope :with_project_category, ->(category_id) { where(project_category_id: category_id) unless category_id.blank? }
scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? }
scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) }
scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "#{search.split(" ").join('|')}%") unless search.blank? }
end
end

View File

@ -7,6 +7,7 @@ module ProjectOperable
has_many :managers, -> { joins(:roles).where(roles: { name: 'Manager' }) }, class_name: 'Member'
has_many :developers, -> { joins(:roles).where(roles: { name: 'Developer' }) }, class_name: 'Member'
has_many :reporters, -> { joins(:roles).where(roles: { name: 'Reporter' }) }, class_name: 'Member'
has_many :writable_members, -> { joins(:roles).where.not(roles: {name: 'Reporter'}) }, class_name: 'Member'
end
def add_member!(user_id, role_name='Developer')

View File

@ -1,5 +1,18 @@
# == Schema Information
#
# Table name: coo_imgs
#
# id :integer not null, primary key
# src_states :string(255)
# url_states :string(255)
# img_type :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# position :integer
#
class CooImg < ApplicationRecord
extend Enumerize
enumerize :img_type, in: %i[com_coop edu_coop alliance_coop]
end
end

View File

@ -1,3 +1,21 @@
# == Schema Information
#
# Table name: diff_records
#
# id :integer not null, primary key
# user_id :integer
# container_type :string(255)
# container_id :integer
# column_name :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_diff_records_on_container_type_and_container_id (container_type,container_id)
# index_diff_records_on_user_id (user_id)
#
class DiffRecord < ApplicationRecord
belongs_to :user
belongs_to :container, polymorphic: true
@ -5,4 +23,4 @@ class DiffRecord < ApplicationRecord
has_one :diff_record_content, dependent: :destroy
delegate :content, to: :diff_record_content
end
end

View File

@ -1,3 +1,16 @@
# == Schema Information
#
# Table name: diff_record_contents
#
# id :integer not null, primary key
# diff_record_id :integer
# content :text(65535)
#
# Indexes
#
# index_diff_record_contents_on_diff_record_id (diff_record_id)
#
class DiffRecordContent < ApplicationRecord
belongs_to :diff_record
end
end

View File

@ -1,3 +1,19 @@
# == Schema Information
#
# Table name: edu_settings
#
# id :integer not null, primary key
# name :string(255)
# value :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# description :string(255)
#
# Indexes
#
# index_edu_settings_on_name (name) UNIQUE
#
class EduSetting < ApplicationRecord
after_commit :expire_value_cache

View File

@ -1,4 +1,23 @@
# == Schema Information
#
# Table name: fork_users
#
# id :integer not null, primary key
# project_id :integer
# fork_project_id :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_fork_users_on_project_id (project_id)
# index_fork_users_on_user_id (user_id)
#
class ForkUser < ApplicationRecord
belongs_to :project
belongs_to :project
belongs_to :user
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
end

4
app/models/gitea/base.rb Normal file
View File

@ -0,0 +1,4 @@
class Gitea::Base < Gitea::Database
self.abstract_class = true
end

View File

@ -1,3 +1,14 @@
# == Schema Information
#
# Table name: ignores
#
# id :integer not null, primary key
# name :string(255)
# content :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
#
class Ignore < ApplicationRecord
include Projectable
end

View File

@ -1,3 +1,53 @@
# == Schema Information
#
# Table name: issues
#
# id :integer not null, primary key
# tracker_id :integer not null
# project_id :integer not null
# subject :string(255) default(""), not null
# description :text(4294967295)
# due_date :date
# category_id :integer
# status_id :integer not null
# assigned_to_id :integer
# priority_id :integer not null
# fixed_version_id :integer
# author_id :integer not null
# created_on :datetime
# updated_on :datetime
# start_date :date
# done_ratio :integer default("0"), not null
# estimated_hours :float(24)
# parent_id :integer
# root_id :integer
# lft :integer
# rgt :integer
# is_private :boolean default("0"), not null
# closed_on :datetime
# project_issues_index :integer
# issue_type :string(255)
# token :integer default("0")
# issue_tags_value :string(255)
# is_lock :boolean default("0")
# issue_classify :string(255)
# ref_name :string(255)
# branch_name :string(255)
#
# Indexes
#
# index_issues_on_assigned_to_id (assigned_to_id)
# index_issues_on_author_id (author_id)
# index_issues_on_category_id (category_id)
# index_issues_on_created_on (created_on)
# index_issues_on_fixed_version_id (fixed_version_id)
# index_issues_on_priority_id (priority_id)
# index_issues_on_root_id_and_lft_and_rgt (root_id,lft,rgt)
# index_issues_on_status_id (status_id)
# index_issues_on_tracker_id (tracker_id)
# issues_project_id (project_id)
#
class Issue < ApplicationRecord
#issue_type 1为普通2为悬赏
include DunCheckAble

View File

@ -1,3 +1,19 @@
# == Schema Information
#
# Table name: issue_depends
#
# id :integer not null, primary key
# user_id :integer
# issue_id :integer
# depend_issue_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_issue_depends_on_user_id_and_issue_id_and_depend_issue_id (user_id,issue_id,depend_issue_id)
#
class IssueDepend < ApplicationRecord
belongs_to :issue
end

View File

@ -1,3 +1,18 @@
# == Schema Information
#
# Table name: issue_priorities
#
# id :integer not null, primary key
# name :string(255)
# position :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_issue_priorities_on_name (name)
#
class IssuePriority < ApplicationRecord
has_many :issues
end
end

View File

@ -1,4 +1,22 @@
# == Schema Information
#
# Table name: issue_statuses
#
# id :integer not null, primary key
# name :string(30) default(""), not null
# is_closed :boolean default("0"), not null
# is_default :boolean default("0"), not null
# position :integer default("1")
# default_done_ratio :integer
#
# Indexes
#
# index_issue_statuses_on_is_closed (is_closed)
# index_issue_statuses_on_is_default (is_default)
# index_issue_statuses_on_position (position)
#
class IssueStatus < ApplicationRecord
has_many :issues
belongs_to :project, optional: true
end
end

View File

@ -1,3 +1,24 @@
# == Schema Information
#
# Table name: issue_tags
#
# id :integer not null, primary key
# name :string(255)
# description :string(255)
# color :string(255)
# user_id :integer
# project_id :integer
# issues_count :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# gid :integer
# gitea_url :string(255)
#
# Indexes
#
# index_issue_tags_on_user_id_and_name_and_project_id (user_id,name,project_id)
#
class IssueTag < ApplicationRecord
has_many :issue_tags_relates, dependent: :destroy

View File

@ -1,3 +1,18 @@
# == Schema Information
#
# Table name: issue_tags_relates
#
# id :integer not null, primary key
# issue_id :integer
# issue_tag_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_issue_tags_relates_on_issue_id_and_issue_tag_id (issue_id,issue_tag_id)
#
class IssueTagsRelate < ApplicationRecord
belongs_to :issue
belongs_to :issue_tag, counter_cache: :issues_count

Some files were not shown because too many files have changed in this diff Show More