diff --git a/Gemfile b/Gemfile index 5fad5f056..491b512c2 100644 --- a/Gemfile +++ b/Gemfile @@ -40,7 +40,7 @@ gem 'oauth2' #导出为pdf gem 'pdfkit' gem 'wkhtmltopdf-binary' -gem 'request_store' +# gem 'request_store' #gem 'iconv' # markdown 转html gem 'redcarpet', '~> 3.4' diff --git a/app/constraint/admin_constraint.rb b/app/constraint/admin_constraint.rb index 2cf5649a7..01ed0cad0 100644 --- a/app/constraint/admin_constraint.rb +++ b/app/constraint/admin_constraint.rb @@ -1,8 +1,13 @@ class AdminConstraint def matches?(request) - laboratory = Laboratory.first - return false unless request.session[:"#{laboratory.try(:identifier).split('.').first}_user_id"] - user = User.find request.session[:"#{laboratory.try(:identifier).split('.').first}_user_id"] - user && user.admin? + if Rails.env.development? + true + else + laboratory = Laboratory.first + return false unless request.session[:"#{laboratory.try(:identifier).split('.').first}_user_id"] + user = User.find request.session[:"#{laboratory.try(:identifier).split('.').first}_user_id"] + user && user.admin? + end + end end \ No newline at end of file diff --git a/app/controllers/sync_forge_controller.rb b/app/controllers/sync_forge_controller.rb new file mode 100644 index 000000000..c208b39dd --- /dev/null +++ b/app/controllers/sync_forge_controller.rb @@ -0,0 +1,263 @@ +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]) + Rails.logger.info("=================begin_to_update_project========") + project = Project.find_by(identifier: sync_params[:identifier]) + Rails.logger.info("--------project_id:#{project.id}---------------") + check_sync_project(project, sync_params) + else #新建项目 + Rails.logger.info("=================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) + Rails.logger.info("=================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 + 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]) + username = new_user.login + password = "12345678" + 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].merge(user_id: new_user.id)) if u[: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 + normal_status(-1, e.message) + end + + private + + def check_sync_project(project,sync_params) + begin + gitea_main = "https://ucloudtest.trustie.net/" + if request.subdomain === 'forgeplus' + gitea_main = "https://trustie.net" + end + Rails.logger.info("----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 + Rails.logger.info("=========check_sync_project_errors:#{e}===================") + end + + end + + def check_new_project(project,sync_params) + Rails.logger.info("***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://ucloudtest.trustie.net/" + if request.subdomain === 'forgeplus' + gitea_main = "https://trustie.net" + end + + SyncProjectsJob.perform_later(sync_projects_params, gitea_main) + Rails.logger.info("***8. end_to_sync_new_project---------------") + end + + def change_project_praises(project, praises,gitea_main) + Rails.logger.info("***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) + + Rails.logger.info("***6. end_to_sync_parises---------------") + end + end + + #检查repository和project_score + def change_project_score(project, project_scores, repository_params) + Rails.logger.info("***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 + Rails.logger.info("***1. end_to_sync_project_score---------------") + rescue Exception => e + Rails.logger.info("=========change_project_score_errors:#{e}===================") + end + end + + def change_project_issues(project, old_issues_params,project_id, gitea_main) + Rails.logger.info("***2. begin_to_syncissues---------------") + begin + forge_issue_ids = project&.issues&.select(:id)&.pluck(:id) + 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 + sync_projects_params = {} + 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 + SyncProjectsJob.perform_later(sync_projects_params, gitea_main) if sync_projects_params.present? + Rails.logger.info("***2. end_to_syncissues---------------") + rescue Exception => e + Rails.logger.info("=========change_project_issues_errors:#{e}===================") + end + end + + def change_project_watchers(project, watchers,gitea_main) + Rails.logger.info("***5. begin_to_sync_watchers---------------") + forge_watchers_ids = project&.watchers&.select(:id)&.pluck(:id) + 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) + Rails.logger.info("***5. begin_to_sync_watchers---------------") + + end + end + + def change_project_versions(project, versions,gitea_main) + Rails.logger.info("***4. begin_to_sync_versions---------------") + forge_version_ids = project&.versions&.select(:id)&.pluck(:id) + 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) + Rails.logger.info("***4. end_to_sync_versions---------------") + end + end + + def change_project_members(project, members,gitea_main) + Rails.logger.info("***3. begin_to_sync_members---------------") + forge_member_ids = project&.members&.select(:id)&.pluck(:id) + 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) + Rails.logger.info("***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_sudomain + Rails.logger.info("=================request.subdomain:#{request.subdomain}========") + gitea_main = "testgitea.trustie.net" + if request.subdomain === 'testforgeplus' + gitea_main = "testgitea2.trustie.net" + elsif request.subdomain === 'forge' + gitea_main = "gitea.trustie.net" + end + return gitea_main + end + +end \ No newline at end of file diff --git a/app/jobs/sync_projects_job.rb b/app/jobs/sync_projects_job.rb new file mode 100644 index 000000000..32114e335 --- /dev/null +++ b/app/jobs/sync_projects_job.rb @@ -0,0 +1,128 @@ +require 'uri' +require 'net/http' + +class SyncProjectsJob < ApplicationJob + queue_as :default + + def perform(sync_params, gitea_main) + SyncLog.sync_log("==========begin to sync #{sync_params[:type]} to forge============") + SyncLog.sync_log("==========sync_params:#{sync_params}============") + + 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}============") + if response.code == '200' + target_jsons = eval(response.body) + if sync_params[:type] == "Project" + SyncLog.sync_log("==========target_jsons: #{target_jsons}============") + update_new_project(target_jsons[:targets_params][0], sync_params[:new_project_id]) + else + create_target(target_jsons[:targets_params], sync_params[:type].to_s) + end + else + SyncLog.sync_log("==========sync_project_to_forge_failed #{sync_params[:type]}============") + end + rescue => e + SyncLog.sync_log("==========sync_project_to_forge_failed #{sync_params[:type]}============errors:#{e}") + end + end + + private + + def update_new_project(re, project_id) + 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? + end + + def create_target(target_jsons, target_type) + 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? + 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)) + 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 + end + if new_target.save! + 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? + end + end + if re[:member_roles].present? + re[:member_roles].each do |m| + MemberRole.create!(m.merge(member_id: new_target.id)) if m.present? + end + end + end + end + end + SyncLog.sync_log("***111222. end_to_create_target---------------") + 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)) + end + end + end + end + end + SyncLog.sync_log("***111222. end_to_create_journal---------------") + end + + 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) + end + end + end + SyncLog.sync_log("***111222. end_to_create_target---------------") + end + +end \ No newline at end of file diff --git a/app/jobs/sync_repository_job.rb b/app/jobs/sync_repository_job.rb new file mode 100644 index 000000000..abec4a6c0 --- /dev/null +++ b/app/jobs/sync_repository_job.rb @@ -0,0 +1,45 @@ +class SyncRepositoryJob < ApplicationJob + queue_as :default + + #同步 trustie的仓库 + + def perform(user_login, identifier, repository_params, gitea_main) + #创建临时文件夹 clone 并强推代码 + SyncLog.sync_log("=================begin to sync request trustie repository:#{repository_params}=====================") + path = "#{Rails.root}/public/cache_repository" + image_url = repository_params[:git_url] + gitlab_branches = repository_params[:gitlab_branches] + image_repo_name = image_url.to_s.split('/')&.last&.chomp('.git') + SyncLog.sync_project_log("========gitlab_branches:#{gitlab_branches}===================") + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + + if Dir.exist?("#{path}/#{image_repo_name}") + system("rm -rf #{path}/#{image_repo_name}") + end + + check_clone = system("cd #{path} && git clone #{image_url}") + SyncLog.sync_log("========check_clone:====cd #{path} && git clone #{image_url}=====success?:#{check_clone}==============") + if check_clone + + new_gitlab_url = "http://root:_Trustie_10010@#{gitea_main}/#{user_login}/#{identifier}.git" + shell_remote_1 = system("cd #{path}/#{image_repo_name} && git remote set-url origin #{new_gitlab_url}") + gitlab_branches.each do |branch| + SyncLog.sync_log("========checkout_branch:#{branch}===================") + shell5 = system("cd #{path}/#{image_repo_name} && git checkout #{branch} && git push --force --set-upstream origin #{branch}") + SyncLog.sync_log("========checkout_branch_shell5:#{shell5}===================") + if !shell5 + SyncLog.sync_project_log("=============force_push_erros==#{path}/#{image_repo_name}++branch:#{branch}") + else + SyncLog.sync_project_log("=============force_push_success==#{path}/#{image_repo_name}++branch+++#{branch}") + end + end + else + SyncLog.sync_project_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}") + end + +end \ No newline at end of file diff --git a/app/models/project.rb b/app/models/project.rb index b288c0cbd..f4fb1122f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -18,7 +18,6 @@ class Project < ApplicationRecord has_many :project_trends, dependent: :destroy has_many :watchers, as: :watchable, dependent: :destroy has_many :fork_users, dependent: :destroy - # has_many :commits, dependent: :destroy has_one :project_score, dependent: :destroy diff --git a/app/models/sync_log.rb b/app/models/sync_log.rb new file mode 100644 index 000000000..f24a0a927 --- /dev/null +++ b/app/models/sync_log.rb @@ -0,0 +1,11 @@ +class SyncLog + def self.sync_log(message=nil) + @my_log ||= Logger.new("#{Rails.root}/log/sync.log") + @my_log.debug(message) unless message.nil? + end + + def self.sync_project_log(message=nil) + @my_log ||= Logger.new("#{Rails.root}/log/sync_error_project.log") + @my_log.debug(message) unless message.nil? + end +end \ No newline at end of file diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index a512a9ab5..f4297acfe 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -12,10 +12,9 @@ class Projects::CreateService < ApplicationService @project = Project.new(project_params) ActiveRecord::Base.transaction do if @project.save! - Rails.logger.info("#############___________repository_params______###########{repository_params}") Repositories::CreateService.new(user, @project, repository_params).call else - # + Rails.logger.info("#############___________create_project_erros______###########{@project.errors.messages}") end end @project diff --git a/app/services/repositories/create_service.rb b/app/services/repositories/create_service.rb index d9d115ac2..b506d13aa 100644 --- a/app/services/repositories/create_service.rb +++ b/app/services/repositories/create_service.rb @@ -11,11 +11,11 @@ class Repositories::CreateService < ApplicationService @repository = Repository.new(repository_params) ActiveRecord::Base.transaction do if @repository.save! - Rails.logger.info("#############__________gitea_repository_params______###########{gitea_repository_params}") - gitea_repository = Gitea::Repository::CreateService.new(user.gitea_token, gitea_repository_params).call sync_project(@repository, gitea_repository) sync_repository(@repository, gitea_repository) + else + Rails.logger.info("#############___________create_repository_erros______###########{@repository.errors.messages}") end @repository end @@ -26,7 +26,7 @@ class Repositories::CreateService < ApplicationService private - def sync_project(repository, gitea_repository) + def sync_project(repository, gitea_repository) if gitea_repository project.update_columns( gpid: gitea_repository["id"], diff --git a/config/routes.rb b/config/routes.rb index ba9efd909..806699948 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,11 @@ Rails.application.routes.draw do resources :edu_settings scope '/api' do + resources :sync_forge, only: [:create] do + collection do + post :sync_users + end + end resources :composes do resources :compose_projects, only: [:create, :destroy] end diff --git a/db/migrate/20200610071625_remove_issues_lock_version_column.rb b/db/migrate/20200610071625_remove_issues_lock_version_column.rb new file mode 100644 index 000000000..2ec9477ae --- /dev/null +++ b/db/migrate/20200610071625_remove_issues_lock_version_column.rb @@ -0,0 +1,5 @@ +class RemoveIssuesLockVersionColumn < ActiveRecord::Migration[5.2] + def change + remove_column :issues, :lock_version + end +end \ No newline at end of file