| @@ -66,6 +66,7 @@ vendor/bundle/ | |||
| /Users | |||
| /files | |||
| /public/images/avatars | |||
| /public/cache_repository | |||
| /public/files | |||
| /workspace | |||
| /log | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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) | |||
| @@ -139,9 +135,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) | |||
| @@ -178,9 +171,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) | |||
| @@ -405,8 +395,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) | |||
| @@ -442,6 +430,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) | |||
| @@ -457,7 +446,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) | |||
| @@ -509,8 +497,5 @@ DEPENDENCIES | |||
| whenever | |||
| wkhtmltopdf-binary | |||
| RUBY VERSION | |||
| ruby 2.3.7p456 | |||
| BUNDLED WITH | |||
| 2.1.4 | |||
| @@ -0,0 +1,78 @@ | |||
| html{margin:0px;padding: 0px;font-size: 14px;font-family: "微软雅黑","宋体";} | |||
| body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { | |||
| margin: 0; | |||
| padding: 0; | |||
| } | |||
| .IndexContent{ | |||
| height: 100vh; | |||
| width: 100%; | |||
| position: relative; | |||
| background-image: url('/images/oauth/backImg.png'); | |||
| background-repeat: no-repeat; | |||
| background-size: cover; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| flex-direction: column; | |||
| } | |||
| .indexLogo{ | |||
| width:80px; | |||
| margin-bottom: 35px; | |||
| } | |||
| .indexPanel{ | |||
| width: 580px; | |||
| min-height: 400px; | |||
| background-color: #fff; | |||
| box-shadow: 0px 2px 10px 5px rgba(0,0,0,0.05); | |||
| border-radius: 5px; | |||
| box-sizing: border-box; | |||
| } | |||
| .indexTitle{ | |||
| height: 75px; | |||
| line-height: 75px; | |||
| font-size: 18px; | |||
| color:#333; | |||
| text-align: center; | |||
| border-bottom: 1px solid #eee; | |||
| } | |||
| .indexInfo{ | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: flex-start; | |||
| } | |||
| .indexInfos{ | |||
| padding:40px 60px; | |||
| } | |||
| .indexInfo > span{ | |||
| color: #333; | |||
| font-size: 16px; | |||
| margin-top: 5px; | |||
| } | |||
| .indexInfo input{ | |||
| width: 100%; | |||
| height:40px; | |||
| border-radius: 2px; | |||
| border:1px solid #eee; | |||
| margin-top: 5px; | |||
| padding:0px 0px 0px 8px; | |||
| outline: none; | |||
| } | |||
| .indexInfo .checkInfo{ | |||
| height: 15px; | |||
| color: red; | |||
| } | |||
| .indexBtn{ | |||
| text-align: center; | |||
| margin-top: 20px; | |||
| } | |||
| .indexSubmit{ | |||
| width: 50%; | |||
| height: 32px; | |||
| line-height: 32px; | |||
| background-color: #1890FF; | |||
| border:none; | |||
| color: #fff; | |||
| border-radius: 2px; | |||
| cursor: pointer; | |||
| outline: none; | |||
| } | |||
| @@ -9,8 +9,9 @@ module ApplicationCable | |||
| private | |||
| def find_verified_user | |||
| puts "############### cookies.signed[:signed_user_id]: #{cookies.signed[:user_id]}" | |||
| puts "############### cookies.signed[:user_id]: #{cookies.signed[:user_id]}" | |||
| if current_user = User.find_by(id: cookies.signed[:user_id]) | |||
| puts "############### find_verified_user success! ###############" | |||
| current_user | |||
| else | |||
| reject_unauthorized_connection | |||
| @@ -1,7 +1,6 @@ | |||
| class MirrorProjectChannel < ApplicationCable::Channel | |||
| def subscribed | |||
| Rails.logger.info "################### channel params: #{params}" | |||
| # @project = Project.find_by_identifier params[:id] | |||
| stream_from "channel_room_#{params[:id]}" | |||
| end | |||
| @@ -13,25 +13,12 @@ class AccountsController < ApplicationController | |||
| password = params[:password] | |||
| platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") | |||
| @user = User.new(admin: false, login: username, mail: email, type: "User") | |||
| @user.password = password | |||
| @user.platform = platform | |||
| @user.activate | |||
| ActiveRecord::Base.transaction do | |||
| interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | |||
| if interactor.success? | |||
| gitea_user = interactor.result | |||
| result = Gitea::User::GenerateTokenService.new(username, password).call | |||
| @user.gitea_token = result['sha1'] | |||
| @user.gitea_uid = gitea_user['id'] | |||
| if @user.save! | |||
| UserExtension.create!(user_id: @user.id) | |||
| @user.create_wallet(balance: 0) | |||
| render_ok({user: {id: @user.id, token: @user.gitea_token}}) | |||
| end | |||
| result = autologin_register(username, email, password, platform) | |||
| if result[:message].blank? | |||
| render_ok({user: result[:user]}) | |||
| else | |||
| render_error(interactor.error) | |||
| render_error(result[:message]) | |||
| end | |||
| end | |||
| rescue Exception => e | |||
| @@ -67,8 +54,8 @@ class AccountsController < ApplicationController | |||
| sync_params = {} | |||
| if (user_params["mail"] && user_params["mail"] != user_mail) || (user_params["login"] && user_params["login"] != params[:old_user_login]) | |||
| sync_params = sync_params.merge(email: user_params["mail"], login_name: user_params["login"], full_name: user_params["login"]) | |||
| if (user_params["mail"] && user_params["mail"] != user_mail) | |||
| sync_params = sync_params.merge(email: user_params["mail"]) | |||
| end | |||
| if sync_params.present? | |||
| @@ -123,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 | |||
| @@ -159,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) | |||
| @@ -259,6 +243,8 @@ class AccountsController < ApplicationController | |||
| def set_autologin_cookie(user) | |||
| token = Token.get_or_create_permanent_login_token(user, "autologin") | |||
| sync_user_token_to_trustie(user.login, token.value) | |||
| cookie_options = { | |||
| :value => token.value, | |||
| :expires => 1.month.from_now, | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -1,372 +1,374 @@ | |||
| require 'oauth2' | |||
| class ApplicationController < ActionController::Base | |||
| include CodeExample | |||
| include RenderExpand | |||
| include RenderHelper | |||
| include ControllerRescueHandler | |||
| include LaboratoryHelper | |||
| include GitHelper | |||
| include LoggerHelper | |||
| include LoginHelper | |||
| include UpdateHelper | |||
| protect_from_forgery prepend: true, unless: -> { request.format.json? } | |||
| before_action :check_sign | |||
| before_action :user_setup | |||
| #before_action :check_account | |||
| include CodeExample | |||
| include RenderExpand | |||
| include RenderHelper | |||
| include ControllerRescueHandler | |||
| include LaboratoryHelper | |||
| include GitHelper | |||
| include LoggerHelper | |||
| include LoginHelper | |||
| include RegisterHelper | |||
| protect_from_forgery prepend: true, unless: -> { request.format.json? } | |||
| before_action :check_sign | |||
| before_action :user_setup | |||
| #before_action :check_account | |||
| after_action :user_trace_log | |||
| # TODO | |||
| # check sql query time | |||
| before_action do | |||
| # TODO | |||
| # check sql query time | |||
| before_action do | |||
| if request.subdomain === 'testforgeplus' || request.subdomain === "profiler" | |||
| Rack::MiniProfiler.authorize_request | |||
| end | |||
| end | |||
| DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) | |||
| OPENKEY = "79e33abd4b6588941ab7622aed1e67e8" | |||
| helper_method :current_user | |||
| # 所有请求必须合法签名 | |||
| def check_sign | |||
| # if !Rails.env.development? | |||
| # Rails.logger.info("66666 #{params}") | |||
| # # suffix = request.url.split(".").last.split("?").first | |||
| # # suffix_arr = ["xls", "xlsx", "pdf", "zip"] # excel文件先注释 | |||
| # # unless suffix_arr.include?(suffix) | |||
| # if params[:client_key].present? | |||
| # randomcode = params[:randomcode] | |||
| # # tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5) | |||
| # | |||
| # sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}") | |||
| # Rails.logger.info("2222 #{sign}") | |||
| # tip_exception(501, "请求不合理") if sign != params[:client_key] | |||
| # else | |||
| # tip_exception(501, "请求不合理") | |||
| # end | |||
| # # end | |||
| # end | |||
| end | |||
| # 全局配置参数 | |||
| # 返回name对应的value | |||
| def edu_setting(name) | |||
| EduSetting.get(name) | |||
| end | |||
| # 平台身份权限判断(学生用户无权限) | |||
| def identity_auth | |||
| ue = current_user.user_extension | |||
| tip_exception(403, "..") unless current_user.admin_or_business? || ue.teacher? || ue.professional? | |||
| end | |||
| # 平台已认证身份判断(已认证的老师和专业人士) | |||
| def certi_identity_auth | |||
| ue = current_user.user_extension | |||
| tip_exception(403, "..") unless current_user.admin_or_business? || | |||
| (current_user.professional_certification && (ue.teacher? || ue.professional?)) | |||
| end | |||
| def shixun_marker | |||
| unless current_user.is_shixun_marker? || current_user.admin_or_business? | |||
| tip_exception(403, "..") | |||
| end | |||
| end | |||
| # 实训的访问权限 | |||
| def shixun_access_allowed | |||
| if !current_user.shixun_permission(@shixun) | |||
| tip_exception(403, "..") | |||
| end | |||
| end | |||
| def admin_or_business? | |||
| User.current.admin? || User.current.business? | |||
| end | |||
| # 访问课堂时没权限直接弹加入课堂的弹框 :409 | |||
| def user_course_identity | |||
| @user_course_identity = current_user.course_identity(@course) | |||
| if @user_course_identity > Course::STUDENT && @course.is_public == 0 | |||
| tip_exception(401, "..") unless User.current.logged? | |||
| check_account | |||
| tip_exception(@course.excellent ? 410 : 409, "您没有权限进入") | |||
| end | |||
| if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id | |||
| # 实名认证和职业认证的身份判断 | |||
| tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication && | |||
| @course.professional_certification && (!current_user.authentication && !current_user.professional_certification) | |||
| tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication | |||
| tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification | |||
| end | |||
| uid_logger("###############user_course_identity:#{@user_course_identity}") | |||
| end | |||
| # 题库的访问权限 | |||
| def bank_visit_auth | |||
| tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public | |||
| tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? || | |||
| (current_user.certification_teacher? && @bank.is_public) | |||
| end | |||
| # 判断用户的邮箱或者手机是否可用 | |||
| # params[:type] 1: 注册;2:忘记密码;3:绑定 | |||
| def check_mail_and_phone_valid login, type | |||
| unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || | |||
| login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ | |||
| tip_exception(-2, "请输入正确的手机号或邮箱") | |||
| end | |||
| # 考虑到安全参数问题,多一次查询,去掉Union | |||
| user = User.where(phone: login).first || User.where(mail: login).first | |||
| if type.to_i == 1 && !user.nil? | |||
| tip_exception(-2, "该手机号码或邮箱已被注册") | |||
| elsif type.to_i == 2 && user.nil? | |||
| tip_exception(-2, "该手机号码或邮箱未注册") | |||
| elsif type.to_i == 3 && user.present? | |||
| tip_exception(-2, "该手机号码或邮箱已绑定") | |||
| end | |||
| sucess_status | |||
| end | |||
| # 发送及记录激活码 | |||
| # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 | |||
| # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9:验证手机号有效 | |||
| def check_verification_code(code, send_type, value) | |||
| case send_type | |||
| when 1, 2, 4, 9 | |||
| # 手机类型的发送 | |||
| sigle_para = {phone: value} | |||
| status = Educoder::Sms.send(mobile: value, code: code) | |||
| tip_exception(-2, code_msg(status)) if status != 0 | |||
| when 8, 3, 5 | |||
| # 邮箱类型的发送 | |||
| sigle_para = {email: value} | |||
| # 60s内不能重复发送 | |||
| send_email_limit_cache_key = "send_email_60_second_limit:#{value}" | |||
| tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) | |||
| # 短时间内不能大量发送 | |||
| send_email_control = LimitForbidControl::SendEmailCode.new(value) | |||
| tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? | |||
| begin | |||
| UserMailer.register_email(value, code).deliver_now | |||
| Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) | |||
| send_email_control.increment! | |||
| # Mailer.run.email_register(code, value) | |||
| rescue Exception => e | |||
| logger_error(e) | |||
| tip_exception(-2,"邮件发送失败,请稍后重试") | |||
| end | |||
| end | |||
| ver_params = {code_type: send_type, code: code}.merge(sigle_para) | |||
| VerificationCode.create!(ver_params) | |||
| end | |||
| def code_msg status | |||
| case status | |||
| when 0 | |||
| "验证码已经发送到您的手机,请注意查收" | |||
| when 8 | |||
| "同一手机号30秒内重复提交相同的内容" | |||
| when 9 | |||
| "同一手机号5分钟内重复提交相同的内容超过3次" | |||
| when 22 | |||
| "1小时内同一手机号发送次数超过限制" | |||
| when 33 | |||
| "验证码发送次数超过频率" | |||
| when 43 | |||
| "一天内同一手机号发送次数超过限制" | |||
| when 53 | |||
| "手机号接收超过频率限制" | |||
| end | |||
| end | |||
| def find_course | |||
| return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? | |||
| @course = Course.find(params[:course_id]) | |||
| tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business? | |||
| rescue Exception => e | |||
| tip_exception(e.message) | |||
| end | |||
| def course_manager | |||
| return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR | |||
| end | |||
| def find_board | |||
| return normal_status(2, "缺少board_id参数") if params[:board_id].blank? | |||
| @board = Board.find(params[:board_id]) | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def validate_type(object_type) | |||
| normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) | |||
| end | |||
| def set_pagination | |||
| @page = params[:page] || 1 | |||
| @page_size = params[:page_size] || 15 | |||
| end | |||
| # 课堂教师权限 | |||
| def teacher_allowed | |||
| logger.info("#####identity: #{current_user.course_identity(@course)}") | |||
| unless current_user.course_identity(@course) < Course::STUDENT | |||
| normal_status(403, "") | |||
| end | |||
| end | |||
| # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) | |||
| def teacher_or_admin_allowed | |||
| unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR | |||
| normal_status(403, "") | |||
| end | |||
| end | |||
| def require_admin | |||
| normal_status(403, "") unless User.current.admin? | |||
| end | |||
| def require_business | |||
| normal_status(403, "") unless admin_or_business? | |||
| end | |||
| # 前端会捕捉401,弹登录弹框 | |||
| # 未授权的捕捉407,弹试用申请弹框 | |||
| def require_login | |||
| #6.13 -hs | |||
| tip_exception(401, "请登录后再操作") unless User.current.logged? | |||
| end | |||
| # 异常提醒 | |||
| def tip_exception(status = -1, message) | |||
| raise Educoder::TipException.new(status, message) | |||
| end | |||
| def missing_template | |||
| tip_exception(404, "...") | |||
| end | |||
| # 弹框提醒 | |||
| def tip_show_exception(status = -2, message) | |||
| raise Educoder::TipException.new(status, message) | |||
| end | |||
| def normal_status(status = 0, message) | |||
| case status | |||
| when 403 | |||
| message = "您没有权限进行该操作" | |||
| when 404 | |||
| message = "您访问的页面不存在或已被删除" | |||
| end | |||
| render :json => { status: status, message: message } | |||
| end | |||
| # 资料是否完善 | |||
| def check_account | |||
| if !current_user.profile_completed? | |||
| #info_url = '/account/profile' | |||
| tip_exception(402, nil) | |||
| end | |||
| end | |||
| # 系统全局认证(暂时隐藏试用申请的判断) | |||
| def check_auth | |||
| # day_cer = UserDayCertification.find_by(user_id: current_user.id) | |||
| # # 如果注册超过24小时则需要完善资料及授权 | |||
| # if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 | |||
| # if !current_user.profile_completed? | |||
| # info_url = '/account/profile' | |||
| # tip_exception(402, info_url) | |||
| # elsif current_user.certification != 1 | |||
| # if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) | |||
| # tip_exception(408, "您的试用申请正在审核中,请耐心等待") | |||
| # end | |||
| # tip_exception(407, "系统未授权") | |||
| # end | |||
| # end | |||
| # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) | |||
| # tip_exception(408, "您的试用申请正在审核中,请耐心等待") | |||
| # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 | |||
| # if !current_user.profile_completed? | |||
| # info_url = '/account/profile' | |||
| # tip_exception(402, info_url) | |||
| # elsif current_user.certification != 1 | |||
| # day_cer = UserDayCertification.find_by(user_id: current_user.id) | |||
| # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 | |||
| # end | |||
| # end | |||
| end | |||
| def user_setup | |||
| # # reacct静态资源加载不需要走这一步 | |||
| #return if params[:controller] == "main" | |||
| # Find the current user | |||
| #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") | |||
| User.current = find_current_user | |||
| uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) | |||
| # 开放课程通过链接访问的用户 | |||
| if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank? | |||
| content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}" | |||
| if Digest::MD5.hexdigest(content) == params[:chinaoocKey] | |||
| user = open_class_user | |||
| if user | |||
| start_user_session(user) | |||
| set_autologin_cookie(user) | |||
| end | |||
| User.current = user | |||
| end | |||
| end | |||
| # if !User.current.logged? && Rails.env.development? | |||
| # User.current = User.find 1 | |||
| # end | |||
| # 测试版前端需求 | |||
| logger.info("subdomain:#{request.subdomain}") | |||
| if request.subdomain != "www" | |||
| if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 | |||
| User.current = User.find 81403 | |||
| elsif params[:debug] == 'student' | |||
| User.current = User.find 8686 | |||
| elsif params[:debug] == 'admin' | |||
| user = User.find 4 | |||
| User.current = user | |||
| cookies.signed[:user_id] = user.id | |||
| end | |||
| end | |||
| # User.current = User.find 81403 | |||
| end | |||
| # Returns the current user or nil if no user is logged in | |||
| # and starts a session if needed | |||
| def find_current_user | |||
| uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") | |||
| uid_logger("0000000000000user setup start: default_yun_session is #{default_yun_session}, session[:current_user_id] is #{session[:"#{default_yun_session}"]}") | |||
| current_domain_session = session[:"#{default_yun_session}"] | |||
| if current_domain_session | |||
| # existing session | |||
| User.current = (User.active.find(current_domain_session) rescue nil) | |||
| elsif autologin_user = try_to_autologin | |||
| autologin_user | |||
| elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? | |||
| # RSS key authentication does not start a session | |||
| User.find_by_rss_key(params[:key]) | |||
| end | |||
| DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) | |||
| OPENKEY = "79e33abd4b6588941ab7622aed1e67e8" | |||
| helper_method :current_user | |||
| # 所有请求必须合法签名 | |||
| def check_sign | |||
| # if !Rails.env.development? | |||
| # Rails.logger.info("66666 #{params}") | |||
| # # suffix = request.url.split(".").last.split("?").first | |||
| # # suffix_arr = ["xls", "xlsx", "pdf", "zip"] # excel文件先注释 | |||
| # # unless suffix_arr.include?(suffix) | |||
| # if params[:client_key].present? | |||
| # randomcode = params[:randomcode] | |||
| # # tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5) | |||
| # | |||
| # sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}") | |||
| # Rails.logger.info("2222 #{sign}") | |||
| # tip_exception(501, "请求不合理") if sign != params[:client_key] | |||
| # else | |||
| # tip_exception(501, "请求不合理") | |||
| # end | |||
| # # end | |||
| # end | |||
| end | |||
| # 全局配置参数 | |||
| # 返回name对应的value | |||
| def edu_setting(name) | |||
| EduSetting.get(name) | |||
| end | |||
| # 平台身份权限判断(学生用户无权限) | |||
| def identity_auth | |||
| ue = current_user.user_extension | |||
| tip_exception(403, "..") unless current_user.admin_or_business? || ue.teacher? || ue.professional? | |||
| end | |||
| # 平台已认证身份判断(已认证的老师和专业人士) | |||
| def certi_identity_auth | |||
| ue = current_user.user_extension | |||
| tip_exception(403, "..") unless current_user.admin_or_business? || | |||
| (current_user.professional_certification && (ue.teacher? || ue.professional?)) | |||
| end | |||
| def shixun_marker | |||
| unless current_user.is_shixun_marker? || current_user.admin_or_business? | |||
| tip_exception(403, "..") | |||
| end | |||
| end | |||
| # 实训的访问权限 | |||
| def shixun_access_allowed | |||
| if !current_user.shixun_permission(@shixun) | |||
| tip_exception(403, "..") | |||
| end | |||
| end | |||
| def admin_or_business? | |||
| User.current.admin? || User.current.business? | |||
| end | |||
| # 访问课堂时没权限直接弹加入课堂的弹框 :409 | |||
| def user_course_identity | |||
| @user_course_identity = current_user.course_identity(@course) | |||
| if @user_course_identity > Course::STUDENT && @course.is_public == 0 | |||
| tip_exception(401, "..") unless User.current.logged? | |||
| check_account | |||
| tip_exception(@course.excellent ? 410 : 409, "您没有权限进入") | |||
| end | |||
| if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id | |||
| # 实名认证和职业认证的身份判断 | |||
| tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication && | |||
| @course.professional_certification && (!current_user.authentication && !current_user.professional_certification) | |||
| tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication | |||
| tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification | |||
| end | |||
| uid_logger("###############user_course_identity:#{@user_course_identity}") | |||
| end | |||
| # 题库的访问权限 | |||
| def bank_visit_auth | |||
| tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public | |||
| tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? || | |||
| (current_user.certification_teacher? && @bank.is_public) | |||
| end | |||
| # 判断用户的邮箱或者手机是否可用 | |||
| # params[:type] 1: 注册;2:忘记密码;3:绑定 | |||
| def check_mail_and_phone_valid login, type | |||
| unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || | |||
| login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ | |||
| tip_exception(-2, "请输入正确的手机号或邮箱") | |||
| end | |||
| # 考虑到安全参数问题,多一次查询,去掉Union | |||
| user = User.where(phone: login).first || User.where(mail: login).first | |||
| if type.to_i == 1 && !user.nil? | |||
| tip_exception(-2, "该手机号码或邮箱已被注册") | |||
| elsif type.to_i == 2 && user.nil? | |||
| tip_exception(-2, "该手机号码或邮箱未注册") | |||
| elsif type.to_i == 3 && user.present? | |||
| tip_exception(-2, "该手机号码或邮箱已绑定") | |||
| end | |||
| sucess_status | |||
| end | |||
| # 发送及记录激活码 | |||
| # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 | |||
| # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9:验证手机号有效 | |||
| def check_verification_code(code, send_type, value) | |||
| case send_type | |||
| when 1, 2, 4, 9 | |||
| # 手机类型的发送 | |||
| sigle_para = {phone: value} | |||
| status = Educoder::Sms.send(mobile: value, code: code) | |||
| tip_exception(-2, code_msg(status)) if status != 0 | |||
| when 8, 3, 5 | |||
| # 邮箱类型的发送 | |||
| sigle_para = {email: value} | |||
| # 60s内不能重复发送 | |||
| send_email_limit_cache_key = "send_email_60_second_limit:#{value}" | |||
| tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) | |||
| # 短时间内不能大量发送 | |||
| send_email_control = LimitForbidControl::SendEmailCode.new(value) | |||
| tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? | |||
| begin | |||
| UserMailer.register_email(value, code).deliver_now | |||
| Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) | |||
| send_email_control.increment! | |||
| # Mailer.run.email_register(code, value) | |||
| rescue Exception => e | |||
| logger_error(e) | |||
| tip_exception(-2,"邮件发送失败,请稍后重试") | |||
| end | |||
| end | |||
| ver_params = {code_type: send_type, code: code}.merge(sigle_para) | |||
| VerificationCode.create!(ver_params) | |||
| end | |||
| def code_msg status | |||
| case status | |||
| when 0 | |||
| "验证码已经发送到您的手机,请注意查收" | |||
| when 8 | |||
| "同一手机号30秒内重复提交相同的内容" | |||
| when 9 | |||
| "同一手机号5分钟内重复提交相同的内容超过3次" | |||
| when 22 | |||
| "1小时内同一手机号发送次数超过限制" | |||
| when 33 | |||
| "验证码发送次数超过频率" | |||
| when 43 | |||
| "一天内同一手机号发送次数超过限制" | |||
| when 53 | |||
| "手机号接收超过频率限制" | |||
| end | |||
| end | |||
| def find_course | |||
| return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? | |||
| @course = Course.find(params[:course_id]) | |||
| tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business? | |||
| rescue Exception => e | |||
| tip_exception(e.message) | |||
| end | |||
| def course_manager | |||
| return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR | |||
| end | |||
| def find_board | |||
| return normal_status(2, "缺少board_id参数") if params[:board_id].blank? | |||
| @board = Board.find(params[:board_id]) | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def validate_type(object_type) | |||
| normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) | |||
| end | |||
| def set_pagination | |||
| @page = params[:page] || 1 | |||
| @page_size = params[:page_size] || 15 | |||
| end | |||
| # 课堂教师权限 | |||
| def teacher_allowed | |||
| logger.info("#####identity: #{current_user.course_identity(@course)}") | |||
| unless current_user.course_identity(@course) < Course::STUDENT | |||
| normal_status(403, "") | |||
| end | |||
| end | |||
| # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) | |||
| def teacher_or_admin_allowed | |||
| unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR | |||
| normal_status(403, "") | |||
| end | |||
| end | |||
| def require_admin | |||
| normal_status(403, "") unless User.current.admin? | |||
| end | |||
| def require_business | |||
| normal_status(403, "") unless admin_or_business? | |||
| end | |||
| # 前端会捕捉401,弹登录弹框 | |||
| # 未授权的捕捉407,弹试用申请弹框 | |||
| def require_login | |||
| #6.13 -hs | |||
| tip_exception(401, "请登录后再操作") unless User.current.logged? | |||
| end | |||
| # 异常提醒 | |||
| def tip_exception(status = -1, message) | |||
| raise Educoder::TipException.new(status, message) | |||
| end | |||
| def missing_template | |||
| tip_exception(404, "...") | |||
| end | |||
| # 弹框提醒 | |||
| def tip_show_exception(status = -2, message) | |||
| raise Educoder::TipException.new(status, message) | |||
| end | |||
| def normal_status(status = 0, message) | |||
| case status | |||
| when 403 | |||
| message = "您没有权限进行该操作" | |||
| when 404 | |||
| message = "您访问的页面不存在或已被删除" | |||
| end | |||
| render :json => { status: status, message: message } | |||
| end | |||
| # 资料是否完善 | |||
| def check_account | |||
| if !current_user.profile_completed? | |||
| #info_url = '/account/profile' | |||
| tip_exception(402, nil) | |||
| end | |||
| end | |||
| # 系统全局认证(暂时隐藏试用申请的判断) | |||
| def check_auth | |||
| # day_cer = UserDayCertification.find_by(user_id: current_user.id) | |||
| # # 如果注册超过24小时则需要完善资料及授权 | |||
| # if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 | |||
| # if !current_user.profile_completed? | |||
| # info_url = '/account/profile' | |||
| # tip_exception(402, info_url) | |||
| # elsif current_user.certification != 1 | |||
| # if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) | |||
| # tip_exception(408, "您的试用申请正在审核中,请耐心等待") | |||
| # end | |||
| # tip_exception(407, "系统未授权") | |||
| # end | |||
| # end | |||
| # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) | |||
| # tip_exception(408, "您的试用申请正在审核中,请耐心等待") | |||
| # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 | |||
| # if !current_user.profile_completed? | |||
| # info_url = '/account/profile' | |||
| # tip_exception(402, info_url) | |||
| # elsif current_user.certification != 1 | |||
| # day_cer = UserDayCertification.find_by(user_id: current_user.id) | |||
| # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 | |||
| # end | |||
| # end | |||
| end | |||
| def user_setup | |||
| # # reacct静态资源加载不需要走这一步 | |||
| #return if params[:controller] == "main" | |||
| # Find the current user | |||
| #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") | |||
| User.current = find_current_user | |||
| uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) | |||
| # 开放课程通过链接访问的用户 | |||
| if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank? | |||
| content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}" | |||
| if Digest::MD5.hexdigest(content) == params[:chinaoocKey] | |||
| user = open_class_user | |||
| if user | |||
| start_user_session(user) | |||
| set_autologin_cookie(user) | |||
| end | |||
| User.current = user | |||
| end | |||
| end | |||
| # if !User.current.logged? && Rails.env.development? | |||
| # User.current = User.find 1 | |||
| # end | |||
| # 测试版前端需求 | |||
| logger.info("subdomain:#{request.subdomain}") | |||
| if request.subdomain != "www" | |||
| if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 | |||
| User.current = User.find 81403 | |||
| elsif params[:debug] == 'student' | |||
| User.current = User.find 8686 | |||
| elsif params[:debug] == 'admin' | |||
| logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....." | |||
| user = User.find 36480 | |||
| User.current = user | |||
| cookies.signed[:user_id] = user.id | |||
| end | |||
| end | |||
| # User.current = User.find 81403 | |||
| end | |||
| # Returns the current user or nil if no user is logged in | |||
| # and starts a session if needed | |||
| def find_current_user | |||
| uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") | |||
| uid_logger("0000000000000user setup start: default_yun_session is #{default_yun_session}, session[:current_user_id] is #{session[:"#{default_yun_session}"]}") | |||
| current_domain_session = session[:"#{default_yun_session}"] | |||
| if current_domain_session | |||
| # existing session | |||
| User.current = (User.active.find(current_domain_session) rescue nil) | |||
| elsif autologin_user = try_to_autologin | |||
| autologin_user | |||
| elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? | |||
| # RSS key authentication does not start a session | |||
| User.find_by_rss_key(params[:key]) | |||
| end | |||
| end | |||
| def user_trace_log | |||
| @@ -381,32 +383,28 @@ class ApplicationController < ActionController::Base | |||
| Rails.logger.user_trace.info(str) | |||
| end | |||
| def try_to_autologin | |||
| if cookies[autologin_cookie_name] | |||
| # auto-login feature starts a new session | |||
| user = nil | |||
| Rails.logger.info("111111111111111111#{default_yun_session}, session is #{session[:"#{default_yun_session}"]} ") | |||
| user = User.try_to_autologin(cookies[autologin_cookie_name]) | |||
| # start_user_session(user) if user # TODO 解决sso退出不同步的问题 | |||
| user | |||
| end | |||
| end | |||
| def api_request? | |||
| %w(xml json).include? params[:format] | |||
| end | |||
| def current_user | |||
| if Rails.env.development? | |||
| User.current = User.find 4 | |||
| else | |||
| User.current | |||
| end | |||
| end | |||
| ## 默认输出json | |||
| def render_json | |||
| respond_to do |format| | |||
| def try_to_autologin | |||
| if cookies[autologin_cookie_name] | |||
| # auto-login feature starts a new session | |||
| user = nil | |||
| Rails.logger.info("111111111111111111#{default_yun_session}, session is #{session[:"#{default_yun_session}"]} ") | |||
| user = User.try_to_autologin(cookies[autologin_cookie_name]) | |||
| # start_user_session(user) if user # TODO 解决sso退出不同步的问题 | |||
| user | |||
| end | |||
| end | |||
| def api_request? | |||
| %w(xml json).include? params[:format] | |||
| end | |||
| def current_user | |||
| User.current | |||
| end | |||
| ## 默认输出json | |||
| def render_json | |||
| respond_to do |format| | |||
| format.json | |||
| end | |||
| end | |||
| @@ -723,39 +721,61 @@ class ApplicationController < ActionController::Base | |||
| def find_repository | |||
| @repo = @user.repositories.find_by_identifier params[:repo_identifier] | |||
| render_not_found("未找到’#{params[:repo_identifier]}’相关的项目") unless @repo | |||
| end | |||
| def find_repository_by_id | |||
| @repo = Repository.find params[:id] | |||
| end | |||
| def find_project | |||
| project_id = params[:project_id] ? params[:project_id] : params[:id] | |||
| project = Project.where(identifier: project_id) | |||
| if project.exists? | |||
| @project = project.first | |||
| end | |||
| def find_repository_by_id | |||
| @repo = Repository.find params[:id] | |||
| end | |||
| def find_project | |||
| project_id = params[:project_id] ? params[:project_id] : params[:id] | |||
| project = Project.where(identifier: project_id) | |||
| if project.exists? | |||
| @project = project.first | |||
| else | |||
| @project = Project.find project_id | |||
| end | |||
| render_not_found("未找到’#{project}’相关的项目") unless @project | |||
| end | |||
| def find_project_with_id | |||
| @project = Project.find(params[:project_id] || params[:id]) | |||
| rescue Exception => e | |||
| logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def render_response(interactor) | |||
| interactor.success? ? render_ok : render_error(interactor.error) | |||
| end | |||
| # projects | |||
| def load_project | |||
| namespace = params[:owner] | |||
| id = params[:repo] || params[: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 @project && current_user.is_a?(AnonymousUser) | |||
| logger.info "###########:This is AnonymousUser" | |||
| @project = nil if !@project.is_public? | |||
| render_forbidden and return | |||
| else | |||
| @project = Project.find project_id | |||
| logger.info "###########:project not found" | |||
| @project = nil | |||
| render_not_found and return | |||
| end | |||
| @project | |||
| end | |||
| render_not_found("未找到’#{project}’相关的项目") unless @project | |||
| end | |||
| def find_project_with_identifier | |||
| @project = Project.find_by_identifier! params[:id] | |||
| render_not_found("未找到’#{params[:id]}’相关的项目") unless @project | |||
| end | |||
| def find_project_with_id | |||
| @project = Project.find(params[:project_id] || params[:id]) | |||
| rescue Exception => e | |||
| logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| def render_response(interactor) | |||
| interactor.success? ? render_ok : render_error(interactor.error) | |||
| end | |||
| def load_repository | |||
| @repository ||= load_project&.repository | |||
| end | |||
| private | |||
| def object_not_found | |||
| @@ -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. 上传到云 | |||
| @@ -98,6 +107,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 = | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,40 @@ | |||
| module Ci::DbConnectable | |||
| extend ActiveSupport::Concern | |||
| include 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 | |||
| @@ -11,19 +11,24 @@ module LoginHelper | |||
| def set_autologin_cookie(user) | |||
| token = Token.get_or_create_permanent_login_token(user, "autologin") | |||
| sync_user_token_to_trustie(user.login, token.value) | |||
| Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" | |||
| cookie_options = { | |||
| :value => token.value, | |||
| :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')) | |||
| end | |||
| unless cookies[autologin_cookie_name].present? | |||
| cookies[autologin_cookie_name] = cookie_options | |||
| end | |||
| # unless cookies[autologin_cookie_name].present? | |||
| # cookies[autologin_cookie_name] = cookie_options | |||
| # end | |||
| cookies[autologin_cookie_name] = cookie_options | |||
| # for action cable | |||
| cookies.signed[:user_id] ||= user.id | |||
| @@ -48,11 +53,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.current.delete_autologin_token(autologin) | |||
| end | |||
| User.current.delete_session_token(session[:tk]) | |||
| 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.delete_autologin_token(autologin) | |||
| user.delete_session_token(session[:tk]) | |||
| self.logged_user = nil | |||
| end | |||
| @@ -65,7 +75,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}") | |||
| @@ -108,4 +118,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 | |||
| @@ -10,7 +10,7 @@ module OperateProjectAbilityAble | |||
| end | |||
| def authorizate_user_can_edit_repo! | |||
| return if @repo.project.manager?(current_user) || current_user.admin? | |||
| return if @repository.project.manager?(current_user) || current_user.admin? | |||
| render_forbidden('你没有权限操作.') | |||
| end | |||
| @@ -0,0 +1,28 @@ | |||
| module RegisterHelper | |||
| extend ActiveSupport::Concern | |||
| def autologin_register(username, email, password, platform= 'forge') | |||
| result = {message: nil, user: nil} | |||
| user = User.new(admin: false, login: username, mail: email, type: "User") | |||
| user.password = password | |||
| user.platform = platform | |||
| user.activate | |||
| interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) | |||
| if interactor.success? | |||
| gitea_user = interactor.result | |||
| result = Gitea::User::GenerateTokenService.new(username, password).call | |||
| user.gitea_token = result['sha1'] | |||
| user.gitea_uid = gitea_user['id'] | |||
| if user.save! | |||
| UserExtension.create!(user_id: user.id) | |||
| result[:user] = {id: user.id, token: user.gitea_token} | |||
| end | |||
| else | |||
| result[:message] = interactor.error | |||
| end | |||
| result | |||
| end | |||
| end | |||
| @@ -1,5 +1,6 @@ | |||
| class ForksController < ApplicationController | |||
| before_action :require_login, :find_project_with_id | |||
| before_action :require_login | |||
| before_action :load_project | |||
| before_action :authenticate_project!, :authenticate_user! | |||
| skip_after_action :user_trace_log, only: [:create] | |||
| @@ -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 | |||
| @@ -1,7 +1,7 @@ | |||
| class IssueTagsController < ApplicationController | |||
| before_action :require_login, except: [:index] | |||
| before_action :find_project_with_id | |||
| before_action :set_project | |||
| before_action :load_repository | |||
| before_action :set_user | |||
| before_action :check_issue_permission, except: :index | |||
| before_action :set_issue_tag, only: [:edit, :update, :destroy] | |||
| @@ -38,12 +38,12 @@ class IssueTagsController < ApplicationController | |||
| begin | |||
| issue_tag = IssueTag.new(tag_params.merge(project_id: @project.id, user_id: current_user.id)) | |||
| if issue_tag.save | |||
| gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call | |||
| if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"]) | |||
| normal_status(0, "标签创建成功") | |||
| else | |||
| normal_status(-1, "标签创建失败") | |||
| end | |||
| # gitea_tag = Gitea::Labels::CreateService.new(current_user, @repository.try(:identifier), tag_params).call | |||
| # if gitea_tag && issue_tag.update_attributes(gid: gitea_tag["id"], gitea_url: gitea_tag["url"]) | |||
| # normal_status(0, "标签创建成功") | |||
| # else | |||
| # normal_status(-1, "标签创建失败") | |||
| # end | |||
| else | |||
| normal_status(-1, "标签创建失败") | |||
| end | |||
| @@ -79,12 +79,12 @@ class IssueTagsController < ApplicationController | |||
| ActiveRecord::Base.transaction do | |||
| begin | |||
| if @issue_tag.update_attributes(tag_params) | |||
| gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call | |||
| if gitea_tag | |||
| normal_status(0, "标签更新成功") | |||
| else | |||
| normal_status(-1, "标签更新失败") | |||
| end | |||
| # gitea_tag = Gitea::Labels::UpdateService.new(current_user, @repository.try(:identifier),@issue_tag.try(:gid), tag_params).call | |||
| # if gitea_tag | |||
| # normal_status(0, "标签更新成功") | |||
| # else | |||
| # normal_status(-1, "标签更新失败") | |||
| # end | |||
| else | |||
| normal_status(-1, "标签更新失败") | |||
| end | |||
| @@ -103,12 +103,12 @@ class IssueTagsController < ApplicationController | |||
| ActiveRecord::Base.transaction do | |||
| begin | |||
| if @issue_tag.destroy | |||
| issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call | |||
| if issue_tag | |||
| normal_status(0, "标签删除成功") | |||
| else | |||
| normal_status(-1, "标签删除失败") | |||
| end | |||
| # issue_tag = Gitea::Labels::DeleteService.new(@user, @repository.try(:identifier), @issue_tag.try(:gid)).call | |||
| # if issue_tag | |||
| # normal_status(0, "标签删除成功") | |||
| # else | |||
| # normal_status(-1, "标签删除失败") | |||
| # end | |||
| else | |||
| normal_status(-1, "标签删除失败") | |||
| end | |||
| @@ -121,13 +121,8 @@ class IssueTagsController < ApplicationController | |||
| private | |||
| def set_project | |||
| # @project = Project.find_by_identifier! params[:project_id] | |||
| @repository = @project.repository | |||
| def set_user | |||
| @user = @project.owner | |||
| normal_status(-1, "项目不存在") unless @project.present? | |||
| normal_status(-1, "仓库不存在") unless @repository.present? | |||
| normal_status(-1, "用户不存在") unless @user.present? | |||
| end | |||
| def check_issue_permission | |||
| @@ -143,4 +138,4 @@ class IssueTagsController < ApplicationController | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -1,12 +1,12 @@ | |||
| class IssuesController < ApplicationController | |||
| before_action :require_login, except: [:index, :show, :index_chosen] | |||
| before_action :find_project_with_id | |||
| before_action :set_project_and_user | |||
| before_action :load_project | |||
| before_action :set_user | |||
| before_action :check_issue_permission | |||
| before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue] | |||
| before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue] | |||
| before_action :get_branches, only: [:new, :edit] | |||
| before_action :check_token_enough, only: [:create, :update] | |||
| skip_after_action :user_trace_log, only: [:update] | |||
| @@ -17,7 +17,7 @@ class IssuesController < ApplicationController | |||
| @user_admin_or_member = current_user.present? && current_user.logged? && (current_user.admin || @project.member?(current_user)) | |||
| issues = @project.issues.issue_issue.issue_index_includes | |||
| issues = issues.where(is_private: false) unless @user_admin_or_member | |||
| @all_issues_size = issues.size | |||
| @open_issues_size = issues.where.not(status_id: 5).size | |||
| @close_issues_size = issues.where(status_id: 5).size | |||
| @@ -98,8 +98,7 @@ class IssuesController < ApplicationController | |||
| end | |||
| def new | |||
| @all_branches = get_branches | |||
| @issue_chosen = issue_left_chosen(@project, nil) | |||
| @issue_chosen = get_associated_data(@project) | |||
| end | |||
| def create | |||
| @@ -107,9 +106,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) | |||
| @@ -138,24 +134,30 @@ class IssuesController < ApplicationController | |||
| tiding_type: 'issue', status: 0) | |||
| end | |||
| #为悬赏任务时, 扣除当前用户的积分 | |||
| if params[:issue_type].to_s == "2" | |||
| post_to_chain("minus", params[:token].to_i, current_user.try(:login)) | |||
| 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} | |||
| else | |||
| normal_status(-1, "创建失败") | |||
| end | |||
| end | |||
| end | |||
| def edit | |||
| # @all_branches = get_branches | |||
| # @issue_chosen = issue_left_chosen(@project, @issue.id) | |||
| @cannot_edit_tags = @issue.issue_type=="2" && @issue.status_id == 5 #悬赏任务已解决且关闭的状态下,不能修改 | |||
| @issue_attachments = @issue.attachments | |||
| end | |||
| def update | |||
| issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) | |||
| return normal_status(-1, "您没有权限修改token") if @issue.will_save_change_to_token? && @issue.user_id != current_user&.id | |||
| last_token = @issue.token | |||
| last_status_id = @issue.status_id | |||
| if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists? | |||
| @issue&.issue_tags_relates&.destroy_all | |||
| params[:issue_tag_ids].each do |tag| | |||
| @@ -163,27 +165,22 @@ class IssuesController < ApplicationController | |||
| end | |||
| end | |||
| user = current_user | |||
| # issue_json = issue_send_params(@issue).except(:issue_classify, :author_id, :project_id).to_json | |||
| issue_hash = old_value_to_hash(@issue, params) | |||
| if @issue.update_attributes(issue_params) | |||
| user_trace_update_log(issue_hash) | |||
| issue_files = params[:attachment_ids] | |||
| change_files = false | |||
| issue_file_ids = [] | |||
| if issue_files.present? | |||
| change_files = true | |||
| issue_files.each do |id| | |||
| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) | |||
| unless attachment.blank? | |||
| attachment.container = @issue | |||
| attachment.author_id = current_user.id | |||
| attachment.description = "" | |||
| attachment.save | |||
| end | |||
| issue_files = params[:attachment_ids] | |||
| change_files = false | |||
| issue_file_ids = [] | |||
| if issue_files.present? | |||
| change_files = true | |||
| issue_files.each do |id| | |||
| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) | |||
| unless attachment.blank? | |||
| attachment.container = @issue | |||
| attachment.author_id = current_user.id | |||
| attachment.description = "" | |||
| attachment.save | |||
| end | |||
| end | |||
| end | |||
| # if params[:issue_tag_ids].present? | |||
| # issue_current_tags = @issue&.issue_tags&.select(:id)&.pluck(:id) | |||
| @@ -198,18 +195,39 @@ class IssuesController < ApplicationController | |||
| # end | |||
| # end | |||
| # end | |||
| issue_hash = old_value_to_hash(@issue, params) | |||
| if params[:status_id].to_i == 5 | |||
| @issue.issue_times.update_all(end_time: Time.now) | |||
| @issue.update_closed_issues_count_in_project! | |||
| end | |||
| @issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id) | |||
| normal_status(0, "更新成功") | |||
| if @issue.issue_type.to_s == "2" && params[:status_id].to_i == 5 && @issue.author_id != current_user.try(:id) | |||
| normal_status(-1, "不允许修改为关闭状态") | |||
| else | |||
| normal_status(-1, "更新失败") | |||
| end | |||
| issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) | |||
| if @issue.update_attributes(issue_params) | |||
| user_trace_update_log(issue_hash) | |||
| if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 | |||
| @issue.issue_times.update_all(end_time: Time.now) | |||
| @issue.update_closed_issues_count_in_project! | |||
| if @issue.issue_type.to_s == "2" && last_status_id != 5 | |||
| if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时,才给token | |||
| post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login)) | |||
| else | |||
| post_to_chain("add", @issue.token, @issue.user.try(:login)) | |||
| end | |||
| end | |||
| end | |||
| if @issue.issue_type.to_s == "2" && @issue.status_id != 5 && @issue.saved_change_to_attribute("token") | |||
| #表示修改token值 | |||
| change_token = last_token - @issue.token | |||
| change_type = change_token > 0 ? "add" : "minus" | |||
| post_to_chain(change_type, change_token.abs, current_user.try(:login)) | |||
| end | |||
| @issue.create_journal_detail(change_files, issue_files, issue_file_ids, current_user&.id) | |||
| normal_status(0, "更新成功") | |||
| else | |||
| normal_status(-1, "更新失败") | |||
| end | |||
| end | |||
| end | |||
| def show | |||
| @@ -229,17 +247,32 @@ class IssuesController < ApplicationController | |||
| end | |||
| def destroy | |||
| if @issue.destroy | |||
| normal_status(0, "删除成功") | |||
| else | |||
| begin | |||
| issue_type = @issue.issue_type | |||
| status_id = @issue.status_id | |||
| token = @issue.token | |||
| login = @issue.user.try(:login) | |||
| if @issue.destroy | |||
| if issue_type == "2" && status_id != 5 | |||
| post_to_chain("add", token, login) | |||
| end | |||
| normal_status(0, "删除成功") | |||
| else | |||
| normal_status(-1, "删除失败") | |||
| end | |||
| rescue => exception | |||
| Rails.logger.info("#########_______exception.message_________##########{exception.message}") | |||
| normal_status(-1, "删除失败") | |||
| else | |||
| end | |||
| end | |||
| def clean | |||
| #批量删除,暂时只能删除未悬赏的 | |||
| issue_ids = params[:ids] | |||
| if issue_ids.present? | |||
| if Issue.where(id: issue_ids).destroy_all | |||
| if Issue.where(id: issue_ids, issue_type: "1").destroy_all | |||
| normal_status(0, "删除成功") | |||
| else | |||
| normal_status(-1, "删除失败") | |||
| @@ -253,7 +286,19 @@ class IssuesController < ApplicationController | |||
| update_hash = {} | |||
| update_hash.merge!(assigned_to_id: params[:assigned_to_id]) if params[:assigned_to_id].present? | |||
| update_hash.merge!(fixed_version_id: params[:fixed_version_id]) if params[:fixed_version_id].present? | |||
| update_hash.merge!(status_id: params[:status_id]) if params[:status_id].present? | |||
| # update_hash.merge!(status_id: params[:status_id]) if params[:status_id].present? | |||
| if params[:status_id].present? | |||
| status_id = params[:status_id].to_i | |||
| update_hash.merge!(status_id: status_id) | |||
| done_ratio = nil | |||
| case status_id | |||
| when 1 | |||
| done_ratio = 0 | |||
| when 3 | |||
| done_ratio = 100 | |||
| end | |||
| update_hash.merge!(done_ratio: done_ratio) if done_ratio | |||
| end | |||
| # update_hash = params[:issue] | |||
| issue_ids = params[:ids] | |||
| if issue_ids.present? | |||
| @@ -299,6 +344,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 | |||
| @@ -340,11 +388,8 @@ class IssuesController < ApplicationController | |||
| end | |||
| private | |||
| def set_project_and_user | |||
| # @project = Project.find_by_identifier(params[:project_id]) || (Project.find params[:project_id]) || (Project.find params[:id]) | |||
| def set_user | |||
| @user = @project&.owner | |||
| # normal_status(-1, "项目不存在") unless @project.present? | |||
| normal_status(-1, "用户不存在") unless @user.present? | |||
| end | |||
| def check_project_public | |||
| @@ -395,17 +440,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], | |||
| @@ -430,4 +464,32 @@ class IssuesController < ApplicationController | |||
| project_id: @project.id | |||
| } | |||
| end | |||
| def post_to_chain(type, amount,login) | |||
| change_params = { | |||
| type: type, | |||
| chain_params: { | |||
| amount: amount, | |||
| reponame: @project.try(:identifier), | |||
| username: login | |||
| } | |||
| } | |||
| PostChainJob.perform_later(change_params) | |||
| end | |||
| def check_token_enough | |||
| if params[:issue_type].to_s == "2" && (@issue.blank? || (@issue.present? && @issue.author_id == current_user.try(:id))) | |||
| return normal_status(-1, "悬赏的奖金必须大于0") if params[:token].to_i == 0 | |||
| query_params = { | |||
| type: "query", | |||
| chain_params: { | |||
| reponame: @project.try(:identifier), | |||
| username: current_user.try(:login) | |||
| } | |||
| } | |||
| response = Gitea::Chain::ChainGetService.new(query_params).call | |||
| return normal_status(-1, "获取token失败,请稍后重试") if response.status != 200 | |||
| return normal_status(-1, "您的token值不足") if JSON.parse(response.body)["balance"].to_i < params[:token].to_i | |||
| end | |||
| end | |||
| end | |||
| @@ -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 } | |||
| @@ -1,6 +1,6 @@ | |||
| class MembersController < ApplicationController | |||
| before_action :require_login | |||
| before_action :find_project_with_id | |||
| before_action :load_project | |||
| before_action :find_user_with_id, only: %i[create remove change_role] | |||
| before_action :operate!, except: %i[index] | |||
| before_action :check_member_exists!, only: %i[create] | |||
| @@ -0,0 +1,35 @@ | |||
| class Oauth::EducoderController < Oauth::BaseController | |||
| def bind | |||
| begin | |||
| login = params[:login] | |||
| mail = params[:mail] || nil | |||
| callback_url = params[:callback_url] | |||
| token = params[:token] | |||
| ::OauthEducoderForm.new({login: login, token: token, callback_url: callback_url}).validate! | |||
| open_user= OpenUsers::Educoder.find_by(uid: login) || OpenUsers::Educoder.find_by(uid: mail) | |||
| if open_user.present? && open_user.user.present? && open_user.user.email_binded? | |||
| Rails.logger.info "######## open_user exist and open_user.user exsit and email is binded ok" | |||
| successful_authentication(open_user.user) | |||
| redirect_to callback_url | |||
| else | |||
| Rails.logger.info "######## open user not exits" | |||
| user = User.find_by(login: login) || User.find_by(mail: mail) | |||
| 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, mail: mail, callback_url: callback_url) | |||
| end | |||
| end | |||
| rescue WechatOauth::Error => ex | |||
| render_error(ex.message) | |||
| end | |||
| end | |||
| end | |||
| @@ -1,4 +1,6 @@ | |||
| class OauthController < ApplicationController | |||
| layout "oauth_register", only: [:register] | |||
| DEFAULT_PASSWORD = "a12345678" | |||
| TOKEN_CALL_BACK = "/oauth/get_token_callback" | |||
| USER_INFO = "/oauth/userinfo" | |||
| @@ -51,4 +53,35 @@ class OauthController < ApplicationController | |||
| def get_token_callback | |||
| end | |||
| def register | |||
| end | |||
| def auto_register | |||
| login = params[:login] | |||
| email = params[:mail] | |||
| password = params[:password] | |||
| callback_url = params[:callback_url] | |||
| platform = params[:plathform] || 'educoder' | |||
| if User.where(mail: email).exists? | |||
| render json: { email_exist: '该邮箱已使用过' } | |||
| else | |||
| result = autologin_register(login, email, password, platform) | |||
| logger.info "[Oauth educoer] =====#{result}" | |||
| if result[:message].blank? | |||
| logger.info "[Oauth educoer] ====auto_register success" | |||
| user = User.find result[:user][:id] | |||
| successful_authentication(user) | |||
| OpenUsers::Educoder.create!(user: user, uid: user.login) | |||
| render json: { callback_url: callback_url } | |||
| # redirect_to callback_url | |||
| else | |||
| logger.info "[Oauth educoer] ====auto_register failed." | |||
| render :action => "auto_register" | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -6,12 +6,8 @@ class ProjectCategoriesController < ApplicationController | |||
| end | |||
| def group_list | |||
| # if current_user&.logged? | |||
| # projects = Project.list_user_projects(current_user.id) | |||
| # else | |||
| # projects = Project.visible | |||
| # end | |||
| projects = Project.no_anomory_projects.visible | |||
| @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size | |||
| @project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc) | |||
| # projects = Project.no_anomory_projects.visible | |||
| # @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size | |||
| end | |||
| end | |||
| @@ -1,5 +1,5 @@ | |||
| class ProjectTrendsController < ApplicationController | |||
| before_action :find_project_with_id | |||
| before_action :load_repository | |||
| before_action :check_project_public | |||
| def index | |||
| @@ -44,4 +44,4 @@ class ProjectTrendsController < ApplicationController | |||
| normal_status(-1, "您没有权限") | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -1,5 +1,7 @@ | |||
| class Projects::BaseController < ApplicationController | |||
| include PaginateHelper | |||
| before_action :require_login, :check_auth | |||
| before_action :load_project | |||
| before_action :load_repository | |||
| end | |||
| @@ -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] | |||
| before_action :find_project_with_id, only: %i[show branches update destroy fork_users praise_users watch_users] | |||
| 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_user] | |||
| 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,26 +44,40 @@ 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 | |||
| # if current_user&.logged? | |||
| # projects = Project.list_user_projects(current_user.id) | |||
| # else | |||
| # projects = Project.visible | |||
| # end | |||
| projects = Project.no_anomory_projects.visible | |||
| @project_group_list = projects.group(:project_type).size | |||
| project_statics = ProjectStatistic.first | |||
| @project_statics_list = [ | |||
| { | |||
| project_type: 'common', | |||
| name: '开源托管项目', | |||
| projects_count: project_statics&.common_projects_count || 0 | |||
| }, | |||
| { | |||
| project_type: 'mirror', | |||
| name: '开源镜像项目', | |||
| projects_count: project_statics&.mirror_projects_count || 0 | |||
| } | |||
| ] | |||
| # projects = Project.no_anomory_projects.visible | |||
| # @project_group_list = projects.group(:project_type).size | |||
| end | |||
| def update | |||
| 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) | |||
| @@ -94,16 +118,48 @@ 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 | |||
| project = Project.includes(:owner, :repository).select(:id, :name, :identifier, :user_id, :project_type).find params[:id] | |||
| 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]) | |||
| logger.info "=============> #{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 | |||
| private | |||
| def project_params | |||
| params.permit(:user_id, :name, :description, :repository_name, | |||
| @@ -116,8 +172,13 @@ class ProjectsController < ApplicationController | |||
| end | |||
| def project_public? | |||
| unless @project.is_public || current_user&admin? | |||
| tip_exception(403, "..") | |||
| return if @project.is_public? | |||
| if current_user | |||
| return if current_user.admin? || @project.member?(current_user.id) | |||
| render_forbidden('你没有权限访问.') | |||
| else | |||
| render_unauthorized('你还未登录.') | |||
| end | |||
| end | |||
| end | |||
| @@ -1,12 +1,11 @@ | |||
| class PullRequestsController < ApplicationController | |||
| before_action :require_login, except: [:index, :show] | |||
| before_action :find_project_with_id | |||
| before_action :set_repository | |||
| before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos] | |||
| # before_action :get_relatived, only: [:edit] | |||
| # | |||
| skip_after_action :user_trace_log, only: [:update] | |||
| before_action :require_login, except: [:index, :show, :files, :commits] | |||
| before_action :load_repository | |||
| 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] | |||
| skip_after_action :user_trace_log, only: [:update] | |||
| include TagChosenHelper | |||
| include ApplicationHelper | |||
| @@ -27,12 +26,13 @@ class PullRequestsController < ApplicationController | |||
| end | |||
| def new | |||
| @all_branches = PullRequests::BranchesService.new(@user, @project).call | |||
| @all_branches = PullRequests::BranchesService.new(@owner, @project).call | |||
| @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_id: @project.id | |||
| project_user_login: @owner.try(:login), | |||
| project_name: "#{@owner.try(:show_real_name)}/#{@repository.try(:identifier)}", | |||
| project_id: @project.identifier, | |||
| id: @project.id | |||
| }] | |||
| @merge_projects = @projects_names | |||
| fork_project = @project.fork_project if @is_fork | |||
| @@ -40,13 +40,14 @@ class PullRequestsController < ApplicationController | |||
| @merge_projects.push({ | |||
| project_user_login: fork_project.owner.try(:login), | |||
| project_name: "#{fork_project.owner.try(:show_real_name)}/#{fork_project.repository.try(:identifier)}", | |||
| project_id: fork_project.id | |||
| project_id: fork_project.identifier, | |||
| id: fork_project.id | |||
| }) | |||
| end | |||
| end | |||
| def get_branches | |||
| branch_result = PullRequests::BranchesService.new(@user, @project).call | |||
| branch_result = PullRequests::BranchesService.new(@owner, @project).call | |||
| render json: branch_result | |||
| # return json: branch_result | |||
| end | |||
| @@ -67,7 +68,9 @@ class PullRequestsController < ApplicationController | |||
| project_id: @project.id, | |||
| issue_id: pull_issue.id, | |||
| fork_project_id: params[:fork_project_id], | |||
| is_original: params[:is_original] | |||
| is_original: params[:is_original], | |||
| files_count: params[:files_count] || 0, | |||
| commits_count: params[:commits_count] || 0 | |||
| } | |||
| local_requests = PullRequest.new(@local_params.merge(pr_params)) | |||
| if local_requests.save | |||
| @@ -91,6 +94,7 @@ class PullRequestsController < ApplicationController | |||
| 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创建失败") | |||
| @@ -232,11 +236,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, "可以合并") | |||
| @@ -245,13 +249,19 @@ class PullRequestsController < ApplicationController | |||
| end | |||
| private | |||
| 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 | |||
| def set_repository | |||
| @repository = @project.repository | |||
| @user = @project.owner | |||
| normal_status(-1, "仓库不存在") unless @repository.present? | |||
| normal_status(-1, "用户不存在") unless @user.present? | |||
| private | |||
| def load_pull_request | |||
| @pull_request = PullRequest.find params[:id] | |||
| end | |||
| def find_pull_request | |||
| @@ -1,11 +1,10 @@ | |||
| class RepositoriesController < ApplicationController | |||
| include ApplicationHelper | |||
| include OperateProjectAbilityAble | |||
| before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror] | |||
| before_action :find_project_with_includes, only: :show | |||
| before_action :find_project, except: [:tags, :commit, :sync_mirror, :show] | |||
| before_action :load_repository | |||
| before_action :authorizate!, except: [:sync_mirror, :tags, :commit] | |||
| before_action :find_repository_by_id, only: %i[commit sync_mirror tags] | |||
| before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] | |||
| before_action :get_ref, only: %i[entries sub_entries top_counts] | |||
| before_action :get_latest_commit, only: %i[entries sub_entries top_counts] | |||
| @@ -14,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) | |||
| @@ -27,62 +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 | |||
| Rails.logger.info("#####################_______hash_commit______############{@hash_commit}") | |||
| Rails.logger.info("#####################_______hash_commit_size______############{@hash_commit.size}") | |||
| end | |||
| def commit | |||
| @commit = Gitea::Repository::Commits::GetService.new(@repo.user.login, @repo.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, @repo.user.login, @repo.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, 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, 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) | |||
| @@ -90,7 +112,7 @@ class RepositoriesController < ApplicationController | |||
| end | |||
| def delete_file | |||
| interactor = Gitea::DeleteFileInteractor.call(current_user, 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, "文件删除成功") | |||
| @@ -104,10 +126,10 @@ class RepositoriesController < ApplicationController | |||
| end | |||
| def sync_mirror | |||
| return render_error("正在镜像中..") if @repo.mirror.waiting? | |||
| return render_error("正在镜像中..") if @repository.mirror.waiting? | |||
| @repo.sync_mirror! | |||
| SyncMirroredRepositoryJob.perform_later(@repo.id, current_user.id) | |||
| @repository.sync_mirror! | |||
| SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id) | |||
| render_ok | |||
| end | |||
| @@ -123,6 +145,7 @@ class RepositoriesController < ApplicationController | |||
| end | |||
| def authorizate! | |||
| return if current_user && current_user.admin? | |||
| if @project.repository.hidden? && !@project.member?(current_user) | |||
| render_forbidden | |||
| end | |||
| @@ -135,18 +158,18 @@ 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 | |||
| @ref = params[:ref] || "master" | |||
| 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? | |||
| def get_latest_commit | |||
| 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 | |||
| @@ -156,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 | |||
| @@ -210,7 +237,7 @@ 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! | |||
| @@ -1,288 +1,334 @@ | |||
| class SyncForgeController < ApplicationController | |||
| # before_action :check_token | |||
| def create | |||
| ActiveRecord::Base.transaction do | |||
| params.permit! | |||
| sync_params = params[:sync_params] | |||
| #以前已同步的项目,那么肯定存在仓库 | |||
| if Project.exists?(identifier: sync_params[:identifier]) | |||
| SyncLog.sync_log("=================begin_to_update_project========") | |||
| project = Project.find_by(identifier: sync_params[:identifier]) | |||
| check_sync_project(project, sync_params) | |||
| else #新建项目 | |||
| SyncLog.sync_log("=================begin_to_create_new_project========") | |||
| project_user = User.where(login: sync_params[:owner_login]).first | |||
| project_params = { | |||
| repository_name: sync_params[:identifier], | |||
| user_id: project_user.id, | |||
| private: !sync_params[:is_public], | |||
| name: sync_params[:name] | |||
| } | |||
| project = Projects::CreateService.new(project_user, project_params).call | |||
| if project.present? | |||
| if sync_params[:project_score].present? | |||
| sync_params.permit! | |||
| score_params = sync_params[:project_score].merge(project_id: project.id) | |||
| new_project_score = ProjectScore.create(score_params) | |||
| SyncLog.sync_log("=================new_project_score:#{new_project_score.try(:id)}========") | |||
| end | |||
| SyncRepositoryJob.perform_later(sync_params[:owner_login], sync_params[:identifier], sync_params[:repository], get_sudomain) if sync_params[:repository].present? | |||
| check_new_project(project, sync_params) | |||
| end | |||
| end | |||
| def sync_range_projects | |||
| sync_counts = params[:sync_count] || 10 | |||
| projects = Project.includes(:project_score, :repository) | |||
| .where(is_public: true) | |||
| .where.not(identifier: ["educoder","trustieforge", "gitlab", "rGDBbQmOK", "socialforge"]) | |||
| .joins(:project_score).order("project_scores.changeset_num desc").limit(sync_counts.to_i) | |||
| projects.each do | project | | |||
| SyncProjectMilitaryJob.perform_later(project, project.repository, project.project_score) | |||
| end | |||
| rescue Exception => e | |||
| SyncLog.sync_project_log("=============sync_has_errors:==#{e.message}, project_id==:#{params[:sync_params][:id]}") | |||
| end | |||
| def sync_users | |||
| params.permit! | |||
| sync_params = params[:sync_params] | |||
| users_params = sync_params[:users] | |||
| users_params.each do |u| | |||
| if User.exists?(login: u[:user_params][:login]) | |||
| SyncLog.sync_log("=================sync_to_user_been_exists====#{u[:user_params][:login]}") | |||
| else | |||
| # new_user = User.new(u[:user_params]) | |||
| if u[:user_params][:mail].blank? | |||
| u_mail = "#{u[:user_params][:login]}@example.com" | |||
| else | |||
| u_mail = u[:user_params][:mail] | |||
| end | |||
| new_user = User.new(u[:user_params].merge(mail: u_mail)) | |||
| username = new_user.login | |||
| password = "12345678" | |||
| if new_user.save! | |||
| SyncLog.sync_log("=================sync_to_user_success==#{new_user.login}") | |||
| else | |||
| SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") | |||
| end | |||
| # ActiveRecord::Base.transaction do | |||
| # interactor = Gitea::RegisterInteractor.call({username: username, email: new_user.mail, password: password}) | |||
| # if interactor.success? | |||
| # gitea_user = interactor.result | |||
| # result = Gitea::User::GenerateTokenService.new(username, password).call | |||
| # new_user.gitea_token = result['sha1'] | |||
| # new_user.gitea_uid = gitea_user['id'] | |||
| # if new_user.save! | |||
| # UserExtension.create!(u[:user_extensions][:user_extensions].merge(user_id: new_user.id)) if u[:user_extensions].present? && u[:user_extensions][:user_extensions].present? | |||
| # else | |||
| # SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") | |||
| # end | |||
| # else | |||
| # SyncLog.sync_project_log("=============sync_to_user_failed,user_login====#{new_user.login}") | |||
| # SyncLog.sync_log("=================sync_to_user_failed,user_login====#{new_user.login}") | |||
| # end | |||
| # end | |||
| end | |||
| end | |||
| # normal_status(1, "completed_sync") | |||
| rescue Exception => e | |||
| SyncLog.sync_log("=================sync_user_failed====#{e}") | |||
| end | |||
| # def create | |||
| # ActiveRecord::Base.transaction do | |||
| # params.permit! | |||
| # sync_params = params[:sync_params] | |||
| # project_user = User.where(login: sync_params[:owner_login])&.first | |||
| # #以前已同步的项目,那么肯定存在仓库 | |||
| # SyncLog.sync_log("=================begin_to_sync_forge: project_identifier: #{sync_params[:identifier]}========") | |||
| # user_projects = Project.where(user_id: project_user.id) | |||
| # if user_projects.where(id: sync_params[:id], identifier: sync_params[:identifier]).present? | |||
| # has_project = true | |||
| # project = user_projects.where(id: sync_params[:id], identifier: sync_params[:identifier])&.first | |||
| # elsif user_projects.where(id: sync_params[:id]).present? | |||
| # has_project = true | |||
| # project = user_projects.where(id: sync_params[:id])&.first | |||
| # elsif user_projects.where(identifier: sync_params[:identifier]).present? | |||
| # has_project = true | |||
| # project = user_projects.where(identifier: sync_params[:identifier])&.first | |||
| # else | |||
| # has_project = false | |||
| # end | |||
| private | |||
| def check_sync_project(project,sync_params) | |||
| begin | |||
| gitea_main = "https://www.trustie.net/" | |||
| if request.subdomain === 'testforgeplus' | |||
| gitea_main = "https://ucloudtest.trustie.net/" | |||
| end | |||
| SyncLog.sync_log("----begin_to_check_sync_project----project_id:#{project.id}---------------") | |||
| change_project_score(project, sync_params[:project_score], sync_params[:repository]) if sync_params[:repository].present? #更新project_score | |||
| change_project_issues(project, sync_params[:issues],project.id, gitea_main) | |||
| change_project_members(project, sync_params[:members],gitea_main) | |||
| change_project_versions(project, sync_params[:project_versions],gitea_main) | |||
| change_project_watchers(project, sync_params[:project_watchers],gitea_main) | |||
| change_project_praises(project, sync_params[:praise_trends],gitea_main) | |||
| rescue => e | |||
| SyncLog.sync_log("=========check_sync_project_errors:#{e}===================") | |||
| end | |||
| end | |||
| # if has_project | |||
| # SyncLog.sync_log("=================begin_to_update_project========") | |||
| # check_sync_project(project, sync_params) | |||
| # else #新建项目 | |||
| # SyncLog.sync_log("=================begin_to_create_new_project========") | |||
| def check_new_project(project,sync_params) | |||
| SyncLog.sync_log("***8. begin_to_sync_new_project---------------") | |||
| sync_projects_params = { | |||
| type: "Project", | |||
| ids: sync_params[:id], | |||
| token: get_token, | |||
| sync_params: sync_params, | |||
| new_project_id: project.id | |||
| } | |||
| gitea_main = "https://www.trustie.net/" | |||
| if request.subdomain === 'testforgeplus' | |||
| gitea_main = "https://ucloudtest.trustie.net/" | |||
| end | |||
| SyncProjectsJob.perform_later(sync_projects_params, gitea_main) | |||
| SyncLog.sync_log("***8. end_to_sync_new_project---------------") | |||
| end | |||
| # project_params = { | |||
| # repository_name: sync_params[:identifier], | |||
| # user_id: project_user.id, | |||
| # private: !sync_params[:is_public], | |||
| # name: sync_params[:name] | |||
| # } | |||
| # project = Projects::CreateService.new(project_user, project_params).call | |||
| # if project.present? | |||
| # if sync_params[:project_score].present? | |||
| # sync_params.permit! | |||
| # score_params = sync_params[:project_score].merge(project_id: project.id) | |||
| # new_project_score = ProjectScore.create(score_params) | |||
| # SyncLog.sync_log("=================new_project_score:#{new_project_score.try(:id)}========") | |||
| # end | |||
| def change_project_praises(project, praises,gitea_main) | |||
| SyncLog.sync_log("***6. begin_to_sync_parises---------------") | |||
| forge_praises_ids = project&.praise_treads&.select(:id)&.pluck(:id) | |||
| diff_target_ids = praises[:ids] - forge_praises_ids | |||
| if diff_target_ids.size > 0 | |||
| sync_projects_params = { | |||
| type: "PraiseTread", | |||
| ids: diff_target_ids, | |||
| token: get_token, | |||
| parent_id: project.id | |||
| } | |||
| SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| SyncLog.sync_log("***6. end_to_sync_parises---------------") | |||
| end | |||
| end | |||
| # SyncRepositoryJob.perform_later(sync_params[:owner_login], sync_params[:identifier], sync_params[:repository], get_sudomain) if sync_params[:repository].present? | |||
| # check_new_project(project, sync_params) | |||
| # else | |||
| # SyncLog.sync_project_log("=============new_project_create_failed, trustie_project_id==:#{params[:sync_params][:id]}") | |||
| # end | |||
| # end | |||
| # end | |||
| # rescue Exception => e | |||
| # SyncLog.sync_project_log("=============sync_has_errors:==#{e.message}, project_id==:#{params[:sync_params][:id]}") | |||
| # end | |||
| #检查repository和project_score | |||
| def change_project_score(project, project_scores, repository_params) | |||
| SyncLog.sync_log("***1. begin_to_sync_project_score---------------") | |||
| begin | |||
| pre_project_score = project.project_score | |||
| if pre_project_score.present? | |||
| change_num = 0 | |||
| project_scores.each do |k,v| | |||
| unless pre_project_score.send("#{k}") == v | |||
| change_num += 1 | |||
| pre_project_score[:"#{k}"] = v | |||
| end | |||
| if k == "changeset_num" && v.to_i > pre_project_score.changeset_num.to_i && repository_params[:url].present? | |||
| SyncRepositoryJob.perform_later(project.owner.try(:login), project.identifier, repository_params, get_sudomain) | |||
| end | |||
| end | |||
| pre_project_score.save! if change_num > 0 #如果 project_score有变化则更新 | |||
| else | |||
| ProjectScore.create!(project_scores.merge(project_id: project.id)) | |||
| end | |||
| SyncLog.sync_log("***1. end_to_sync_project_score---------------") | |||
| rescue Exception => e | |||
| SyncLog.sync_log("=========change_project_score_errors:#{e}===================") | |||
| end | |||
| end | |||
| # def sync_users | |||
| # params.permit! | |||
| # sync_params = params[:sync_params] | |||
| # users_params = sync_params[:users] | |||
| def change_project_issues(project, old_issues_params,project_id, gitea_main) | |||
| SyncLog.sync_log("***2. begin_to_syncissues---------------") | |||
| begin | |||
| forge_issue_ids = project&.issues&.select(:id)&.pluck(:id) | |||
| sync_projects_params = {} | |||
| unless forge_issue_ids.size.to_i < old_issues_params[:count].to_i | |||
| forge_journal_ids = Journal.select([:id, :journalized_id, :journalized_type]).where(journalized_id: forge_issue_ids).pluck(:id) | |||
| diff_issue_ids = old_issues_params[:ids] - forge_issue_ids | |||
| if diff_issue_ids.size == 0 #issue数量一样,判断评论是否有增减 | |||
| diff_journal_ids = old_issues_params[:journals][:ids] - forge_journal_ids | |||
| unless diff_journal_ids.size == 0 | |||
| sync_projects_params = { | |||
| type: "Journal", | |||
| ids: diff_journal_ids, | |||
| token: get_token, | |||
| parent_id: project_id | |||
| } | |||
| end | |||
| else | |||
| sync_projects_params = { | |||
| type: "Issue", | |||
| ids: diff_issue_ids, | |||
| token: get_token, | |||
| parent_id: project_id | |||
| } | |||
| end | |||
| end | |||
| SyncProjectsJob.perform_later(sync_projects_params, gitea_main) if sync_projects_params.present? | |||
| SyncLog.sync_log("***2. end_to_syncissues---------------") | |||
| rescue Exception => e | |||
| SyncLog.sync_log("=========change_project_issues_errors:#{e}===================") | |||
| end | |||
| end | |||
| # users_params.each do |u| | |||
| # if User.exists?(login: u[:user_params][:login]) | |||
| # SyncLog.sync_log("=================sync_to_user_been_exists====#{u[:user_params][:login]}") | |||
| # else | |||
| # # new_user = User.new(u[:user_params]) | |||
| def change_project_watchers(project, watchers,gitea_main) | |||
| SyncLog.sync_log("***5. begin_to_sync_watchers---------------") | |||
| forge_watchers_ids = project&.watchers&.select(:id)&.pluck(:id) | |||
| unless forge_watchers_ids.size.to_i < watchers[:count].to_i | |||
| diff_target_ids = watchers[:ids] - forge_watchers_ids | |||
| if diff_target_ids.size > 0 | |||
| sync_projects_params = { | |||
| type: "Watcher", | |||
| ids: diff_target_ids, | |||
| token: get_token, | |||
| parent_id: project.id | |||
| } | |||
| SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| end | |||
| end | |||
| SyncLog.sync_log("***5. begin_to_sync_watchers---------------") | |||
| end | |||
| # if u[:user_params][:mail].blank? | |||
| # u_mail = "#{u[:user_params][:login]}@example.com" | |||
| # else | |||
| # u_mail = u[:user_params][:mail] | |||
| # end | |||
| def change_project_versions(project, versions,gitea_main) | |||
| SyncLog.sync_log("***4. begin_to_sync_versions---------------") | |||
| forge_version_ids = project&.versions&.select(:id)&.pluck(:id) | |||
| unless forge_version_ids.size < versions[:count].to_i | |||
| diff_version_ids = versions[:ids] - forge_version_ids | |||
| if diff_version_ids.size > 0 | |||
| sync_projects_params = { | |||
| type: "Version", | |||
| ids: diff_version_ids, | |||
| token: get_token, | |||
| parent_id: project.id | |||
| } | |||
| SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| end | |||
| SyncLog.sync_log("***4. end_to_sync_versions---------------") | |||
| end | |||
| end | |||
| # new_user = User.new(u[:user_params].merge(mail: u_mail)) | |||
| def change_project_members(project, members,gitea_main) | |||
| SyncLog.sync_log("***3. begin_to_sync_members---------------") | |||
| forge_member_ids = project&.members&.select(:id)&.pluck(:id) | |||
| unless forge_member_ids.size < members[:count] | |||
| diff_member_ids = members[:ids] - forge_member_ids | |||
| if diff_member_ids.size > 0 | |||
| sync_projects_params = { | |||
| type: "Member", | |||
| ids: diff_member_ids, | |||
| token: get_token, | |||
| parent_id: project.id | |||
| } | |||
| SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| end | |||
| SyncLog.sync_log("***3. end_to_sync_members---------------") | |||
| end | |||
| end | |||
| # username = new_user.login | |||
| # password = "12345678" | |||
| # # if new_user.save! | |||
| # # SyncLog.sync_log("=================sync_to_user_success==#{new_user.login}") | |||
| # # else | |||
| # # SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") | |||
| # # end | |||
| # ActiveRecord::Base.transaction do | |||
| # interactor = Gitea::RegisterInteractor.call({username: username, email: new_user.mail, password: password}) | |||
| # if interactor.success? | |||
| # gitea_user = interactor.result | |||
| # result = Gitea::User::GenerateTokenService.new(username, password).call | |||
| # new_user.gitea_token = result['sha1'] | |||
| # new_user.gitea_uid = gitea_user['id'] | |||
| # if new_user.save! | |||
| # UserExtension.create!(u[:user_extensions][:user_extensions].merge(user_id: new_user.id)) if u[:user_extensions].present? && u[:user_extensions][:user_extensions].present? | |||
| # else | |||
| # SyncLog.sync_log("=================sync_to_user_failed,user_login==#{new_user.login}") | |||
| # end | |||
| # else | |||
| # SyncLog.sync_log("=============sync_to_user_failed,user_login====#{new_user.login}") | |||
| # SyncLog.sync_log("=================sync_to_user_failed,user_login====#{new_user.login}") | |||
| # end | |||
| # end | |||
| # end | |||
| # end | |||
| # # normal_status(1, "completed_sync") | |||
| # rescue Exception => e | |||
| # SyncLog.sync_log("=================sync_user_failed====#{e}") | |||
| # end | |||
| # private | |||
| # def check_sync_project(project,sync_params) | |||
| # begin | |||
| # gitea_main = "https://www.trustie.net/" | |||
| # # if request.subdomain === 'testforgeplus' | |||
| # # gitea_main = "https://ucloudtest.trustie.net/" | |||
| # # end | |||
| # SyncLog.sync_log("----begin_to_check_sync_project----project_id:#{project.id}---------------") | |||
| # change_project_score(project, sync_params[:project_score], sync_params[:repository]) if sync_params[:repository].present? #更新project_score | |||
| # change_project_issues(project, sync_params[:issues],project.id, gitea_main) | |||
| # change_project_members(project, sync_params[:members],gitea_main) | |||
| # change_project_versions(project, sync_params[:project_versions],gitea_main) | |||
| # change_project_watchers(project, sync_params[:project_watchers],gitea_main) | |||
| # change_project_praises(project, sync_params[:praise_trends],gitea_main) | |||
| # rescue => e | |||
| # SyncLog.sync_log("=========check_sync_project_errors:#{e}===================") | |||
| # end | |||
| # end | |||
| # def check_new_project(project,sync_params) | |||
| # SyncLog.sync_log("***8. begin_to_sync_new_project---------------") | |||
| # sync_projects_params = { | |||
| # type: "Project", | |||
| # ids: sync_params[:id], | |||
| # token: get_token, | |||
| # sync_params: sync_params, | |||
| # new_project_id: project.id | |||
| # } | |||
| # gitea_main = "https://www.trustie.net/" | |||
| # # if request.subdomain === 'testforgeplus' | |||
| # # gitea_main = "https://ucloudtest.trustie.net/" | |||
| # # end | |||
| # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) | |||
| # SyncLog.sync_log("***8. end_to_sync_new_project---------------") | |||
| # end | |||
| # def check_token | |||
| # def change_project_praises(project, praises,gitea_main) | |||
| # SyncLog.sync_log("***6. begin_to_sync_parises---------------") | |||
| # forge_praises_ids = project&.praise_treads&.select(:id)&.pluck(:id) | |||
| # diff_target_ids = praises[:ids] - forge_praises_ids | |||
| # if diff_target_ids.size > 0 | |||
| # sync_projects_params = { | |||
| # type: "PraiseTread", | |||
| # ids: diff_target_ids, | |||
| # token: get_token, | |||
| # parent_id: project.id | |||
| # } | |||
| # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| # SyncLog.sync_log("***6. end_to_sync_parises---------------") | |||
| # end | |||
| # end | |||
| # #检查repository和project_score | |||
| # def change_project_score(project, project_scores, repository_params) | |||
| # SyncLog.sync_log("***1. begin_to_sync_project_score---------------") | |||
| # begin | |||
| # pre_project_score = project.project_score | |||
| # if pre_project_score.present? | |||
| # change_num = 0 | |||
| # project_scores.each do |k,v| | |||
| # unless pre_project_score.send("#{k}") == v | |||
| # change_num += 1 | |||
| # pre_project_score[:"#{k}"] = v | |||
| # end | |||
| # if k == "changeset_num" && v.to_i > pre_project_score.changeset_num.to_i && repository_params[:url].present? | |||
| # SyncRepositoryJob.perform_later(project.owner.try(:login), project.identifier, repository_params, get_sudomain) | |||
| # end | |||
| # end | |||
| # pre_project_score.save! if change_num > 0 #如果 project_score有变化则更新 | |||
| # else | |||
| # ProjectScore.create!(project_scores.merge(project_id: project.id)) | |||
| # end | |||
| # SyncLog.sync_log("***1. end_to_sync_project_score---------------") | |||
| # rescue Exception => e | |||
| # SyncLog.sync_log("=========change_project_score_errors:#{e}===================") | |||
| # end | |||
| # end | |||
| # def change_project_issues(project, old_issues_params,project_id, gitea_main) | |||
| # SyncLog.sync_log("***2. begin_to_syncissues---------------") | |||
| # begin | |||
| # forge_issue_ids = project&.issues&.select(:id)&.pluck(:id) | |||
| # sync_projects_params = {} | |||
| # SyncLog.sync_log("***2--01. forge_issue_ids-#{forge_issue_ids.size.to_i}--------------") | |||
| # if forge_issue_ids.size.to_i <= old_issues_params[:count].to_i | |||
| # diff_issue_ids = old_issues_params[:ids] - forge_issue_ids | |||
| # if diff_issue_ids.size == 0 #issue数量一样,判断评论是否有增减 | |||
| # forge_journal_ids = Journal.select([:id, :journalized_id, :journalized_type]).where(journalized_id: forge_issue_ids).pluck(:id) | |||
| # diff_journal_ids = old_issues_params[:journals][:ids] - forge_journal_ids | |||
| # unless diff_journal_ids.size == 0 | |||
| # sync_projects_params = { | |||
| # type: "Journal", | |||
| # ids: diff_journal_ids, | |||
| # token: get_token, | |||
| # parent_id: project_id | |||
| # } | |||
| # SyncLog.sync_log("***2--02. sync_projects_params-#{sync_projects_params}--------------") | |||
| # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) | |||
| # end | |||
| # else | |||
| # new_diff_ids = diff_issue_ids.in_groups_of(200).map{|k| k.reject(&:blank?)} | |||
| # diff_len = new_diff_ids.length | |||
| # (1..diff_len).each do |len| | |||
| # sync_projects_params = { | |||
| # type: "Issue", | |||
| # ids: new_diff_ids[len-1], | |||
| # token: get_token, | |||
| # parent_id: project_id | |||
| # } | |||
| # SyncLog.sync_log("***2--030#{len}. sync_projects_params_groups-#{sync_projects_params}--------------") | |||
| # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) | |||
| # end | |||
| # # sync_projects_params = { | |||
| # # type: "Issue", | |||
| # # ids: diff_issue_ids, | |||
| # # token: get_token, | |||
| # # parent_id: project_id | |||
| # # } | |||
| # # SyncLog.sync_log("***2--03. sync_projects_params_groups-#{sync_projects_params}--------------") | |||
| # # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) | |||
| # end | |||
| # end | |||
| # # SyncProjectsJob.perform_later(sync_projects_params, gitea_main) if sync_projects_params.present? | |||
| # SyncLog.sync_log("***2. end_to_syncissues---------------") | |||
| # rescue Exception => e | |||
| # SyncLog.sync_log("=========change_project_issues_errors:#{e}===================") | |||
| # end | |||
| # end | |||
| # def change_project_watchers(project, watchers,gitea_main) | |||
| # SyncLog.sync_log("***5. begin_to_sync_watchers---------------") | |||
| # forge_watchers_ids = project&.watchers&.select(:id)&.pluck(:id) | |||
| # if forge_watchers_ids.size.to_i <= watchers[:count].to_i | |||
| # diff_target_ids = watchers[:ids] - forge_watchers_ids | |||
| # if diff_target_ids.size > 0 | |||
| # sync_projects_params = { | |||
| # type: "Watcher", | |||
| # ids: diff_target_ids, | |||
| # token: get_token, | |||
| # parent_id: project.id | |||
| # } | |||
| # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| # end | |||
| # end | |||
| # SyncLog.sync_log("***5. begin_to_sync_watchers---------------") | |||
| # end | |||
| # def change_project_versions(project, versions,gitea_main) | |||
| # SyncLog.sync_log("***4. begin_to_sync_versions---------------") | |||
| # forge_version_ids = project&.versions&.select(:id)&.pluck(:id) | |||
| # if forge_version_ids.size <= versions[:count].to_i | |||
| # diff_version_ids = versions[:ids] - forge_version_ids | |||
| # if diff_version_ids.size > 0 | |||
| # sync_projects_params = { | |||
| # type: "Version", | |||
| # ids: diff_version_ids, | |||
| # token: get_token, | |||
| # parent_id: project.id | |||
| # } | |||
| # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| # end | |||
| # SyncLog.sync_log("***4. end_to_sync_versions---------------") | |||
| # end | |||
| # end | |||
| # def change_project_members(project, members,gitea_main) | |||
| # SyncLog.sync_log("***3. begin_to_sync_members---------------") | |||
| # forge_member_ids = project&.members&.select(:id)&.pluck(:id) | |||
| # if forge_member_ids.size <= members[:count] | |||
| # diff_member_ids = members[:ids] - forge_member_ids | |||
| # if diff_member_ids.size > 0 | |||
| # sync_projects_params = { | |||
| # type: "Member", | |||
| # ids: diff_member_ids, | |||
| # token: get_token, | |||
| # parent_id: project.id | |||
| # } | |||
| # SyncProjectsJob.perform_later(sync_projects_params,gitea_main) | |||
| # end | |||
| # SyncLog.sync_log("***3. end_to_sync_members---------------") | |||
| # end | |||
| # end | |||
| # def check_token | |||
| # sync_params = params[:sync_params] | |||
| # unless sync_params[:token] && sync_params[:token] == get_token | |||
| # render json: {message: "token_errors"} | |||
| # end | |||
| # end | |||
| def get_token | |||
| "34c82f51e0b699d9d16d70fd6497c9b1e4821d6ea3e872558a6537a091076b8e" | |||
| end | |||
| # def get_token | |||
| # "34c82f51e0b699d9d16d70fd6497c9b1e4821d6ea3e872558a6537a091076b8e" | |||
| # end | |||
| def get_sudomain | |||
| SyncLog.sync_log("=================request.subdomain:#{request.subdomain}========") | |||
| gitea_main = "gitea.trustie.net" | |||
| if request.subdomain === 'testforgeplus' | |||
| gitea_main = "testgitea2.trustie.net" | |||
| # elsif request.subdomain === 'forgeplus' | |||
| # gitea_main = "gitea.trustie.net" | |||
| end | |||
| return gitea_main | |||
| end | |||
| # def get_sudomain | |||
| # SyncLog.sync_log("=================request.subdomain:#{request.subdomain}========") | |||
| # gitea_main = "gitea.trustie.net" | |||
| # if request.subdomain === 'testforgeplus' | |||
| # gitea_main = "testgitea2.trustie.net" | |||
| # # elsif request.subdomain === 'forgeplus' | |||
| # # gitea_main = "gitea.trustie.net" | |||
| # end | |||
| # return gitea_main | |||
| # end | |||
| end | |||
| end | |||
| @@ -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 | |||
| @@ -149,32 +152,41 @@ class UsersController < ApplicationController | |||
| def trustie_related_projects | |||
| projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc") | |||
| projects_json = [] | |||
| domain_url = EduSetting.get('host_name') + '/projects' | |||
| if projects.present? | |||
| projects.each do |p| | |||
| project_url = "/#{p.owner.login}/#{p.identifier}" | |||
| pj = { | |||
| id: p.id, | |||
| name: p.name, | |||
| is_public: p.is_public, | |||
| updated_on: p.updated_on.strftime("%Y-%m-%d"), | |||
| status: p.status, | |||
| is_member: p.member?(current_user.try(:id)), | |||
| owner: { | |||
| name: p.owner.try(:show_real_name), | |||
| login: p.owner.login | |||
| }, | |||
| members_count: p&.members.size, | |||
| issues_count: p.issues_count - p.pull_requests_count, | |||
| commits_count: p&.project_score&.changeset_num.to_i | |||
| commits_count: p&.project_score&.changeset_num.to_i, | |||
| http_url: domain_url + project_url, | |||
| http_collaborator_url: domain_url + project_url + "/setting/collaborator", | |||
| http_issues_url: domain_url + project_url + "/issues", | |||
| http_commits_url: domain_url + project_url + "/commits", | |||
| project_score: p&.project_score.present? ? p&.project_score&.as_json(:except=>[:created_at, :updated_at]).merge!(commit_time: format_time(p&.project_score&.commit_time)) : {} | |||
| } | |||
| projects_json.push(pj) | |||
| end | |||
| end | |||
| Rails.logger.info("==========projects_json========+########{projects_json}") | |||
| render json: { projects: projects_json } | |||
| render json: { projects: projects_json.present? ? projects_json : {} } | |||
| end | |||
| def trustie_projects | |||
| user_id = User.select(:id, :login).where(login: params[:login])&.first&.id | |||
| projects = Project.visible | |||
| projects = projects.joins(:members).where(members: { user_id: user_id }) | |||
| search = params[:search].to_s.strip | |||
| @@ -1,6 +1,6 @@ | |||
| class VersionReleasesController < ApplicationController | |||
| before_action :find_project_with_id | |||
| before_action :set_user_and_project | |||
| before_action :load_repository | |||
| before_action :set_user | |||
| before_action :require_login, except: [:index] | |||
| before_action :find_version , only: [:edit, :update, :destroy] | |||
| skip_after_action :user_trace_log, only: [:update] | |||
| @@ -124,14 +124,8 @@ class VersionReleasesController < ApplicationController | |||
| private | |||
| def set_user_and_project | |||
| # @project = Project.find_by_id(params[:project_id]) | |||
| @repository = @project.repository #项目的仓库 | |||
| @user = @project.owner | |||
| unless @user.present? && @project.present? && @repository.present? | |||
| normal_status(-1, "仓库不存在") | |||
| end | |||
| def set_user | |||
| @user = @repository.user | |||
| end | |||
| def find_version | |||
| @@ -141,18 +135,18 @@ class VersionReleasesController < ApplicationController | |||
| end | |||
| end | |||
| def releases_params | |||
| def releases_params | |||
| { | |||
| 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" #分支 | |||
| } | |||
| end | |||
| def create_attachments(attachment_ids, target) | |||
| def create_attachments(attachment_ids, target) | |||
| attachment_ids.each do |id| | |||
| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) | |||
| unless attachment.blank? | |||
| @@ -1,6 +1,6 @@ | |||
| class VersionsController < ApplicationController | |||
| before_action :require_login, except: [:index, :show] | |||
| before_action :find_project_with_id | |||
| before_action :load_repository | |||
| before_action :check_issue_permission, except: [:show, :index] | |||
| before_action :set_version, only: [:edit, :update, :destroy, :show,:update_status] | |||
| @@ -166,4 +166,4 @@ class VersionsController < ApplicationController | |||
| end | |||
| end | |||
| end | |||
| end | |||
| @@ -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 | |||
| @@ -0,0 +1,30 @@ | |||
| class OauthEducoderForm | |||
| include ActiveModel::Model | |||
| attr_accessor :login, :token, :callback_url | |||
| validates :login, presence: true | |||
| validates :token, presence: true | |||
| validates :callback_url, presence: true | |||
| validate :check_callback_url! | |||
| validate :check_auth! | |||
| def check_auth! | |||
| secret = OauthEducoder.config[:access_key_secret] | |||
| before_raw_pay_load = Digest::SHA1.hexdigest("#{login}#{secret}#{Time.now.to_i/60-1}") | |||
| now_raw_pay_load = Digest::SHA1.hexdigest("#{login}#{secret}#{Time.now.to_i/60}") | |||
| if token != now_raw_pay_load && token != before_raw_pay_load | |||
| raise '你的请求无效值无效.' | |||
| end | |||
| end | |||
| def check_callback_url! | |||
| request_host = URI.parse(callback_url).host | |||
| callback_url = OauthEducoder.config[:callback_url_host] | |||
| raise 'callback_url参数无效.' if request_host != callback_url | |||
| end | |||
| end | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,2 @@ | |||
| module Ci::LanguagesHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module CompareHelper | |||
| end | |||
| @@ -0,0 +1,2 @@ | |||
| module DevOpsHelper | |||
| end | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -1,15 +1,16 @@ | |||
| module Gitea | |||
| class CreateFileInteractor | |||
| def self.call(user, params={}) | |||
| interactor = new(user, params) | |||
| def self.call(token, owner, params={}) | |||
| interactor = new(token, owner, params) | |||
| interactor.run | |||
| interactor | |||
| end | |||
| attr_reader :error, :result | |||
| def initialize(user, params) | |||
| @user = user | |||
| def initialize(token, owner, params) | |||
| @token = token | |||
| @owner = owner | |||
| @params = params | |||
| end | |||
| @@ -23,7 +24,7 @@ module Gitea | |||
| def run | |||
| Contents::CreateForm.new(valid_params).validate! | |||
| response = Gitea::Repository::Entries::CreateService.new(user, @params[:identifier], @params[:filepath], file_params).call | |||
| response = Gitea::Repository::Entries::CreateService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call | |||
| render_result(response) | |||
| rescue Exception => exception | |||
| Rails.logger.info "Exception ===========> #{exception.message}" | |||
| @@ -33,7 +34,7 @@ module Gitea | |||
| private | |||
| attr_reader :params, :user | |||
| attr_reader :params, :owner, :token | |||
| def fail!(error) | |||
| @error = error | |||
| @@ -57,6 +58,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 | |||
| @@ -1,15 +1,16 @@ | |||
| module Gitea | |||
| class DeleteFileInteractor | |||
| def self.call(user, params={}) | |||
| interactor = new(user, params) | |||
| def self.call(token, owner, params={}) | |||
| interactor = new(token, owner, params) | |||
| interactor.run | |||
| interactor | |||
| end | |||
| attr_reader :error, :result | |||
| def initialize(user, params) | |||
| @user = user | |||
| def initialize(token, owner, params) | |||
| @token = token | |||
| @owner = owner | |||
| @params = params | |||
| end | |||
| @@ -23,7 +24,7 @@ module Gitea | |||
| def run | |||
| Contents::DeleteForm.new(valid_params).validate! | |||
| response = Gitea::Repository::Entries::DeleteService.new(user, @params[:identifier], @params[:filepath], file_params).call | |||
| response = Gitea::Repository::Entries::DeleteService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call | |||
| render_result(response) | |||
| rescue Exception => exception | |||
| fail!(exception.message) | |||
| @@ -31,7 +32,7 @@ module Gitea | |||
| private | |||
| attr_reader :params, :user | |||
| attr_reader :params, :owner, :token | |||
| def fail!(error) | |||
| puts "[exception]: error" | |||
| @@ -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 | |||
| @@ -1,15 +1,16 @@ | |||
| module Gitea | |||
| class UpdateFileInteractor | |||
| def self.call(user, params={}) | |||
| interactor = new(user, params) | |||
| def self.call(token, owner, params={}) | |||
| interactor = new(token, owner, params) | |||
| interactor.run | |||
| interactor | |||
| end | |||
| attr_reader :error, :result | |||
| def initialize(user, params) | |||
| @user = user | |||
| def initialize(token, owner, params) | |||
| @owner = owner | |||
| @token = token | |||
| @params = params | |||
| end | |||
| @@ -23,7 +24,7 @@ module Gitea | |||
| def run | |||
| Contents::UpdateForm.new(valid_params).validate! | |||
| response = Gitea::Repository::Entries::UpdateService.new(user, @params[:identifier], @params[:filepath], file_params).call | |||
| response = Gitea::Repository::Entries::UpdateService.new(token, owner, @params[:identifier], @params[:filepath], file_params).call | |||
| render_result(response) | |||
| rescue Exception => exception | |||
| fail!(exception.message) | |||
| @@ -31,7 +32,7 @@ module Gitea | |||
| private | |||
| attr_reader :params, :user | |||
| attr_reader :params, :owner, :token | |||
| def fail!(error) | |||
| puts "[exception]: error" | |||
| @@ -0,0 +1,29 @@ | |||
| class BroadcastMirrorRepoMsgJob < ApplicationJob | |||
| queue_as :default | |||
| def perform(repo_id) | |||
| puts "############ BroadcastMirrorRepoMsgJob start ############ #{repo_id}" | |||
| repo = Repository.find_by(id: repo_id) | |||
| return if repo.blank? | |||
| project = repo.project | |||
| json_data = { | |||
| mirror_status: repo.mirror_status, | |||
| mirror_num: repo.mirror_num, | |||
| mirror_url: repo.mirror_url, | |||
| first_sync: repo.first_sync?, | |||
| identifier: repo.identifier, | |||
| name: project.name, | |||
| id: project.id, | |||
| type: project.numerical_for_project_type | |||
| } | |||
| puts "############ broadcast start.......... " | |||
| puts "############ broadcast channel_name: channel_room_#{project.id}" | |||
| puts "############ broadcast project data: #{json_data} " | |||
| cable_result = ActionCable.server.broadcast "channel_room_#{project.id}", project: json_data | |||
| puts "############ broadcast result: #{cable_result == 1 ? 'successed' : 'failed'} " | |||
| end | |||
| end | |||
| @@ -0,0 +1,36 @@ | |||
| # 运行示例: bundle exec rails runner "CheckMirrorJob.new.call()" | |||
| class CheckMirrorJob < ApplicationJob | |||
| queue_as :default | |||
| def perform(project) | |||
| SyncLog.sync_log("==========begin_check_project_id_job:#{project.id}============") | |||
| begin | |||
| response = Gitea::Repository::Branches::ListService.new(project.owner, project.identifier).call | |||
| unless response.present? | |||
| SyncLog.sync_log("==========check_project_error_id:#{project.id}============") | |||
| ActiveRecord::Base.transaction do | |||
| delete_gitea = Gitea::Repository::DeleteService.new(project.owner, project.identifier).call | |||
| if delete_gitea.status == 204 || delete_gitea.status == 404 #删除成功或者仓库不存在,都重新创建 | |||
| repository_params= { | |||
| name: project.identifier, | |||
| auto_init: true, | |||
| private: project.repository.hidden, | |||
| } | |||
| gitea_repository = Gitea::Repository::CreateService.new(project.owner.gitea_token, repository_params).call | |||
| if gitea_repository | |||
| project.update_columns(gpid: gitea_repository["id"],forked_count: gitea_repository["forks_count"]) | |||
| else | |||
| SyncLog.sync_log("==========gitea_repository_created_failed:#{project.id}============") | |||
| end | |||
| else | |||
| SyncLog.sync_log("==========delete_gitea_failed:#{project.id}============") | |||
| end | |||
| end | |||
| end | |||
| rescue => e | |||
| SyncLog.sync_log("==========failed_check_project_id:#{project.id}============errors:#{e}") | |||
| end | |||
| end | |||
| end | |||
| @@ -10,24 +10,8 @@ class MigrateRemoteRepositoryJob < ApplicationJob | |||
| gitea_repository = Gitea::Repository::MigrateService.new(token, params).call | |||
| if gitea_repository | |||
| repo&.project&.update_columns(gpid: gitea_repository["id"]) | |||
| repo&.mirror&.update_columns(status: Mirror.statuses[:succeeded]) | |||
| project = repo.project | |||
| json_data = { | |||
| mirror_status: repo.mirror_status, | |||
| mirror_num: repo.mirror_num, | |||
| mirror_url: repo.mirror_url, | |||
| first_sync: repo.first_sync?, | |||
| identifier: repo.identifier, | |||
| name: project.name, | |||
| id: project.id, | |||
| type: project.numerical_for_project_type | |||
| } | |||
| puts "############ broadcast start.......... ############" | |||
| cable_result = ActionCable.server.broadcast "channel_room_#{repo.identifier}", project: json_data | |||
| puts "############ room_channel_#{repo.identifier} result : #{cable_result}" | |||
| repo&.mirror&.succeeded! | |||
| puts "############ mirror status: #{repo.mirror.status} ############" | |||
| end | |||
| end | |||
| end | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,22 @@ | |||
| require 'uri' | |||
| require 'net/http' | |||
| class SyncProjectMilitaryJob < ApplicationJob | |||
| queue_as :default | |||
| def perform(project, repository, project_socre) | |||
| SyncLog.sync_log("============begin to sync project, project_id: #{project.id} ===========") | |||
| project_except_params = %w(id user_id praises_count watchers_count issues_count pull_requests_count versions_count issue_tags_count closed_issues_count forked_from_project_id forked_count) | |||
| project_params = { | |||
| project: project.as_json(except: project_except_params), | |||
| repository: repository.as_json(except: %w(id project_id login user_id)), | |||
| project_socre: project_socre.as_json(except: %w(id project_id)) | |||
| } | |||
| url = "http://39.105.176.215:49999/api/sync_forge/sync_projects" #trustie上的相关路由 | |||
| uri = URI.parse(url) | |||
| http = Net::HTTP.new(uri.hostname, uri.port) | |||
| http.use_ssl = false | |||
| response = http.send_request('POST', uri.path, project_params.to_json, {'Content-Type' => 'application/json'}) | |||
| SyncLog.sync_log("============end to sync project, status: #{response.code} ===========") | |||
| end | |||
| end | |||
| @@ -8,28 +8,28 @@ 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) | |||
| http.use_ssl = true | |||
| response = http.send_request('GET', uri.path, sync_params.to_json, {'Content-Type' => 'application/json'}) | |||
| SyncLog.sync_log("==========response_status::#{response.code}============") | |||
| SyncLog.sync_log("=======#{sync_params[:parent_id].present? ? sync_params[:parent_id] : sync_params[:new_project_id]}===response_status::#{response.code}============") | |||
| if response.code == '200' | |||
| target_jsons = eval(response.body) | |||
| if sync_params[:type] == "Project" | |||
| SyncLog.sync_project_log("==========target_jsons: #{target_jsons}============") | |||
| # SyncLog.sync_log("==========target_jsons: #{target_jsons}============") | |||
| update_new_project(target_jsons[:targets_params][0], sync_params[:new_project_id]) | |||
| else | |||
| SyncLog.sync_project_log("========== #{sync_params[:type]}============") | |||
| SyncLog.sync_log("========== #{sync_params[:type]}============") | |||
| create_target(target_jsons[:targets_params], sync_params[:type].to_s) | |||
| end | |||
| else | |||
| SyncLog.sync_project_log("==========sync_project_to_forge_failed #{sync_params[:type]}============") | |||
| SyncLog.sync_log("==========sync_project_to_forge_failed #{sync_params[:type]}============") | |||
| end | |||
| rescue => e | |||
| SyncLog.sync_project_log("==========sync_project_to_forge_failed #{sync_params[:type]}============errors:#{e}") | |||
| SyncLog.sync_log("==========sync_project_to_forge_failed #{sync_params[:type]}============errors:#{e}") | |||
| end | |||
| end | |||
| @@ -39,41 +39,63 @@ class SyncProjectsJob < ApplicationJob | |||
| SyncLog.sync_log("=========begin_to_update_project=project_id: #{project_id}============") | |||
| project = Project.find_by(id: project_id) | |||
| project.update(re[:target_params]) if re[:target_params].present? | |||
| create_target(re[:issues_params], "Issue") if re[:issues_params].present? | |||
| create_target(re[:member_params], "Member") if re[:member_params].present? | |||
| create_target(re[:watcher_params], "Watcher") if re[:watcher_params].present? | |||
| create_target(re[:praise_treads], "PraiseTread") if re[:praise_treads].present? | |||
| create_versions(project, re[:versions_params]) if re[:versions_params].present? | |||
| create_target(re[:issues_params], "Issue") if re[:issues_params].present? | |||
| end | |||
| def create_target(target_jsons, target_type) | |||
| begin | |||
| SyncLog.sync_project_log("***【#{target_type}】. begin_to_create_target---------------") | |||
| return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? | |||
| target_jsons.each_with_index do |re,index| | |||
| SyncLog.sync_project_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") | |||
| SyncLog.sync_log("***【#{target_type}】. begin_to_create_target---------------") | |||
| return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? | |||
| target_jsons.each_with_index do |re,index| | |||
| begin | |||
| SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") | |||
| if re[:target_params].present? | |||
| SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}") | |||
| u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first | |||
| re[:target_params].delete(:id) | |||
| if target_type == "Issue" | |||
| new_target = target_type.constantize.new(re[:target_params].merge(author_id: u_id)) | |||
| is_exists = Issue.exists?(author_id: u_id, project_id: re[:target_params][:project_id], subject: re[:target_params][:subject]) | |||
| unless is_exists | |||
| version_name = re[:re_version] | |||
| version_id = Version.where(project_id: re[:target_params][:project_id], name: version_name)&.first&.id if version_name.present? | |||
| assing_u_id = User.select(:id, :login).where(login: re[:assign_login]).pluck(:id).first | |||
| new_target = target_type.constantize.new(re[:target_params].merge(author_id: u_id)) | |||
| new_target.assigned_to_id = assing_u_id | |||
| new_target.fixed_version_id = version_id if version_id.present? | |||
| end | |||
| else | |||
| new_target = target_type.constantize.new(re[:target_params].merge(user_id: u_id)) | |||
| end | |||
| if target_type == "Issue" | |||
| assing_u_id = User.select(:id, :login).where(login: re[:assign_login]).pluck(:id).first | |||
| new_target.assigned_to_id = assing_u_id | |||
| case target_type | |||
| when "Journal" | |||
| 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) | |||
| when "Member" | |||
| is_exists = Member.exists?(user_id: u_id, project_id: re[:target_params][:project_id], created_on: re[:target_params][:created_on].to_s.to_time) | |||
| when "Version" | |||
| is_exists = Version.exists?(user_id: u_id, project_id: re[:target_params][:project_id], created_on: re[:target_params][:created_on].to_s.to_time) | |||
| when "Watcher" | |||
| is_exists = Watcher.exists?(user_id: u_id, watchable_id: re[:target_params][:watchable_id], created_at: re[:target_params][:created_at].to_s.to_time) | |||
| when "PraiseTread" | |||
| is_exists = PraiseTread.exists?(user_id: u_id, praise_tread_object_id: re[:target_params][:praise_tread_object_id], created_at: re[:target_params][:created_at].to_s.to_time) | |||
| else | |||
| is_exists = false | |||
| end | |||
| unless is_exists | |||
| new_target = target_type.constantize.new(re[:target_params].merge(user_id: u_id)) | |||
| end | |||
| end | |||
| if new_target.save! | |||
| SyncLog.sync_project_log("***【#{target_type}】. create_success---------------") | |||
| if !is_exists && new_target.save! | |||
| SyncLog.sync_log("***【#{target_type}】. create_success---------------") | |||
| if re[:journals].present? | |||
| create_journals(re[:journals], "Journal", new_target.id) | |||
| end | |||
| if re[:journal_details].present? | |||
| re[:journal_details].each do |j| | |||
| JournalDetail.create!(j.merge(journal_id: new_target.id)) if j.present? | |||
| unless JournalDetail.exists?(journal_id: new_target.id) | |||
| JournalDetail.create!(j.merge(journal_id: new_target.id)) if j.present? | |||
| end | |||
| end | |||
| end | |||
| if re[:member_roles].present? | |||
| @@ -82,35 +104,51 @@ class SyncProjectsJob < ApplicationJob | |||
| end | |||
| end | |||
| else | |||
| SyncLog.sync_project_log("***【#{target_type}】. create_failed---------------") | |||
| SyncLog.sync_log("***【#{target_type}】. create_failed---or has_exists---------------") | |||
| end | |||
| end | |||
| SyncLog.sync_log("***111222. end_to_create_target---------------") | |||
| rescue => e | |||
| SyncLog.sync_log("=========***【#{target_type}】creat_had_erros:#{e}===================") | |||
| next | |||
| end | |||
| SyncLog.sync_project_log("***111222. end_to_create_target---------------") | |||
| rescue => e | |||
| SyncLog.sync_project_log("=========***【#{target_type}】creat_had_erros:#{e}===================") | |||
| end | |||
| end | |||
| def create_journals(target_jsons, target_type,issue_id) | |||
| SyncLog.sync_log("***【#{target_type}】. begin_to_create_target---------------") | |||
| return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? | |||
| target_jsons.each_with_index do |re,index| | |||
| SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") | |||
| if re[:target_params].present? | |||
| u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first | |||
| re[:target_params].delete(:id) | |||
| new_target = Journal.new(re[:target_params].merge(user_id: u_id)) | |||
| new_target.journalized_id = issue_id | |||
| if new_target.save! | |||
| if re[:journal_details].present? | |||
| re[:journal_details].each do |j| | |||
| JournalDetail.create!(j.merge(journal_id: new_target.id)) | |||
| begin | |||
| SyncLog.sync_log("***user_login:#{re[:user_login]}----target_type:#{target_type}-----#{index+1}") | |||
| 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 | |||
| re[:target_params].delete(:id) | |||
| new_target = Journal.new(re[:target_params].merge(user_id: u_id)) | |||
| new_target.journalized_id = issue_id | |||
| if new_target.save! | |||
| if re[:journal_details].present? | |||
| re[:journal_details].each do |j| | |||
| JournalDetail.create!(j.merge(journal_id: new_target.id)) | |||
| end | |||
| end | |||
| else | |||
| SyncLog.sync_log("***111222. journal_create failed---------------") | |||
| end | |||
| end | |||
| end | |||
| rescue => e | |||
| SyncLog.sync_log("***111222. journal_create failed---#{e}------------") | |||
| next | |||
| end | |||
| end | |||
| SyncLog.sync_log("***111222. end_to_create_journal---------------") | |||
| end | |||
| @@ -118,19 +156,27 @@ class SyncProjectsJob < ApplicationJob | |||
| def create_versions(project, target_jsons) | |||
| SyncLog.sync_log("***【Versions】. begin_to_create_verison---------------") | |||
| return SyncLog.sync_log("*** no target_jsons") if target_jsons.blank? | |||
| all_issues = project.issues.select(:id, :project_id, :fixed_version_id) | |||
| target_jsons.each do |re| | |||
| old_id = re[:target_params][:id] | |||
| if re[:target_params].present? | |||
| u_id = User.select(:id, :login).where(login: re[:user_login]).pluck(:id).first | |||
| re[:target_params].delete(:id) | |||
| new_target = Version.new(re[:target_params].merge(user_id: u_id)) | |||
| if new_target.save! | |||
| all_issues&.where(fixed_version_id: old_id)&.update_all(fixed_version_id: new_target.id) | |||
| is_exists = Version.exists?(user_id: u_id, project_id: re[:target_params][:project_id], created_on: re[:target_params][:created_on].to_s.to_time) | |||
| if is_exists | |||
| SyncLog.sync_log("***00000. Version:#{re[:target_params][:id]}-is exists--------------") | |||
| else | |||
| re[:target_params].delete(:id) | |||
| new_target = Version.new(re[:target_params].merge(user_id: u_id)) | |||
| if new_target.save! | |||
| SyncLog.sync_log("***111222. Version_create success-#{new_target.id}--------------") | |||
| # all_issues = project.issues.select(:id, :project_id, :fixed_version_id) | |||
| # all_issues&.where(fixed_version_id: old_id)&.update_all(fixed_version_id: new_target.id) | |||
| else | |||
| SyncLog.sync_log("***111222. Version_create failed-#{old_id}--------------") | |||
| end | |||
| end | |||
| end | |||
| end | |||
| SyncLog.sync_log("***111222. end_to_create_target---------------") | |||
| end | |||
| end | |||
| end | |||
| @@ -25,13 +25,14 @@ class SyncRepositoryJob < ApplicationJob | |||
| gitlab_branches.each do |branch| | |||
| shell5 = system("cd #{path}/#{image_repo_name} && git checkout #{branch} && git push --force --set-upstream origin #{branch}") | |||
| if !shell5 | |||
| SyncLog.sync_project_log("=============force_push_erros==#{path}/#{image_repo_name}++branch:#{branch}") | |||
| SyncLog.sync_log("=============force_push_erros==#{path}/#{image_repo_name}++branch:#{branch}") | |||
| else | |||
| SyncLog.sync_project_log("=============force_push_success==#{path}/#{image_repo_name}++branch+++#{branch}") | |||
| SyncLog.sync_log("=============force_push_success==#{path}/#{image_repo_name}++branch+++#{branch}") | |||
| system("rm -rf #{path}/#{image_repo_name}") | |||
| end | |||
| end | |||
| else | |||
| SyncLog.sync_project_log("=============check_clone_erros==#{path}/#{image_repo_name}") | |||
| SyncLog.sync_log("=============check_clone_erros==#{path}/#{image_repo_name}") | |||
| SyncLog.sync_log("++++++++++++++++++check_clone_erros++++++++++++++++++#{image_repo_name}") | |||
| end | |||
| SyncLog.sync_log("=================end to sync repository=====================#{image_repo_name}") | |||
| @@ -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 | |||
| @@ -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 user’s 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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,20 @@ | |||
| module OauthEducoder | |||
| class << self | |||
| def config | |||
| educoder_config = {} | |||
| begin | |||
| config = Rails.application.config_for(:configuration).symbolize_keys! | |||
| educoder_config = config[:oauth_educoder].symbolize_keys! | |||
| raise 'oauth educoder config missing' if educoder_config.blank? | |||
| rescue => ex | |||
| raise ex if Rails.env.production? | |||
| puts %Q{\033[33m [warning] educoder config or configuration.yml missing, | |||
| please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} | |||
| educoder_config = {} | |||
| end | |||
| educoder_config | |||
| end | |||
| end | |||
| end | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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) | |||
| # | |||
| # status:0 审核中 1 同意 2 拒绝 3 撤销 | |||
| # auth_type:1 实名认证, 2 职业认证 | |||
| class ApplyUserAuthentication < ApplicationRecord | |||
| @@ -1,3 +1,36 @@ | |||
| # == 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(40) 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 | |||
| # is_publish :integer default("1") | |||
| # publish_time :datetime | |||
| # memo_image :boolean default("0") | |||
| # extra_type :integer 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_created_on (created_on) | |||
| # | |||
| class Attachment < ApplicationRecord | |||
| include BaseModel | |||
| include Publicable | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,5 @@ | |||
| module Ci | |||
| # def self.table_name_prefix | |||
| # 'ci_' | |||
| # end | |||
| end | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,7 @@ | |||
| class Ci::LocalBase < ApplicationRecord | |||
| self.abstract_class = true | |||
| def self.table_name_prefix | |||
| "ci_" | |||
| end | |||
| end | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -0,0 +1,72 @@ | |||
| # == 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") | |||
| # visibility :string(255) default("public") | |||
| # repo_admin_change_team_access :boolean default("1") | |||
| # is_org :boolean default("0") | |||
| # website :string(255) | |||
| # 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 | |||
| @@ -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 | |||
| @@ -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 | |||