From 12cc37443e12e63513f85dc59e112284ec76111d Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 9 May 2022 18:12:27 +0800 Subject: [PATCH 01/82] add: trace controller and router --- app/controllers/trace/base_controller.rb | 18 ++++++ app/controllers/trace/projects_controller.rb | 60 +++++++++++++++++++ .../trace/trace_users_controller.rb | 14 +++++ app/services/trace/check_result_service.rb | 8 +-- app/services/trace/check_service.rb | 4 +- config/routes.rb | 14 +++++ 6 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 app/controllers/trace/base_controller.rb create mode 100644 app/controllers/trace/projects_controller.rb create mode 100644 app/controllers/trace/trace_users_controller.rb diff --git a/app/controllers/trace/base_controller.rb b/app/controllers/trace/base_controller.rb new file mode 100644 index 000000000..d3fb52d1c --- /dev/null +++ b/app/controllers/trace/base_controller.rb @@ -0,0 +1,18 @@ +class Trace::BaseController < ApplicationController + + helper_method :observed_logged_user?, :observed_user + + + def observed_user + @_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id])) + end + + def observed_logged_user? + observed_user.id == User.current&.id + end + + protected + def check_auth + return render_forbidden unless current_user.admin? || observed_logged_user? + end +end \ No newline at end of file diff --git a/app/controllers/trace/projects_controller.rb b/app/controllers/trace/projects_controller.rb new file mode 100644 index 000000000..a5adcbbb1 --- /dev/null +++ b/app/controllers/trace/projects_controller.rb @@ -0,0 +1,60 @@ +class Trace::ProjectsController < Trace::BaseController + + before_action :require_login + before_action :load_project + + def tasks + branch_name = params[:branch_name] + [code, data, error] = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) + if code == 200 + render_ok + else + render_error(-1, "检测失败 Error:#{error}") + end + rescue Exception => exception + puts exception.message + normal_status(-1, exception.message) + end + + def task_results + limit = params[:limit] || params[:per_page] + limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i + page = params[:page].to_i.zero? ? 1 : params[:page].to_i + [code, data, error] = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) + if code == 200 + render :json => {data: data} + else + render_error(-1, "获取检测记录失败 Error:#{error}") + end + rescue Exception => exception + puts exception.message + normal_status(-1, exception.message) + end + + def reload_task + render_error(-1, "project_id错误") if params[:project_id].blank? + [code, data, error] = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) + if code == 200 + render_ok + else + render_error(-1, "重新检测失败 Error:#{error}") + end + rescue Exception => exception + puts exception.message + normal_status(-1, exception.message) + end + + + def task_pdf + render_error(-1, "task_id错误") if params[:task_id].blank? + [code, data, error] = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) + if code == 200 + render_ok + else + render_error(-1, "下载报告失败 Error:#{error}") + end + rescue Exception => exception + puts exception.message + normal_status(-1, exception.message) + end +end \ No newline at end of file diff --git a/app/controllers/trace/trace_users_controller.rb b/app/controllers/trace/trace_users_controller.rb new file mode 100644 index 000000000..4601c3525 --- /dev/null +++ b/app/controllers/trace/trace_users_controller.rb @@ -0,0 +1,14 @@ +class Trace::TraceUsersController < Trace::BaseController + before_action :require_auth + + def create + if current_user.trace_token.present? + render_ok + else + render_error(-1, "代码溯源用户初始化失败") + end + rescue Exception => exception + puts exception.message + normal_status(-1, exception.message) + end +end \ No newline at end of file diff --git a/app/services/trace/check_result_service.rb b/app/services/trace/check_result_service.rb index f1dd61ab0..9c177b147 100644 --- a/app/services/trace/check_result_service.rb +++ b/app/services/trace/check_result_service.rb @@ -1,11 +1,11 @@ # 代码溯源 查询检测结果 class Trace::CheckResultService < Trace::ClientService - attr_accessor :token, :project_name, :file_name, :page_num, :page_size + attr_accessor :token, :project, :file_name, :page_num, :page_size - def initialize(token, project_name=nil, file_name=nil, page_num=1, page_size=15) + def initialize(token, project, file_name=nil, page_num=1, page_size=15) @token = token - @project_name = project_name + @project = project @file_name = file_name @page_num = page_num @page_size = page_size @@ -19,7 +19,7 @@ class Trace::CheckResultService < Trace::ClientService private def request_params { - product_name: project_name, + product_name: "#{project&.owner&.login}-#{project.identifier}", file_name: file_name, pageNum: page_num, pageSize: page_size, diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index d31bbcf09..56a70b9a5 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -17,9 +17,9 @@ class Trace::CheckService < Trace::ClientService private def request_params - repo = Gitea::Repository::GetService.call(project&.owner&.login, project&.identifier) + repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier) { - product_name: project&.name, + product_name: "#{project&.owner&.login}-#{project&.identifier}", product_type: project&.category&.name, code_type: project&.language&.name, product_desc: project&.description, diff --git a/config/routes.rb b/config/routes.rb index 64dce0e60..836960fe2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -677,6 +677,20 @@ Rails.application.routes.draw do end # Project Area END + namespace :trace do + resources :trace_users, only: [:create] + scope "/:owner/:repo" do + resource :projects, path: '/', only: [:index] do + member do + post :tasks + get :task_results + get :reload_task + get :task_pdf + end + end + end + end + scope module: :helps do resources :faqs, only: [:index] end From c64fa5135b8d2bb80de409021889eafd02c1895e Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 09:18:49 +0800 Subject: [PATCH 02/82] fix --- app/controllers/trace/projects_controller.rb | 8 ++--- app/services/trace/check_result_service.rb | 2 +- app/services/trace/check_service.rb | 11 ++++--- app/services/trace/client_service.rb | 31 +++++++++++++++++--- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/app/controllers/trace/projects_controller.rb b/app/controllers/trace/projects_controller.rb index a5adcbbb1..160433fe7 100644 --- a/app/controllers/trace/projects_controller.rb +++ b/app/controllers/trace/projects_controller.rb @@ -5,7 +5,7 @@ class Trace::ProjectsController < Trace::BaseController def tasks branch_name = params[:branch_name] - [code, data, error] = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) + code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) if code == 200 render_ok else @@ -20,7 +20,7 @@ class Trace::ProjectsController < Trace::BaseController limit = params[:limit] || params[:per_page] limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i - [code, data, error] = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) + code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 render :json => {data: data} else @@ -33,7 +33,7 @@ class Trace::ProjectsController < Trace::BaseController def reload_task render_error(-1, "project_id错误") if params[:project_id].blank? - [code, data, error] = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) + code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) if code == 200 render_ok else @@ -47,7 +47,7 @@ class Trace::ProjectsController < Trace::BaseController def task_pdf render_error(-1, "task_id错误") if params[:task_id].blank? - [code, data, error] = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) + code, data, error = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) if code == 200 render_ok else diff --git a/app/services/trace/check_result_service.rb b/app/services/trace/check_result_service.rb index 9c177b147..f6a44c882 100644 --- a/app/services/trace/check_result_service.rb +++ b/app/services/trace/check_result_service.rb @@ -19,7 +19,7 @@ class Trace::CheckResultService < Trace::ClientService private def request_params { - product_name: "#{project&.owner&.login}-#{project.identifier}", + product_name: "#{project&.owner&.id}#{project.id}", file_name: file_name, pageNum: page_num, pageSize: page_size, diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index 56a70b9a5..cf1fcf133 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -11,7 +11,7 @@ class Trace::CheckService < Trace::ClientService end def call - result = authed_post(token, url, {data: request_params}) + result = http_authed_post(token, url, {data: request_params}) reponse = render_response(result) end @@ -19,9 +19,9 @@ class Trace::CheckService < Trace::ClientService def request_params repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier) { - product_name: "#{project&.owner&.login}-#{project&.identifier}", - product_type: project&.category&.name, - code_type: project&.language&.name, + product_name: "#{project&.owner&.id}#{project&.id}", + product_type: project&.project_category&.name, + code_type: project&.project_language&.name, product_desc: project&.description, git_url: repo['clone_url'], if_branch: if_branch, @@ -32,5 +32,4 @@ class Trace::CheckService < Trace::ClientService def url "/user/check".freeze end -end - +end \ No newline at end of file diff --git a/app/services/trace/client_service.rb b/app/services/trace/client_service.rb index 72ffa8ca2..9423b575d 100644 --- a/app/services/trace/client_service.rb +++ b/app/services/trace/client_service.rb @@ -12,6 +12,18 @@ class Trace::ClientService < ApplicationService conn.post(full_url(url), params[:data]) end + def http_authed_post(token, url, params={}) + puts "[trace][POST] request params: #{params}" + puts "[trace][POST] request token: #{token}" + url = URI("#{full_url(url)}") + http = Net::HTTP.new(url.host, url.port) + request = Net::HTTP::Post.new(url) + request["Authorization"] = token + form_data = params[:data].stringify_keys.to_a + request.set_form form_data, 'multipart/form-data' + http.request(request) + end + def get(url, params={}) puts "[trace][GET] request params: #{params}" conn.get do |req| @@ -100,11 +112,22 @@ class Trace::ClientService < ApplicationService end def render_response(response) - status = response.status - body = JSON.parse(response&.body) + if response.is_a?(Faraday::Response) + status = response.status + body = JSON.parse(response&.body) - log_error(status, body) + log_error(status, body) - return [body["code"], body["data"], body["error"]] + return [body["code"], body["data"], body["error"]] + end + + if response.is_a?(Net::HTTPOK) + status = 200 + body = JSON.parse(response&.body) + + log_error(status, body) + + return [body["code"], body["data"], body["error"]] + end end end \ No newline at end of file From 72a32ed8c48f608e9f647e1ee376d6ba9bb00640 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 15:04:25 +0800 Subject: [PATCH 03/82] rename namespace --- app/controllers/{trace => traces}/base_controller.rb | 0 app/controllers/{trace => traces}/projects_controller.rb | 0 app/controllers/{trace => traces}/trace_users_controller.rb | 0 config/routes.rb | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename app/controllers/{trace => traces}/base_controller.rb (100%) rename app/controllers/{trace => traces}/projects_controller.rb (100%) rename app/controllers/{trace => traces}/trace_users_controller.rb (100%) diff --git a/app/controllers/trace/base_controller.rb b/app/controllers/traces/base_controller.rb similarity index 100% rename from app/controllers/trace/base_controller.rb rename to app/controllers/traces/base_controller.rb diff --git a/app/controllers/trace/projects_controller.rb b/app/controllers/traces/projects_controller.rb similarity index 100% rename from app/controllers/trace/projects_controller.rb rename to app/controllers/traces/projects_controller.rb diff --git a/app/controllers/trace/trace_users_controller.rb b/app/controllers/traces/trace_users_controller.rb similarity index 100% rename from app/controllers/trace/trace_users_controller.rb rename to app/controllers/traces/trace_users_controller.rb diff --git a/config/routes.rb b/config/routes.rb index 836960fe2..9c3fe2ecf 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -677,7 +677,7 @@ Rails.application.routes.draw do end # Project Area END - namespace :trace do + namespace :traces do resources :trace_users, only: [:create] scope "/:owner/:repo" do resource :projects, path: '/', only: [:index] do From 17ccf3d57662eb3d6d50a0598986bff724e8d866 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 15:07:04 +0800 Subject: [PATCH 04/82] rename namespace --- app/controllers/traces/base_controller.rb | 2 +- app/controllers/traces/projects_controller.rb | 2 +- app/controllers/traces/trace_users_controller.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/traces/base_controller.rb b/app/controllers/traces/base_controller.rb index d3fb52d1c..2b857d232 100644 --- a/app/controllers/traces/base_controller.rb +++ b/app/controllers/traces/base_controller.rb @@ -1,4 +1,4 @@ -class Trace::BaseController < ApplicationController +class Traces::BaseController < ApplicationController helper_method :observed_logged_user?, :observed_user diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 160433fe7..7e91a2bc7 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -1,4 +1,4 @@ -class Trace::ProjectsController < Trace::BaseController +class Traces::ProjectsController < Trace::BaseController before_action :require_login before_action :load_project diff --git a/app/controllers/traces/trace_users_controller.rb b/app/controllers/traces/trace_users_controller.rb index 4601c3525..0b738bead 100644 --- a/app/controllers/traces/trace_users_controller.rb +++ b/app/controllers/traces/trace_users_controller.rb @@ -1,4 +1,4 @@ -class Trace::TraceUsersController < Trace::BaseController +class Traces::TraceUsersController < Trace::BaseController before_action :require_auth def create From a0a7f908f4e1f013ba541eff9e360541d14ab049 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 15:08:42 +0800 Subject: [PATCH 05/82] rename namespace --- app/controllers/traces/projects_controller.rb | 2 +- app/controllers/traces/trace_users_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 7e91a2bc7..6f329b83b 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -1,4 +1,4 @@ -class Traces::ProjectsController < Trace::BaseController +class Traces::ProjectsController < Traces::BaseController before_action :require_login before_action :load_project diff --git a/app/controllers/traces/trace_users_controller.rb b/app/controllers/traces/trace_users_controller.rb index 0b738bead..bf203c646 100644 --- a/app/controllers/traces/trace_users_controller.rb +++ b/app/controllers/traces/trace_users_controller.rb @@ -1,4 +1,4 @@ -class Traces::TraceUsersController < Trace::BaseController +class Traces::TraceUsersController < Traces::BaseController before_action :require_auth def create From 59db914bcc2e9928885a24d082b0f05726e49c33 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 15:10:01 +0800 Subject: [PATCH 06/82] change route position --- config/routes.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 9c3fe2ecf..097aaf2a7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -427,6 +427,20 @@ Rails.application.routes.draw do end end + namespace :traces do + resources :trace_users, only: [:create] + scope "/:owner/:repo" do + resource :projects, path: '/', only: [:index] do + member do + post :tasks + get :task_results + get :reload_task + get :task_pdf + end + end + end + end + # Project Area START scope "/:owner/:repo" do scope do @@ -677,20 +691,6 @@ Rails.application.routes.draw do end # Project Area END - namespace :traces do - resources :trace_users, only: [:create] - scope "/:owner/:repo" do - resource :projects, path: '/', only: [:index] do - member do - post :tasks - get :task_results - get :reload_task - get :task_pdf - end - end - end - end - scope module: :helps do resources :faqs, only: [:index] end From 2d9bde134a83b1e62d66f0e9b1075ce588f104a8 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 15:11:04 +0800 Subject: [PATCH 07/82] fix --- app/controllers/traces/trace_users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/trace_users_controller.rb b/app/controllers/traces/trace_users_controller.rb index bf203c646..70191479e 100644 --- a/app/controllers/traces/trace_users_controller.rb +++ b/app/controllers/traces/trace_users_controller.rb @@ -1,5 +1,5 @@ class Traces::TraceUsersController < Traces::BaseController - before_action :require_auth + before_action :check_auth def create if current_user.trace_token.present? From f31796f344f0be126cd0bc756a9d2a1f3721b277 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 15:53:14 +0800 Subject: [PATCH 08/82] add: branch valid for tasks --- app/controllers/accounts_controller.rb | 381 ++++++++++++++++++ app/controllers/traces/projects_controller.rb | 15 +- 2 files changed, 390 insertions(+), 6 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index a837e952f..5b4571d9d 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,3 +1,4 @@ +<<<<<<< HEAD class AccountsController < ApplicationController include ApplicationHelper @@ -384,3 +385,383 @@ class AccountsController < ApplicationController end end +======= +class AccountsController < ApplicationController + include ApplicationHelper + + #skip_before_action :check_account, :only => [:logout] + + def index + render json: session + end + + # 其他平台同步注册的用户 + def remote_register + Register::RemoteForm.new(remote_register_params).validate! + username = params[:username]&.gsub(/\s+/, "") + tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) + email = params[:email]&.gsub(/\s+/, "") + password = params[:password] + platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") + + ActiveRecord::Base.transaction do + result = autologin_register(username, email, password, platform) + if result[:message].blank? + render_ok({user: result[:user]}) + else + render_error(result[:message]) + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + + # 其他平台修改用户的信息,这边同步修改 + def remote_update + ActiveRecord::Base.transaction do + user_params = params[:user_params] + user_extension_params = params[:user_extension_params] + + u = User.find_by(login: params[:old_user_login]) + user_mail = u.try(:mail) + + if u.present? + ue = u.user_extension + u.login = user_params["login"] if user_params["login"] + u.mail = user_params["mail"] if user_params["mail"] + u.lastname = user_params["lastname"] if user_params["lastname"] + + ue.gender = user_extension_params["gender"] + ue.school_id = user_extension_params["school_id"] + ue.location = user_extension_params["location"] + ue.location_city = user_extension_params["location_city"] + ue.identity = user_extension_params["identity"] + ue.technical_title = user_extension_params["technical_title"] + ue.student_id = user_extension_params["student_id"] + ue.description = user_extension_params["description"] + ue.save! + u.save! + + sync_params = {} + + if (user_params["mail"] && user_params["mail"] != user_mail) + sync_params = sync_params.merge(email: user_params["mail"]) + end + + if sync_params.present? + interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) + if interactor.success? + render_ok + else + render_error(interactor.error) + end + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + + # 其他平台同步登录 + def remote_login + @user = User.try_to_login(params[:login], params[:password]) + if @user + successful_authentication(@user) + render_ok({user: {id: @user.id, token: @user.gitea_token}}) + else + render_error("用户不存在") + end + end + + #修改密码 + def remote_password + @user = User.find_by(login: params[:login]) + return render_error("未找到相关用户!") if @user.blank? + + sync_params = { + password: params[:password].to_s, + email: @user.mail + } + + interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) + if interactor.success? + @user.update_attribute(:password, params[:password]) + render_ok + else + render_error(interactor.error) + end + end + + + + # 用户注册 + # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 + # params[:login] 邮箱或者手机号 + # params[:namespace] 登录名 + # params[:code] 验证码 + # code_type 1:注册手机验证码 8:邮箱注册验证码 + # 本地forge注册入口需要重新更改逻辑 + def register + # type只可能是1或者8 + user = nil + begin + Register::Form.new(register_params).validate! + + user = Users::RegisterService.call(register_params) + password = register_params[:password].strip + + # gitea用户注册, email, username, password + interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.call(user.login, password) + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user[:body]['id'] + if user.save! + UserExtension.create!(user_id: user.id) + successful_authentication(user) + render_ok + end + else + tip_exception(-1, interactor.error) + end + rescue Register::BaseForm::EmailError => e + tip_exception(-2, e.message) + rescue Register::BaseForm::LoginError => e + tip_exception(-3, e.message) + rescue Register::BaseForm::PhoneError => e + tip_exception(-4, e.message) + rescue Register::BaseForm::PasswordFormatError => e + tip_exception(-5, e.message) + rescue Register::BaseForm::VerifiCodeError => e + tip_exception(-6, e.message) + rescue Exception => e + Gitea::User::DeleteService.call(user.login) unless user.nil? + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + end + + # 用户登录 + def login + Users::LoginForm.new(account_params).validate! + @user = User.try_to_login(params[:login], params[:password]) + + return normal_status(-2, "错误的账号或密码") if @user.blank? + # user is already in local database + return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? + + login_control = LimitForbidControl::UserLogin.new(@user) + return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? + + password_ok = @user.check_password?(params[:password].to_s) + unless password_ok + if login_control.remain_times-1 == 0 + normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") + else + normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") + end + login_control.increment! + return + end + + successful_authentication(@user) + sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 + + # session[:user_id] = @user.id + end + + def change_password + @user = User.find_by(login: params[:login]) + return render_error("未找到相关用户!") if @user.blank? + return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) + + sync_params = { + password: params[:password].to_s, + email: @user.mail, + login_name: @user.login, + source_id: 0 + } + + interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) + if interactor.success? + @user.update_attribute(:password, params[:password]) + render_ok + else + render_error(interactor.error) + end + end + + # 忘记密码 + def reset_password + begin + code = params[:code] + login_type = phone_mail_type(params[:login].strip) + # 获取验证码 + if login_type == 1 + phone = params[:login] + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last + user = User.find_by_phone(phone) + else + email = params[:login] + verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last + user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs + end + return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip + return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD + + user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] + ActiveRecord::Base.transaction do + user.save! + LimitForbidControl::UserLogin.new(user).clear + end + sucess_status + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + end + + def successful_authentication(user) + uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + + set_autologin_cookie(user) + UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) + user.update_column(:last_login_on, Time.now) + session[:"#{default_yun_session}"] = user.id + Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") + # 注册完成后有一天的试用申请(先去掉) + # UserDayCertification.create(user_id: user.id, status: 1) + end + + 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, + :path => '/', + :secure => false, + :httponly => true + } + if edu_setting('cookie_domain').present? + cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) + end + cookies[autologin_cookie_name] = cookie_options + cookies.signed[:user_id] ||= user.id + + logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") + end + + def logout + Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") + UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) + logout_user + render :json => {status: 1, message: "退出成功!"} + end + + # 检验邮箱是否已被注册及邮箱或者手机号是否合法 + # 参数type为事件类型 1:注册;2:忘记密码;3:绑定 + def valid_email_and_phone + check_mail_and_phone_valid(params[:login], params[:type]) + end + + # 发送验证码 + # params[:login] 手机号或者邮箱号 + # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 + # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效 + def get_verification_code + code = %W(0 1 2 3 4 5 6 7 8 9) + value = params[:login] + type = params[:type].strip.to_i + login_type = phone_mail_type(value) + send_type = verify_type(login_type, type) + verification_code = code.sample(6).join + + sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") + tip_exception(501, "请求不合理") if sign != params[:smscode] + + logger.info "########### 验证码:#{verification_code}" + logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") + + # 记录验证码 + check_verification_code(verification_code, send_type, value) + render_ok + end + + # check user's login or email or phone is used + # params[:value] 手机号或者邮箱号或者登录名 + # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) + def check + Register::CheckColumnsForm.new(check_params).validate! + render_ok + end + + private + + # type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 + # login_type 1:手机类型 2:邮箱类型 + def verify_type login_type, type + case type + when 1 + login_type == 1 ? 1 : 8 + when 2 + login_type == 1 ? 2 : 3 + when 3 + login_type == 1 ? 4 : tip_exception('请填写正确的手机号') + when 4 + login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 + when 5 + login_type == 1 ? 9 : tip_exception('请填写正确的手机号') + end + end + + def generate_login(login) + type = phone_mail_type(login.strip) + + if type == 1 + uid_logger("start register by phone: type is #{type}") + pre = 'p' + email = nil + phone = login + else + uid_logger("start register by email: type is #{type}") + pre = 'm' + email = login + phone = nil + end + code = generate_identifier User, 8, pre + + { login: pre + code, email: email, phone: phone } + end + + def user_params + params.require(:user).permit(:login, :email, :phone) + end + + def account_params + params.require(:account).permit(:login, :password) + end + + def check_params + params.permit(:type, :value) + end + + def register_params + params.permit(:login, :namespace, :password, :code) + end + + def remote_register_params + params.permit(:username, :email, :password, :platform) + end + +end +>>>>>>> b62824ad (add: branch valid for tasks) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 6f329b83b..66bfb71b0 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -5,11 +5,14 @@ class Traces::ProjectsController < Traces::BaseController def tasks branch_name = params[:branch_name] + return render_error("分支名不能为空!") if branch_name.blank? + @all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier) + return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) if code == 200 render_ok else - render_error(-1, "检测失败 Error:#{error}") + render_error("检测失败 Error:#{error}") end rescue Exception => exception puts exception.message @@ -24,7 +27,7 @@ class Traces::ProjectsController < Traces::BaseController if code == 200 render :json => {data: data} else - render_error(-1, "获取检测记录失败 Error:#{error}") + render_error("获取检测记录失败 Error:#{error}") end rescue Exception => exception puts exception.message @@ -32,12 +35,12 @@ class Traces::ProjectsController < Traces::BaseController end def reload_task - render_error(-1, "project_id错误") if params[:project_id].blank? + return render_error("project_id错误") if params[:project_id].blank? code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) if code == 200 render_ok else - render_error(-1, "重新检测失败 Error:#{error}") + render_error("重新检测失败 Error:#{error}") end rescue Exception => exception puts exception.message @@ -46,12 +49,12 @@ class Traces::ProjectsController < Traces::BaseController def task_pdf - render_error(-1, "task_id错误") if params[:task_id].blank? + return render_error("task_id错误") if params[:task_id].blank? code, data, error = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) if code == 200 render_ok else - render_error(-1, "下载报告失败 Error:#{error}") + render_error("下载报告失败 Error:#{error}") end rescue Exception => exception puts exception.message From cf09b28f5ef4ae8bce8cbaa2170c77ae214bb0b6 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 16:14:27 +0800 Subject: [PATCH 09/82] add: project menu services --- app/controllers/projects_controller.rb | 1 + app/models/project_unit.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 8bc2fb476..2d0f0f5cd 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -22,6 +22,7 @@ class ProjectsController < ApplicationController menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge? menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions") menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge? + menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge? menu.append(menu_hash_by_name("activity")) menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge? diff --git a/app/models/project_unit.rb b/app/models/project_unit.rb index cc35a6b28..6ee0f2a8b 100644 --- a/app/models/project_unit.rb +++ b/app/models/project_unit.rb @@ -16,7 +16,7 @@ class ProjectUnit < ApplicationRecord belongs_to :project - enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7} + enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7, services: 8} validates :unit_type, uniqueness: { scope: :project_id} From 5dcee1b4dc486de1706dc56cd2453538869f9e1b Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 10 May 2022 17:10:19 +0800 Subject: [PATCH 10/82] add: traces api document --- app/docs/slate/source/api.html.md | 1 + app/docs/slate/source/includes/_projects.md | 4 +- app/docs/slate/source/includes/_traces.md | 216 ++++++++++++++ public/docs/api.html | 307 +++++++++++++++++++- 4 files changed, 524 insertions(+), 4 deletions(-) create mode 100644 app/docs/slate/source/includes/_traces.md diff --git a/app/docs/slate/source/api.html.md b/app/docs/slate/source/api.html.md index a846317c4..0031a99f4 100644 --- a/app/docs/slate/source/api.html.md +++ b/app/docs/slate/source/api.html.md @@ -16,6 +16,7 @@ includes: - users - projects - repositories + - traces - pulls - issues - organizations diff --git a/app/docs/slate/source/includes/_projects.md b/app/docs/slate/source/includes/_projects.md index d4899a710..08ad6c234 100644 --- a/app/docs/slate/source/includes/_projects.md +++ b/app/docs/slate/source/includes/_projects.md @@ -280,7 +280,7 @@ repo |是| |string |项目标识identifier ### 返回字段说明 参数 | 类型 | 字段说明 --------- | ----------- | ----------- -menu_name |string|导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置 +menu_name |string|导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,services:服务,activity:动态,setting:仓库设置 > 返回的JSON示例: @@ -408,7 +408,7 @@ await octokit.request('POST /api/yystopf/ceshi/project_units') ### 请求参数 参数 | 必选 | 默认 | 类型 | 字段说明 --------- | ------- | ------- | -------- | ---------- -|unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑 | +|unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,resources:资源库,services:服务 | ### 返回字段说明: diff --git a/app/docs/slate/source/includes/_traces.md b/app/docs/slate/source/includes/_traces.md new file mode 100644 index 000000000..6bdfb950a --- /dev/null +++ b/app/docs/slate/source/includes/_traces.md @@ -0,0 +1,216 @@ +# Traces + +## 代码溯源初始化 +用户同意协议后请求的接口,创建代码溯源的账号 + +> 示例: + +```shell +curl -X POST \ +http://localhost:3000/api/traces/trace_users.json +``` + +```javascript +await octokit.request('POST /api/traces/trace_users.json') +``` + +### HTTP 请求 +`POST api/traces/trace_users.json` + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 代码分析结果列表 +查询项目下代码分析的结果 + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/traces/yystopf/many_branch/task_results.json +``` + +```javascript +await octokit.request('GET /api/traces/:owner/:repo/task_results.json') +``` + +### HTTP 请求 +`GET api/traces/:owner/:repo/task_results.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +owner|是|否|string | 项目所有者标识| +repo|是 | 否|string | 项目标识 | +page |否| 1 | int | 页码 | +limit |否| 15 | int | 每页数量 | + +### 返回字段说明(暂缺) + + +> 返回的JSON示例: + +```json +{ + "data": [ + { + "accuracy": "20", + "code_type": "C", + "depth": "2", + "detect_flag": "快速-组件级", + "detect_rule": "快速-组件级,2,20,,开源软件,50,10", + "detect_startdate": "2022-05-10 15:59:46 ", + "detect_status": "fail", + "detectflag": "快速-组件级", + "fail_reason": "Invalid package type", + "file_name": "many_branch.zip", + "license_process": "100", + "licenseparam": "开源软件", + "package_type": "", + "product_name": "84727546110", + "project_id": "6dbc3e42-5857-4ca4-a54d-58fd9dbf6dc5", + "sim_process": "100", + "similarity_process": "2", + "task_id": "15139171-091b-4316-98b1-6068970efa44", + "totalsize": 5, + "uid": "78", + "vuln_process": "", + "vulnlevel": "" + } + ] +} +``` + + + + +## 新建分析 +用户选择仓库分支进行代码分析的接口 + +> 示例: + +```shell +curl -X POST \ +http://localhost:3000/api/traces/yystopf/many_branch/tasks.json +``` + +```javascript +await octokit.request('POST /api/traces/:owner/:repo/tasks.json') +``` + +### HTTP 请求 +`POST api/traces/:owner/:repo/tasks.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +owner |是 | 否 | string | 项目所有者标识 | +repo |是 | 否 | string | 项目标识 | +branch_name|是 | 否| string | 分支名称 | + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 重新扫描 +对代码分析结果进行再次分析 + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/traces/yystopf/many_branch/reload_task.json +``` + +```javascript +await octokit.request('GET /api/traces/:owner/:repo/reload_task.json') +``` + +### HTTP 请求 +`GET api/traces/:owner/:repo/reload_task.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +owner |是 | 否 | string | 项目所有者标识 | +repo |是 | 否 | string | 项目标识 | +project_id|是 | 否| string | 代码分析结果里的project_id | + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + + +## 下载报告 +把代码分析的结果下载到本地 + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/traces/yystopf/many_branch/task_pdf.json +``` + +```javascript +await octokit.request('GET /api/traces/:owner/:repo/task_pdf.json') +``` + +### HTTP 请求 +`GET api/traces/:owner/:repo/task_pdf.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +owner |是 | 否 | string | 项目所有者标识 | +repo |是 | 否 | string | 项目标识 | +task_id|是 | 否| string | 代码分析结果里的task_id | + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + diff --git a/public/docs/api.html b/public/docs/api.html index 45da64400..1fe7bc08e 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -543,6 +543,26 @@ +
  • + Traces + +
  • Pulls
      @@ -4968,7 +4988,7 @@ http://localhost:3000/api/yystopf/ceshi/menu_list | jq menu_name string -导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置 +导航名称, home:主页,code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,services:服务,activity:动态,setting:仓库设置 @@ -5131,7 +5151,7 @@ http://localhost:3000/api/yystopf/ceshi/project_units.json 是 array -项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑 +项目模块内容, 支持以下参数:code:代码库,issues:疑修,pulls:合并请求,devops:工作流,versions:里程碑,wiki:维基,resources:资源库,services:服务

      返回字段说明:

      @@ -9302,6 +9322,289 @@ http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json +

      Traces

      代码溯源初始化

      +

      用户同意协议后请求的接口,创建代码溯源的账号

      + +
      +

      示例:

      +
      +
      curl -X POST \
      +http://localhost:3000/api/traces/trace_users.json
      +
      await octokit.request('POST /api/traces/trace_users.json')
      +

      HTTP 请求

      +

      POST api/traces/trace_users.json

      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "status": 0,
      +    "message": "success"
      +}
      +
      + +

      代码分析结果列表

      +

      查询项目下代码分析的结果

      + +
      +

      示例:

      +
      +
      curl -X GET \
      +http://localhost:3000/api/traces/yystopf/many_branch/task_results.json
      +
      await octokit.request('GET /api/traces/:owner/:repo/task_results.json')
      +

      HTTP 请求

      +

      GET api/traces/:owner/:repo/task_results.json

      +

      请求参数

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      ownerstring项目所有者标识
      repostring项目标识
      page1int页码
      limit15int每页数量
      +

      返回字段说明(暂缺)

      + + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "data": [
      +        {
      +            "accuracy": "20",
      +            "code_type": "C",
      +            "depth": "2",
      +            "detect_flag": "快速-组件级",
      +            "detect_rule": "快速-组件级,2,20,,开源软件,50,10",
      +            "detect_startdate": "2022-05-10 15:59:46 ",
      +            "detect_status": "fail",
      +            "detectflag": "快速-组件级",
      +            "fail_reason": "Invalid package type",
      +            "file_name": "many_branch.zip",
      +            "license_process": "100",
      +            "licenseparam": "开源软件",
      +            "package_type": "",
      +            "product_name": "84727546110",
      +            "project_id": "6dbc3e42-5857-4ca4-a54d-58fd9dbf6dc5",
      +            "sim_process": "100",
      +            "similarity_process": "2",
      +            "task_id": "15139171-091b-4316-98b1-6068970efa44",
      +            "totalsize": 5,
      +            "uid": "78",
      +            "vuln_process": "",
      +            "vulnlevel": ""
      +        }
      +    ]
      +}
      +
      + +

      新建分析

      +

      用户选择仓库分支进行代码分析的接口

      + +
      +

      示例:

      +
      +
      curl -X POST \
      +http://localhost:3000/api/traces/yystopf/many_branch/tasks.json
      +
      await octokit.request('POST /api/traces/:owner/:repo/tasks.json')
      +

      HTTP 请求

      +

      POST api/traces/:owner/:repo/tasks.json

      +

      请求参数

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      ownerstring项目所有者标识
      repostring项目标识
      branch_namestring分支名称
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "status": 0,
      +    "message": "success"
      +}
      +
      + +

      重新扫描

      +

      对代码分析结果进行再次分析

      + +
      +

      示例:

      +
      +
      curl -X GET \
      +http://localhost:3000/api/traces/yystopf/many_branch/reload_task.json
      +
      await octokit.request('GET /api/traces/:owner/:repo/reload_task.json')
      +

      HTTP 请求

      +

      GET api/traces/:owner/:repo/reload_task.json

      +

      请求参数

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      ownerstring项目所有者标识
      repostring项目标识
      project_idstring代码分析结果里的project_id
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "status": 0,
      +    "message": "success"
      +}
      +
      + +

      下载报告

      +

      把代码分析的结果下载到本地

      + +
      +

      示例:

      +
      +
      curl -X GET \
      +http://localhost:3000/api/traces/yystopf/many_branch/task_pdf.json
      +
      await octokit.request('GET /api/traces/:owner/:repo/task_pdf.json')
      +

      HTTP 请求

      +

      GET api/traces/:owner/:repo/task_pdf.json

      +

      请求参数

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      参数必选默认类型字段说明
      ownerstring项目所有者标识
      repostring项目标识
      task_idstring代码分析结果里的task_id
      + +
      +

      返回的JSON示例:

      +
      +
      {
      +    "status": 0,
      +    "message": "success"
      +}
      +
      +

      Pulls

      Get a pull request

      获取合并请求详情接口

      From 1f13bba52e6a88a3baf5d975b3bd36b583ad9b5f Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 11 May 2022 10:34:35 +0800 Subject: [PATCH 11/82] add: trace user tasks_count --- app/controllers/traces/projects_controller.rb | 3 +++ app/models/trace_user.rb | 25 ++++++++++--------- ...11022334_add_tasks_count_to_trace_users.rb | 5 ++++ 3 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 db/migrate/20220511022334_add_tasks_count_to_trace_users.rb diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 66bfb71b0..1b09bd971 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -5,11 +5,13 @@ class Traces::ProjectsController < Traces::BaseController def tasks branch_name = params[:branch_name] + return render_error("无可用检测次数") if current_user.trace_user&.tasks_count >= 5 return render_error("分支名不能为空!") if branch_name.blank? @all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier) return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) if code == 200 + current_user.trace_user.increment!(:tasks_count, 1) render_ok else render_error("检测失败 Error:#{error}") @@ -25,6 +27,7 @@ class Traces::ProjectsController < Traces::BaseController page = params[:page].to_i.zero? ? 1 : params[:page].to_i code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 + current_user.trace_user.update_column(:tasks_count, data[0]["totalsize"]) if data.size > 0 render :json => {data: data} else render_error("获取检测记录失败 Error:#{error}") diff --git a/app/models/trace_user.rb b/app/models/trace_user.rb index e89641565..0e8b3d119 100644 --- a/app/models/trace_user.rb +++ b/app/models/trace_user.rb @@ -2,18 +2,19 @@ # # Table name: trace_users # -# id :integer not null, primary key -# user_id :integer -# username :string(255) -# password :string(255) -# unit :string(255) -# telnumber :string(255) -# email :string(255) -# name :string(255) -# token :text(65535) -# expired_at :datetime -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# user_id :integer +# username :string(255) +# password :string(255) +# unit :string(255) +# telnumber :string(255) +# email :string(255) +# name :string(255) +# token :text(65535) +# expired_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# tasks_count :integer default("0") # # Indexes # diff --git a/db/migrate/20220511022334_add_tasks_count_to_trace_users.rb b/db/migrate/20220511022334_add_tasks_count_to_trace_users.rb new file mode 100644 index 000000000..035d93a94 --- /dev/null +++ b/db/migrate/20220511022334_add_tasks_count_to_trace_users.rb @@ -0,0 +1,5 @@ +class AddTasksCountToTraceUsers < ActiveRecord::Migration[5.2] + def change + add_column :trace_users, :tasks_count, :integer, default: 0 + end +end From 7750cbe272d0177b46b3b2062b4e7e88eed590df Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 11 May 2022 11:20:18 +0800 Subject: [PATCH 12/82] add: project trace tasks count --- app/controllers/traces/projects_controller.rb | 6 ++--- app/models/trace_user.rb | 25 +++++++++---------- ...11022334_add_tasks_count_to_trace_users.rb | 5 ---- ...31711_add_trace_tasks_count_to_projects.rb | 5 ++++ 4 files changed, 20 insertions(+), 21 deletions(-) delete mode 100644 db/migrate/20220511022334_add_tasks_count_to_trace_users.rb create mode 100644 db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 1b09bd971..812ea535b 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -5,13 +5,13 @@ class Traces::ProjectsController < Traces::BaseController def tasks branch_name = params[:branch_name] - return render_error("无可用检测次数") if current_user.trace_user&.tasks_count >= 5 + return render_error("无可用检测次数") if @project&.trace_tasks_count >= 5 return render_error("分支名不能为空!") if branch_name.blank? @all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier) return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) if code == 200 - current_user.trace_user.increment!(:tasks_count, 1) + @project.increment!(:trace_tasks_count, 1) render_ok else render_error("检测失败 Error:#{error}") @@ -27,7 +27,7 @@ class Traces::ProjectsController < Traces::BaseController page = params[:page].to_i.zero? ? 1 : params[:page].to_i code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 - current_user.trace_user.update_column(:tasks_count, data[0]["totalsize"]) if data.size > 0 + @project.update_column(:trace_tasks_count, data[0]["totalsize"]) if data.size > 0 render :json => {data: data} else render_error("获取检测记录失败 Error:#{error}") diff --git a/app/models/trace_user.rb b/app/models/trace_user.rb index 0e8b3d119..e89641565 100644 --- a/app/models/trace_user.rb +++ b/app/models/trace_user.rb @@ -2,19 +2,18 @@ # # Table name: trace_users # -# id :integer not null, primary key -# user_id :integer -# username :string(255) -# password :string(255) -# unit :string(255) -# telnumber :string(255) -# email :string(255) -# name :string(255) -# token :text(65535) -# expired_at :datetime -# created_at :datetime not null -# updated_at :datetime not null -# tasks_count :integer default("0") +# id :integer not null, primary key +# user_id :integer +# username :string(255) +# password :string(255) +# unit :string(255) +# telnumber :string(255) +# email :string(255) +# name :string(255) +# token :text(65535) +# expired_at :datetime +# created_at :datetime not null +# updated_at :datetime not null # # Indexes # diff --git a/db/migrate/20220511022334_add_tasks_count_to_trace_users.rb b/db/migrate/20220511022334_add_tasks_count_to_trace_users.rb deleted file mode 100644 index 035d93a94..000000000 --- a/db/migrate/20220511022334_add_tasks_count_to_trace_users.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddTasksCountToTraceUsers < ActiveRecord::Migration[5.2] - def change - add_column :trace_users, :tasks_count, :integer, default: 0 - end -end diff --git a/db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb b/db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb new file mode 100644 index 000000000..fcbeff6b6 --- /dev/null +++ b/db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb @@ -0,0 +1,5 @@ +class AddTraceTasksCountToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :trace_tasks_count, :integer, default: 0 + end +end From 12c961d70d74c6d7a57c7a4c5a738f35d3184bff Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 09:19:19 +0800 Subject: [PATCH 13/82] fix --- app/controllers/traces/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 812ea535b..a1f4b14db 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -27,7 +27,7 @@ class Traces::ProjectsController < Traces::BaseController page = params[:page].to_i.zero? ? 1 : params[:page].to_i code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 - @project.update_column(:trace_tasks_count, data[0]["totalsize"]) if data.size > 0 + @project.update_column(:trace_tasks_count, data[0]["totalsize"]) if data.is_a?(Array) && data.size > 0 render :json => {data: data} else render_error("获取检测记录失败 Error:#{error}") From 9b3336c0a0ad3aa1bcb1c4b3a50251d72d91cbac Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 09:26:17 +0800 Subject: [PATCH 14/82] fix: reload task need increment tasks count --- app/controllers/traces/projects_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index a1f4b14db..8bd423878 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -41,6 +41,7 @@ class Traces::ProjectsController < Traces::BaseController return render_error("project_id错误") if params[:project_id].blank? code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) if code == 200 + @project.increment!(:trace_tasks_count, 1) render_ok else render_error("重新检测失败 Error:#{error}") From 3eccd6be648afaa0d532670c1d49730d8bc7b22a Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 09:45:37 +0800 Subject: [PATCH 15/82] add: user has trace user field --- app/controllers/accounts_controller.rb | 381 -------------------- app/views/users/get_user_info.json.jbuilder | 1 + 2 files changed, 1 insertion(+), 381 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 5b4571d9d..a837e952f 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,4 +1,3 @@ -<<<<<<< HEAD class AccountsController < ApplicationController include ApplicationHelper @@ -385,383 +384,3 @@ class AccountsController < ApplicationController end end -======= -class AccountsController < ApplicationController - include ApplicationHelper - - #skip_before_action :check_account, :only => [:logout] - - def index - render json: session - end - - # 其他平台同步注册的用户 - def remote_register - Register::RemoteForm.new(remote_register_params).validate! - username = params[:username]&.gsub(/\s+/, "") - tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) - email = params[:email]&.gsub(/\s+/, "") - password = params[:password] - platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") - - ActiveRecord::Base.transaction do - result = autologin_register(username, email, password, platform) - if result[:message].blank? - render_ok({user: result[:user]}) - else - render_error(result[:message]) - end - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - - # 其他平台修改用户的信息,这边同步修改 - def remote_update - ActiveRecord::Base.transaction do - user_params = params[:user_params] - user_extension_params = params[:user_extension_params] - - u = User.find_by(login: params[:old_user_login]) - user_mail = u.try(:mail) - - if u.present? - ue = u.user_extension - u.login = user_params["login"] if user_params["login"] - u.mail = user_params["mail"] if user_params["mail"] - u.lastname = user_params["lastname"] if user_params["lastname"] - - ue.gender = user_extension_params["gender"] - ue.school_id = user_extension_params["school_id"] - ue.location = user_extension_params["location"] - ue.location_city = user_extension_params["location_city"] - ue.identity = user_extension_params["identity"] - ue.technical_title = user_extension_params["technical_title"] - ue.student_id = user_extension_params["student_id"] - ue.description = user_extension_params["description"] - ue.save! - u.save! - - sync_params = {} - - if (user_params["mail"] && user_params["mail"] != user_mail) - sync_params = sync_params.merge(email: user_params["mail"]) - end - - if sync_params.present? - interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) - if interactor.success? - render_ok - else - render_error(interactor.error) - end - end - end - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - - # 其他平台同步登录 - def remote_login - @user = User.try_to_login(params[:login], params[:password]) - if @user - successful_authentication(@user) - render_ok({user: {id: @user.id, token: @user.gitea_token}}) - else - render_error("用户不存在") - end - end - - #修改密码 - def remote_password - @user = User.find_by(login: params[:login]) - return render_error("未找到相关用户!") if @user.blank? - - sync_params = { - password: params[:password].to_s, - email: @user.mail - } - - interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) - if interactor.success? - @user.update_attribute(:password, params[:password]) - render_ok - else - render_error(interactor.error) - end - end - - - - # 用户注册 - # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 - # params[:login] 邮箱或者手机号 - # params[:namespace] 登录名 - # params[:code] 验证码 - # code_type 1:注册手机验证码 8:邮箱注册验证码 - # 本地forge注册入口需要重新更改逻辑 - def register - # type只可能是1或者8 - user = nil - begin - Register::Form.new(register_params).validate! - - user = Users::RegisterService.call(register_params) - password = register_params[:password].strip - - # gitea用户注册, email, username, password - interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) - if interactor.success? - gitea_user = interactor.result - result = Gitea::User::GenerateTokenService.call(user.login, password) - user.gitea_token = result['sha1'] - user.gitea_uid = gitea_user[:body]['id'] - if user.save! - UserExtension.create!(user_id: user.id) - successful_authentication(user) - render_ok - end - else - tip_exception(-1, interactor.error) - end - rescue Register::BaseForm::EmailError => e - tip_exception(-2, e.message) - rescue Register::BaseForm::LoginError => e - tip_exception(-3, e.message) - rescue Register::BaseForm::PhoneError => e - tip_exception(-4, e.message) - rescue Register::BaseForm::PasswordFormatError => e - tip_exception(-5, e.message) - rescue Register::BaseForm::VerifiCodeError => e - tip_exception(-6, e.message) - rescue Exception => e - Gitea::User::DeleteService.call(user.login) unless user.nil? - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - end - - # 用户登录 - def login - Users::LoginForm.new(account_params).validate! - @user = User.try_to_login(params[:login], params[:password]) - - return normal_status(-2, "错误的账号或密码") if @user.blank? - # user is already in local database - return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? - - login_control = LimitForbidControl::UserLogin.new(@user) - return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? - - password_ok = @user.check_password?(params[:password].to_s) - unless password_ok - if login_control.remain_times-1 == 0 - normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") - else - normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") - end - login_control.increment! - return - end - - successful_authentication(@user) - sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 - - # session[:user_id] = @user.id - end - - def change_password - @user = User.find_by(login: params[:login]) - return render_error("未找到相关用户!") if @user.blank? - return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) - - sync_params = { - password: params[:password].to_s, - email: @user.mail, - login_name: @user.login, - source_id: 0 - } - - interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) - if interactor.success? - @user.update_attribute(:password, params[:password]) - render_ok - else - render_error(interactor.error) - end - end - - # 忘记密码 - def reset_password - begin - code = params[:code] - login_type = phone_mail_type(params[:login].strip) - # 获取验证码 - if login_type == 1 - phone = params[:login] - verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last - user = User.find_by_phone(phone) - else - email = params[:login] - verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last - user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs - end - return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip - return normal_status(-2, "验证码已失效") if !verifi_code&.effective? - return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD - - user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] - ActiveRecord::Base.transaction do - user.save! - LimitForbidControl::UserLogin.new(user).clear - end - sucess_status - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end - end - - def successful_authentication(user) - uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") - # Valid user - self.logged_user = user - # generate a key and set cookie if autologin - - set_autologin_cookie(user) - UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) - user.update_column(:last_login_on, Time.now) - session[:"#{default_yun_session}"] = user.id - Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") - # 注册完成后有一天的试用申请(先去掉) - # UserDayCertification.create(user_id: user.id, status: 1) - end - - 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, - :path => '/', - :secure => false, - :httponly => true - } - if edu_setting('cookie_domain').present? - cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) - end - cookies[autologin_cookie_name] = cookie_options - cookies.signed[:user_id] ||= user.id - - logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") - end - - def logout - Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") - UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) - logout_user - render :json => {status: 1, message: "退出成功!"} - end - - # 检验邮箱是否已被注册及邮箱或者手机号是否合法 - # 参数type为事件类型 1:注册;2:忘记密码;3:绑定 - def valid_email_and_phone - check_mail_and_phone_valid(params[:login], params[:type]) - end - - # 发送验证码 - # params[:login] 手机号或者邮箱号 - # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 - # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 - # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效 - def get_verification_code - code = %W(0 1 2 3 4 5 6 7 8 9) - value = params[:login] - type = params[:type].strip.to_i - login_type = phone_mail_type(value) - send_type = verify_type(login_type, type) - verification_code = code.sample(6).join - - sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") - tip_exception(501, "请求不合理") if sign != params[:smscode] - - logger.info "########### 验证码:#{verification_code}" - logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") - - # 记录验证码 - check_verification_code(verification_code, send_type, value) - render_ok - end - - # check user's login or email or phone is used - # params[:value] 手机号或者邮箱号或者登录名 - # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) - def check - Register::CheckColumnsForm.new(check_params).validate! - render_ok - end - - private - - # type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 - # login_type 1:手机类型 2:邮箱类型 - def verify_type login_type, type - case type - when 1 - login_type == 1 ? 1 : 8 - when 2 - login_type == 1 ? 2 : 3 - when 3 - login_type == 1 ? 4 : tip_exception('请填写正确的手机号') - when 4 - login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 - when 5 - login_type == 1 ? 9 : tip_exception('请填写正确的手机号') - end - end - - def generate_login(login) - type = phone_mail_type(login.strip) - - if type == 1 - uid_logger("start register by phone: type is #{type}") - pre = 'p' - email = nil - phone = login - else - uid_logger("start register by email: type is #{type}") - pre = 'm' - email = login - phone = nil - end - code = generate_identifier User, 8, pre - - { login: pre + code, email: email, phone: phone } - end - - def user_params - params.require(:user).permit(:login, :email, :phone) - end - - def account_params - params.require(:account).permit(:login, :password) - end - - def check_params - params.permit(:type, :value) - end - - def register_params - params.permit(:login, :namespace, :password, :code) - end - - def remote_register_params - params.permit(:username, :email, :password, :platform) - end - -end ->>>>>>> b62824ad (add: branch valid for tasks) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index 95085580e..d60f46ade 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -25,3 +25,4 @@ json.description @user.description json.super_description @user.super_description json.(@user, :show_email, :show_department, :show_location, :show_super_description) json.message_unread_total @message_unread_total +json.has_trace_user @user.trace_user.present? \ No newline at end of file From 5d771c824bd112ed0da84da0790aada04dac8380 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 11:12:34 +0800 Subject: [PATCH 16/82] add: operate permission and request timeout --- app/controllers/traces/projects_controller.rb | 2 ++ app/services/trace/client_service.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 8bd423878..191f04e83 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -1,7 +1,9 @@ class Traces::ProjectsController < Traces::BaseController + include OperateProjectAbilityAble before_action :require_login before_action :load_project + before_action :authorizate_user_can_edit_project! def tasks branch_name = params[:branch_name] diff --git a/app/services/trace/client_service.rb b/app/services/trace/client_service.rb index 9423b575d..09aa617e1 100644 --- a/app/services/trace/client_service.rb +++ b/app/services/trace/client_service.rb @@ -18,6 +18,7 @@ class Trace::ClientService < ApplicationService url = URI("#{full_url(url)}") http = Net::HTTP.new(url.host, url.port) request = Net::HTTP::Post.new(url) + request.read_timeout = 1200 request["Authorization"] = token form_data = params[:data].stringify_keys.to_a request.set_form form_data, 'multipart/form-data' From 498ee26f59d2e6f43c218a2d721f9ec3c674d928 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 11:14:17 +0800 Subject: [PATCH 17/82] fix --- app/services/trace/client_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/trace/client_service.rb b/app/services/trace/client_service.rb index 09aa617e1..0f1449225 100644 --- a/app/services/trace/client_service.rb +++ b/app/services/trace/client_service.rb @@ -17,8 +17,8 @@ class Trace::ClientService < ApplicationService puts "[trace][POST] request token: #{token}" url = URI("#{full_url(url)}") http = Net::HTTP.new(url.host, url.port) + http.read_timeout = 1200 request = Net::HTTP::Post.new(url) - request.read_timeout = 1200 request["Authorization"] = token form_data = params[:data].stringify_keys.to_a request.set_form form_data, 'multipart/form-data' From 00fc83235f8b4360140c1695379730438defbb85 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 17:11:16 +0800 Subject: [PATCH 18/82] download file use redirect --- app/controllers/traces/projects_controller.rb | 11 ++++++----- .../message_template/project_setting_changed.rb | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 191f04e83..1bf5515dd 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -57,11 +57,12 @@ class Traces::ProjectsController < Traces::BaseController def task_pdf return render_error("task_id错误") if params[:task_id].blank? code, data, error = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) - if code == 200 - render_ok - else - render_error("下载报告失败 Error:#{error}") - end + domain = Trace.trace_config[:domain] + base_url = Trace.trace_config[:base_url] + url = "/user/pdfreport?task_id=#{params[:task_id]}" + file_path = [domain, api_url, url].join + request.headers["Authorization"] = current_user.trace_token + redirect_to file_path rescue Exception => exception puts exception.message normal_status(-1, exception.message) diff --git a/app/models/message_template/project_setting_changed.rb b/app/models/message_template/project_setting_changed.rb index 0920dfe7a..ab597122a 100644 --- a/app/models/message_template/project_setting_changed.rb +++ b/app/models/message_template/project_setting_changed.rb @@ -141,6 +141,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate navbar.gsub!('devops', '工作流') navbar.gsub!('versions', '里程碑') navbar.gsub!('resources', '资源库') + navbar.gsub!('services', '服务') if change_count > 1 content.sub!('{ifnavbar}', '
      ') else @@ -290,6 +291,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate navbar.gsub!('devops', '工作流') navbar.gsub!('versions', '里程碑') navbar.gsub!('resources', '资源库') + navbar.gsub!('services', '服务') if change_count > 1 content.sub!('{ifnavbar}', '
      ') else From 4dccdfde974d1660afb23e1b7658d488d1f9be46 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 17:15:19 +0800 Subject: [PATCH 19/82] fix --- app/controllers/traces/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 1bf5515dd..4945d9c7d 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -60,7 +60,7 @@ class Traces::ProjectsController < Traces::BaseController domain = Trace.trace_config[:domain] base_url = Trace.trace_config[:base_url] url = "/user/pdfreport?task_id=#{params[:task_id]}" - file_path = [domain, api_url, url].join + file_path = [domain, base_url, url].join request.headers["Authorization"] = current_user.trace_token redirect_to file_path rescue Exception => exception From 3d9fe5bba56faaa0de53690c619f5aa81df327a3 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 12 May 2022 17:52:19 +0800 Subject: [PATCH 20/82] add: download pdf from trace server --- .gitignore | 3 ++- app/controllers/traces/projects_controller.rb | 13 +++++------ app/services/trace/pdf_report_service.rb | 23 ++++++++++++++----- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index fbed31a8e..2eac1d277 100644 --- a/.gitignore +++ b/.gitignore @@ -84,4 +84,5 @@ redis_data/ Dockerfile dump.rdb .tags* -ceshi_user.xlsx \ No newline at end of file +ceshi_user.xlsx +public/trace_task_results \ No newline at end of file diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 4945d9c7d..bd9eb8661 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -56,13 +56,12 @@ class Traces::ProjectsController < Traces::BaseController def task_pdf return render_error("task_id错误") if params[:task_id].blank? - code, data, error = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) - domain = Trace.trace_config[:domain] - base_url = Trace.trace_config[:base_url] - url = "/user/pdfreport?task_id=#{params[:task_id]}" - file_path = [domain, base_url, url].join - request.headers["Authorization"] = current_user.trace_token - redirect_to file_path + result = Trace::PdfReportService.call(current_user.trace_token, params[:task_id]) + if result.is_a?(Hash) && result[:code] == 200 + redirect_to result[:download_url] + else + render_error("下载报告失败!") + end rescue Exception => exception puts exception.message normal_status(-1, exception.message) diff --git a/app/services/trace/pdf_report_service.rb b/app/services/trace/pdf_report_service.rb index e91a78b30..244698641 100644 --- a/app/services/trace/pdf_report_service.rb +++ b/app/services/trace/pdf_report_service.rb @@ -1,4 +1,7 @@ # 代码溯源 导出pdf +require 'open-uri' +require 'fileutils' + class Trace::PdfReportService < Trace::ClientService attr_accessor :token, :task_id @@ -9,15 +12,23 @@ class Trace::PdfReportService < Trace::ClientService end def call - result = authed_get(token, url, request_params) - response = render_response(result) + content = URI.open("#{domain}#{base_url}#{url}?task_id#{task_id}", "Authorization" => token) + if content.is_a?(Tempfile) + check_file_path + IO.copy_stream(content, "#{save_path}/#{task_id}.zip") + return {code: 200, download_url: "/trace_task_results/#{task_id}.zip"} + else + return {code: 404} + end end private - def request_params - { - task_id: task_id - } + def check_file_path + FileUtils.mkdir_p save_path + end + + def save_path + "public/trace_task_results" end def url From 7fcbbb79225a390f6196fd34e466eb074b0a0319 Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 13 May 2022 13:53:25 +0800 Subject: [PATCH 21/82] fix: remove project tasks_count --- app/controllers/traces/projects_controller.rb | 6 +++--- app/services/trace/pdf_report_service.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index bd9eb8661..a1847d808 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -7,13 +7,13 @@ class Traces::ProjectsController < Traces::BaseController def tasks branch_name = params[:branch_name] - return render_error("无可用检测次数") if @project&.trace_tasks_count >= 5 + # return render_error("无可用检测次数") if @project&.trace_tasks_count >= 5 return render_error("分支名不能为空!") if branch_name.blank? @all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier) return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) if code == 200 - @project.increment!(:trace_tasks_count, 1) + # @project.increment!(:trace_tasks_count, 1) render_ok else render_error("检测失败 Error:#{error}") @@ -43,7 +43,7 @@ class Traces::ProjectsController < Traces::BaseController return render_error("project_id错误") if params[:project_id].blank? code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) if code == 200 - @project.increment!(:trace_tasks_count, 1) + # @project.increment!(:trace_tasks_count, 1) render_ok else render_error("重新检测失败 Error:#{error}") diff --git a/app/services/trace/pdf_report_service.rb b/app/services/trace/pdf_report_service.rb index 244698641..aa7312739 100644 --- a/app/services/trace/pdf_report_service.rb +++ b/app/services/trace/pdf_report_service.rb @@ -12,11 +12,11 @@ class Trace::PdfReportService < Trace::ClientService end def call - content = URI.open("#{domain}#{base_url}#{url}?task_id#{task_id}", "Authorization" => token) + content = open("#{domain}#{base_url}#{url}?task_id=#{task_id}", "Authorization" => token) if content.is_a?(Tempfile) check_file_path - IO.copy_stream(content, "#{save_path}/#{task_id}.zip") - return {code: 200, download_url: "/trace_task_results/#{task_id}.zip"} + IO.copy_stream(content, "#{save_path}/#{task_id}.pdf") + return {code: 200, download_url: "/trace_task_results/#{task_id}.pdf"} else return {code: 404} end From 0e4c0a46c2df885883366076e313f6bb681890ee Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 13 May 2022 13:56:12 +0800 Subject: [PATCH 22/82] fix --- .../20220511031711_add_trace_tasks_count_to_projects.rb | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb diff --git a/db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb b/db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb deleted file mode 100644 index fcbeff6b6..000000000 --- a/db/migrate/20220511031711_add_trace_tasks_count_to_projects.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddTraceTasksCountToProjects < ActiveRecord::Migration[5.2] - def change - add_column :projects, :trace_tasks_count, :integer, default: 0 - end -end From 2c7bb1b5cd5a9c3f1541130b80441c29fd02dab7 Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 13 May 2022 14:00:21 +0800 Subject: [PATCH 23/82] fix: remove project tasks_count --- app/controllers/traces/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index a1847d808..ff4e42627 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -29,7 +29,7 @@ class Traces::ProjectsController < Traces::BaseController page = params[:page].to_i.zero? ? 1 : params[:page].to_i code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 - @project.update_column(:trace_tasks_count, data[0]["totalsize"]) if data.is_a?(Array) && data.size > 0 + # @project.update_column(:trace_tasks_count, data[0]["totalsize"]) if data.is_a?(Array) && data.size > 0 render :json => {data: data} else render_error("获取检测记录失败 Error:#{error}") From 94881dd72a5c5e0ee0d7659ad11e4a96e961d2ad Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 13 May 2022 14:31:59 +0800 Subject: [PATCH 24/82] add: user trace tasks record --- app/controllers/traces/projects_controller.rb | 19 +++++++++++--- app/docs/slate/source/includes/_traces.md | 1 + app/models/project.rb | 1 + app/models/user.rb | 1 + app/models/user_trace_task.rb | 25 +++++++++++++++++++ .../20220513061129_create_user_trace_tasks.rb | 12 +++++++++ spec/models/user_trace_task_spec.rb | 5 ++++ 7 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 app/models/user_trace_task.rb create mode 100644 db/migrate/20220513061129_create_user_trace_tasks.rb create mode 100644 spec/models/user_trace_task_spec.rb diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index ff4e42627..cd6dcd1e0 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -13,7 +13,12 @@ class Traces::ProjectsController < Traces::BaseController return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) code, data, error = Trace::CheckService.call(current_user.trace_token, @project, "1", branch_name) if code == 200 - # @project.increment!(:trace_tasks_count, 1) + UserTraceTask.create!( + user_id: current_user.id, + project_id: @project.id, + branch_tag: branch_name, + task_id: data["task_id"] + ) render_ok else render_error("检测失败 Error:#{error}") @@ -29,7 +34,6 @@ class Traces::ProjectsController < Traces::BaseController page = params[:page].to_i.zero? ? 1 : params[:page].to_i code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 - # @project.update_column(:trace_tasks_count, data[0]["totalsize"]) if data.is_a?(Array) && data.size > 0 render :json => {data: data} else render_error("获取检测记录失败 Error:#{error}") @@ -41,9 +45,18 @@ class Traces::ProjectsController < Traces::BaseController def reload_task return render_error("project_id错误") if params[:project_id].blank? + branch_name = params[:branch_name] + return render_error("分支名不能为空!") if branch_name.blank? + @all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier) + return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) code, data, error = Trace::ReloadCheckService.call(current_user.trace_token, params[:project_id]) if code == 200 - # @project.increment!(:trace_tasks_count, 1) + UserTraceTask.create!( + user_id: current_user.id, + project_id: @project.id, + branch_tag: branch_name, + task_id: data["task_id"] + ) render_ok else render_error("重新检测失败 Error:#{error}") diff --git a/app/docs/slate/source/includes/_traces.md b/app/docs/slate/source/includes/_traces.md index 6bdfb950a..e6aa24b48 100644 --- a/app/docs/slate/source/includes/_traces.md +++ b/app/docs/slate/source/includes/_traces.md @@ -163,6 +163,7 @@ await octokit.request('GET /api/traces/:owner/:repo/reload_task.json') owner |是 | 否 | string | 项目所有者标识 | repo |是 | 否 | string | 项目标识 | project_id|是 | 否| string | 代码分析结果里的project_id | +branch_name|是 | 否| string | 分支名称 | > 返回的JSON示例: diff --git a/app/models/project.rb b/app/models/project.rb index a35fbf387..1edc088f6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -124,6 +124,7 @@ class Project < ApplicationRecord has_many :pinned_projects, dependent: :destroy has_many :has_pinned_users, through: :pinned_projects, source: :user has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id + has_many :user_trace_tasks, dependent: :destroy after_create :incre_user_statistic, :incre_platform_statistic after_save :check_project_members before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data diff --git a/app/models/user.rb b/app/models/user.rb index 66aeb6164..bf764c148 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -175,6 +175,7 @@ class User < Owner has_many :system_notification_histories has_many :system_notifications, through: :system_notification_histories has_one :trace_user, dependent: :destroy + has_many :user_trace_tasks, dependent: :destroy # Groups and active users scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } diff --git a/app/models/user_trace_task.rb b/app/models/user_trace_task.rb new file mode 100644 index 000000000..328cb7c0b --- /dev/null +++ b/app/models/user_trace_task.rb @@ -0,0 +1,25 @@ +# == Schema Information +# +# Table name: user_trace_tasks +# +# id :integer not null, primary key +# user_id :integer +# project_id :integer +# branch_tag :string(255) +# task_id :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_user_trace_tasks_on_project_id (project_id) +# index_user_trace_tasks_on_user_id (user_id) +# + +class UserTraceTask < ApplicationRecord + + belongs_to :user + belongs_to :project + + +end diff --git a/db/migrate/20220513061129_create_user_trace_tasks.rb b/db/migrate/20220513061129_create_user_trace_tasks.rb new file mode 100644 index 000000000..db96ea402 --- /dev/null +++ b/db/migrate/20220513061129_create_user_trace_tasks.rb @@ -0,0 +1,12 @@ +class CreateUserTraceTasks < ActiveRecord::Migration[5.2] + def change + create_table :user_trace_tasks do |t| + t.references :user + t.references :project + t.string :branch_tag + t.string :task_id + + t.timestamps + end + end +end diff --git a/spec/models/user_trace_task_spec.rb b/spec/models/user_trace_task_spec.rb new file mode 100644 index 000000000..b2542f57a --- /dev/null +++ b/spec/models/user_trace_task_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe UserTraceTask, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From 9e8c576ff6c5f93a12c8d1893b180c8112ed661e Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 13 May 2022 15:38:04 +0800 Subject: [PATCH 25/82] fix: remove require manager operate --- app/controllers/traces/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index cd6dcd1e0..15d7102eb 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -3,7 +3,7 @@ class Traces::ProjectsController < Traces::BaseController before_action :require_login before_action :load_project - before_action :authorizate_user_can_edit_project! + # before_action :authorizate_user_can_edit_project! def tasks branch_name = params[:branch_name] From 04a733d99f9366164b9ce7710edab3651b58c81d Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 13 May 2022 16:57:41 +0800 Subject: [PATCH 26/82] fix: check user trace tasks count --- app/controllers/traces/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 15d7102eb..fee8fda9e 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -7,7 +7,7 @@ class Traces::ProjectsController < Traces::BaseController def tasks branch_name = params[:branch_name] - # return render_error("无可用检测次数") if @project&.trace_tasks_count >= 5 + return render_error("无可用检测次数") if @project.user_trace_tasks.size >= 5 return render_error("分支名不能为空!") if branch_name.blank? @all_branches = Gitea::Repository::Branches::ListNameService.call(@project&.owner, @project.identifier) return render_error("请输入正确的分支名!") unless @all_branches["branch_name"].include?(branch_name) From 5a728e7d4d104d2732326ac0e6eed1e948ae8b46 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 09:58:47 +0800 Subject: [PATCH 27/82] fix: trace user exist and compact tasks create params --- app/controllers/traces/projects_controller.rb | 1 + app/services/trace/check_service.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index fee8fda9e..b3c2ef66a 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -32,6 +32,7 @@ class Traces::ProjectsController < Traces::BaseController limit = params[:limit] || params[:per_page] limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i + return render :json => {data: []} if current_user.trace_user.nil? code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 render :json => {data: data} diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index cf1fcf133..f12319502 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -26,7 +26,7 @@ class Trace::CheckService < Trace::ClientService git_url: repo['clone_url'], if_branch: if_branch, branch_tag: branch_tag - } + }.compact end def url From a6efae8b10c993b7ba98de2dc955acbcde857162 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 10:48:23 +0800 Subject: [PATCH 28/82] fix --- app/services/trace/check_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index f12319502..a13f6d3be 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -20,8 +20,8 @@ class Trace::CheckService < Trace::ClientService repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier) { product_name: "#{project&.owner&.id}#{project&.id}", - product_type: project&.project_category&.name, - code_type: project&.project_language&.name, + product_type: project&.project_category&.name || '其他', + code_type: project&.project_language&.name || '其他', product_desc: project&.description, git_url: repo['clone_url'], if_branch: if_branch, From 2f4ffe3d8e800c8e1561a93c1c7a71df183d6296 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 14:25:54 +0800 Subject: [PATCH 29/82] fix: change trace user post valid --- app/controllers/traces/trace_users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/trace_users_controller.rb b/app/controllers/traces/trace_users_controller.rb index 70191479e..9002a5abd 100644 --- a/app/controllers/traces/trace_users_controller.rb +++ b/app/controllers/traces/trace_users_controller.rb @@ -1,5 +1,5 @@ class Traces::TraceUsersController < Traces::BaseController - before_action :check_auth + # before_action :check_auth def create if current_user.trace_token.present? From acbd0d376ce483f229394d07c05268062f1d438f Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 14:26:21 +0800 Subject: [PATCH 30/82] fix: change trace user post valid --- app/controllers/traces/trace_users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/traces/trace_users_controller.rb b/app/controllers/traces/trace_users_controller.rb index 9002a5abd..0b28e905a 100644 --- a/app/controllers/traces/trace_users_controller.rb +++ b/app/controllers/traces/trace_users_controller.rb @@ -1,5 +1,5 @@ class Traces::TraceUsersController < Traces::BaseController - # before_action :check_auth + before_action :require_login def create if current_user.trace_token.present? From 77620f77358a402ed257dd144055b5ed512c3079 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 16:59:25 +0800 Subject: [PATCH 31/82] add: download and import user template xlsx --- .../admins/import_users_controller.rb | 2 +- .../admins/new_import_user_from_excel.rb | 15 ++++ .../admins/import_user_from_excel_service.rb | 71 ++++++++++++++++++ app/views/admins/users/index.html.erb | 4 +- public/导入用户模板.xlsx | Bin 0 -> 9230 bytes 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 app/imports/admins/new_import_user_from_excel.rb create mode 100644 app/services/admins/import_user_from_excel_service.rb create mode 100644 public/导入用户模板.xlsx diff --git a/app/controllers/admins/import_users_controller.rb b/app/controllers/admins/import_users_controller.rb index 5d8a60ce6..4575b08d5 100644 --- a/app/controllers/admins/import_users_controller.rb +++ b/app/controllers/admins/import_users_controller.rb @@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController def create return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) - result = Admins::ImportUserService.call(params[:file].to_io) + result = Admins::ImportUserFromExcelService.call(params[:file].to_io) render_ok(result) rescue Admins::ImportUserService::Error => ex render_error(ex) diff --git a/app/imports/admins/new_import_user_from_excel.rb b/app/imports/admins/new_import_user_from_excel.rb new file mode 100644 index 000000000..b9a452cf1 --- /dev/null +++ b/app/imports/admins/new_import_user_from_excel.rb @@ -0,0 +1,15 @@ +class Admins::NewImportUserFromExcel < BaseImportXlsx + UserData = Struct.new(:login, :email, :password, :nickname) + + def read_each(&block) + sheet.each_row_streaming(pad_cells: true, offset: 1) do |row| + data = row.map(&method(:cell_value))[0..3] + block.call UserData.new(*data) + end + end + + private + def cell_value(obj) + obj&.cell_value + end +end \ No newline at end of file diff --git a/app/services/admins/import_user_from_excel_service.rb b/app/services/admins/import_user_from_excel_service.rb new file mode 100644 index 000000000..709551c23 --- /dev/null +++ b/app/services/admins/import_user_from_excel_service.rb @@ -0,0 +1,71 @@ +class Admins::ImportUserFromExcelService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :file, :result + + def initialize(file) + @file = file + @result = { success: 0, fail: [] } + end + + def call + raise Error, '文件不存在' if file.blank? + excel = Admins::NewImportUserFromExcel.new(file) + + excel.read_each(&method(:save_user)) + result + rescue ApplicationImport::Error => ex + raise Error, ex.message + end + + private + def save_user(data) + user = find_user(data) + if user.blank? + create_user(data) + result[:success] +=1 + else + fail_data = data.as_json + fail_data[:data] = fail_data.values.join(",") + fail_data[:message] = '用户已存在' + result[:fail] << fail_data + end + + rescue Exception => ex + fail_data = data.as_json + fail_data[:data] = fail_data.values.join(",") + fail_data[:message] = ex.message + result[:fail] << fail_data + end + + def create_user(data) + ActiveRecord::Base.transaction do + username = data.login&.gsub(/\s+/, "") + email = data.email&.gsub(/\s+/, "") + password = data.password + nickname = data.nickname&.gsub(/\s+/, "") + raise Error, "无法使用以下关键词:#{username},请重新命名" if ReversedKeyword.check_exists?(data.login) + Register::RemoteForm.new({username: username, email: email, password: password, platform: 'forge'}).validate! + user = User.new(admin: false, login: username, mail: email, nickname: nickname, platform: 'forge' , type: "User") + user.password = password + user.activate + raise Error, user.errors.full_messages.join(",") unless user.valid? + interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.call(username, password) + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user[:body]['id'] + UserExtension.create!(user_id: user.id) if user.save! + else + raise interactor.error, 'gitea user create error' + end + + user + end + end + + def find_user(data) + User.find_by(login: data.login) + end +end \ No newline at end of file diff --git a/app/views/admins/users/index.html.erb b/app/views/admins/users/index.html.erb index e21a3d665..2f41ffdb6 100644 --- a/app/views/admins/users/index.html.erb +++ b/app/views/admins/users/index.html.erb @@ -31,7 +31,9 @@ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> <% end %> - <%= javascript_void_link '导入用户', class: 'btn btn-secondary btn-sm', data: { toggle: 'modal', target: '.admin-import-user-modal'} %> + <%= link_to '下载导入模板', "/导入用户模板.xlsx", class: 'btn btn-secondary mr-3' %> + + <%= javascript_void_link '导入用户', class: 'btn btn-secondary', data: { toggle: 'modal', target: '.admin-import-user-modal'} %> diff --git a/public/导入用户模板.xlsx b/public/导入用户模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c538bed63aab06831ab7286e6a1ffe52a0337864 GIT binary patch literal 9230 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 literal 0 HcmV?d00001 From 8ae6a0deb29c0f554f9c4b5ce4f24a68fbdb3f1f Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 17:02:38 +0800 Subject: [PATCH 32/82] fix: some feature about permission --- app/controllers/projects_controller.rb | 2 +- app/controllers/traces/projects_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2d0f0f5cd..cbe9fc890 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -22,7 +22,7 @@ class ProjectsController < ApplicationController menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge? menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions") menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge? - menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? + menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && @project.member(current_user.id) menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge? menu.append(menu_hash_by_name("activity")) menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge? diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index b3c2ef66a..41200e411 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -3,7 +3,7 @@ class Traces::ProjectsController < Traces::BaseController before_action :require_login before_action :load_project - # before_action :authorizate_user_can_edit_project! + before_action :authorizate_user_can_edit_project!, except: [:task_results] def tasks branch_name = params[:branch_name] From f51ebaad67a8d407c3e2a3a0e8fd945765cb3a60 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 16 May 2022 17:08:52 +0800 Subject: [PATCH 33/82] fix --- app/controllers/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index cbe9fc890..277112265 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -22,7 +22,7 @@ class ProjectsController < ApplicationController menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge? menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions") menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge? - menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && @project.member(current_user.id) + menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && @project.member?(current_user.id) menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge? menu.append(menu_hash_by_name("activity")) menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge? From 4fade5d0b7a88040df4126515c73026ec16cc53d Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 17 May 2022 11:34:08 +0800 Subject: [PATCH 34/82] fix: project trace tasks name rule change --- app/controllers/projects_controller.rb | 2 +- app/controllers/traces/projects_controller.rb | 4 ++-- app/services/trace/check_result_service.rb | 2 +- app/services/trace/check_service.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 277112265..68c4e59fb 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -22,7 +22,7 @@ class ProjectsController < ApplicationController menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge? menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions") menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge? - menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && @project.member?(current_user.id) + menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && (current_user.admin? || @project.member?(current_user.id)) menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge? menu.append(menu_hash_by_name("activity")) menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge? diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 41200e411..4b0d6cf85 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -32,10 +32,10 @@ class Traces::ProjectsController < Traces::BaseController limit = params[:limit] || params[:per_page] limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i - return render :json => {data: []} if current_user.trace_user.nil? + return render :json => {left_tasks_count: 5, data: []} if current_user.trace_user.nil? code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 - render :json => {data: data} + render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size ,data: data} else render_error("获取检测记录失败 Error:#{error}") end diff --git a/app/services/trace/check_result_service.rb b/app/services/trace/check_result_service.rb index f6a44c882..2a673b7ff 100644 --- a/app/services/trace/check_result_service.rb +++ b/app/services/trace/check_result_service.rb @@ -19,7 +19,7 @@ class Trace::CheckResultService < Trace::ClientService private def request_params { - product_name: "#{project&.owner&.id}#{project.id}", + product_name: Digest::MD5.hexdigest.new(project&.id.to_s), file_name: file_name, pageNum: page_num, pageSize: page_size, diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index a13f6d3be..9a1cac60c 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -19,7 +19,7 @@ class Trace::CheckService < Trace::ClientService def request_params repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier) { - product_name: "#{project&.owner&.id}#{project&.id}", + product_name: Digest::MD5.hexdigest.new(project&.id.to_s), product_type: project&.project_category&.name || '其他', code_type: project&.project_language&.name || '其他', product_desc: project&.description, From 077926de181b0bc640c7397c46671d9a53ff46c9 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 17 May 2022 11:39:57 +0800 Subject: [PATCH 35/82] fix --- app/controllers/traces/projects_controller.rb | 2 +- app/services/trace/check_result_service.rb | 2 +- app/services/trace/check_service.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/traces/projects_controller.rb b/app/controllers/traces/projects_controller.rb index 4b0d6cf85..62573a1d8 100644 --- a/app/controllers/traces/projects_controller.rb +++ b/app/controllers/traces/projects_controller.rb @@ -35,7 +35,7 @@ class Traces::ProjectsController < Traces::BaseController return render :json => {left_tasks_count: 5, data: []} if current_user.trace_user.nil? code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit) if code == 200 - render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size ,data: data} + render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size, data: data} else render_error("获取检测记录失败 Error:#{error}") end diff --git a/app/services/trace/check_result_service.rb b/app/services/trace/check_result_service.rb index 2a673b7ff..444462eac 100644 --- a/app/services/trace/check_result_service.rb +++ b/app/services/trace/check_result_service.rb @@ -19,7 +19,7 @@ class Trace::CheckResultService < Trace::ClientService private def request_params { - product_name: Digest::MD5.hexdigest.new(project&.id.to_s), + product_name: Digest::MD5.hexdigest(project&.id.to_s), file_name: file_name, pageNum: page_num, pageSize: page_size, diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index 9a1cac60c..b440b0b04 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -19,7 +19,7 @@ class Trace::CheckService < Trace::ClientService def request_params repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier) { - product_name: Digest::MD5.hexdigest.new(project&.id.to_s), + product_name: Digest::MD5.hexdigest(project&.id.to_s), product_type: project&.project_category&.name || '其他', code_type: project&.project_language&.name || '其他', product_desc: project&.description, From bfd3298cd0111f9c913451e88c3d9b45615a4b05 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 17 May 2022 11:42:43 +0800 Subject: [PATCH 36/82] fix --- app/services/trace/check_result_service.rb | 2 +- app/services/trace/check_service.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/trace/check_result_service.rb b/app/services/trace/check_result_service.rb index 444462eac..ff47d9a39 100644 --- a/app/services/trace/check_result_service.rb +++ b/app/services/trace/check_result_service.rb @@ -19,7 +19,7 @@ class Trace::CheckResultService < Trace::ClientService private def request_params { - product_name: Digest::MD5.hexdigest(project&.id.to_s), + product_name: Digest::MD5.hexdigest(project&.id.to_s)[0...20], file_name: file_name, pageNum: page_num, pageSize: page_size, diff --git a/app/services/trace/check_service.rb b/app/services/trace/check_service.rb index b440b0b04..d1623445b 100644 --- a/app/services/trace/check_service.rb +++ b/app/services/trace/check_service.rb @@ -19,7 +19,7 @@ class Trace::CheckService < Trace::ClientService def request_params repo = Gitea::Repository::GetService.call(project&.owner, project&.identifier) { - product_name: Digest::MD5.hexdigest(project&.id.to_s), + product_name: Digest::MD5.hexdigest(project&.id.to_s)[0...20], product_type: project&.project_category&.name || '其他', code_type: project&.project_language&.name || '其他', product_desc: project&.description, From 9cd18397f7a7ddeec987fc9851d661171b294698 Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 18 May 2022 10:11:09 +0800 Subject: [PATCH 37/82] fix: import user login length required --- app/libs/custom_regexp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/libs/custom_regexp.rb b/app/libs/custom_regexp.rb index 25c3ae988..72184630a 100644 --- a/app/libs/custom_regexp.rb +++ b/app/libs/custom_regexp.rb @@ -1,7 +1,7 @@ module CustomRegexp PHONE = /1\d{10}/ EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/ - LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 + LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}/ #只含有数字、字母、下划线不能以下划线开头和结尾 LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/ NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/ From ca3c56452917b968d0b302728686757e20708657 Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 18 May 2022 11:03:39 +0800 Subject: [PATCH 38/82] fix: not found user return 404 --- app/controllers/owners_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/owners_controller.rb b/app/controllers/owners_controller.rb index 067fe4da1..863f8aa3a 100644 --- a/app/controllers/owners_controller.rb +++ b/app/controllers/owners_controller.rb @@ -11,6 +11,8 @@ class OwnersController < ApplicationController end def show + return render_not_found unless @user.present? + @owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id]) # return render_not_found unless @owner.present? # 组织 From e237fd46f7d151a3162f806a6042dae03abad34e Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 18 May 2022 11:37:23 +0800 Subject: [PATCH 39/82] fix: not found user return 404 --- app/controllers/owners_controller.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/owners_controller.rb b/app/controllers/owners_controller.rb index 863f8aa3a..28a5210d5 100644 --- a/app/controllers/owners_controller.rb +++ b/app/controllers/owners_controller.rb @@ -11,10 +11,8 @@ class OwnersController < ApplicationController end def show - return render_not_found unless @user.present? - @owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id]) - # return render_not_found unless @owner.present? + return render_not_found unless @owner.present? # 组织 if @owner.is_a?(Organization) return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition From 83e43f0c9792010817828abcc117294e2e287303 Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 20 May 2022 11:43:22 +0800 Subject: [PATCH 40/82] add: new readme delay function --- app/helpers/repositories_helper.rb | 39 +++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index b8bfc31cd..9fd45249c 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -87,6 +87,42 @@ module RepositoriesHelper end end + # author hui.he + def new_readme_render_decode64_content(str, owner, repo, ref) + path = [owner&.login, repo&.identifier, 'tree', ref].join("/") + return nil if str.blank? + content = Base64.decode64(str).force_encoding('UTF-8') + s_regex = /\[.*?\]\((.*?)\)/ + src_regex = /src=\"(.*?)\"/ + ss = content.to_s.scan(s_regex) + ss_src = content.to_s.scan(src_regex) + total_sources = ss + ss_src + total_sources.uniq! + total_sources.each do |s| + begin + s_content = s[0] + # 链接直接跳过不做替换 + next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') + # 路径替换 + if s_content.starts_with?('./') || s_content.starts_with?("../") || s_content.starts_with?("/") + s_content = File.expand_path(s_content, path) + s_content = s_content.split("#{Rails.root}/")[1] + content = content.gsub(s[0], "/#{s_content}") + else + # 图片资源替换 + s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join + content = content.gsub(s[0], s_content) + end + rescue + next + end + end + + return content + rescue + return str + end + # unix_time values for example: 1604382982 def render_format_time_with_unix(unix_time) Time.at(unix_time).strftime("%Y-%m-%d %H:%M") @@ -102,7 +138,8 @@ module RepositoriesHelper Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}") content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] Rails.logger.info("content===#{content}") - readme_render_decode64_content(content, owner, repo, ref) + # readme_render_decode64_content(content, owner, repo, ref) + new_readme_render_decode64_content(content, owner, repo, ref) else file_type = File.extname(entry['name'].to_s)[1..-1] if image_type?(file_type) From 779c86108a547da22ef3cb2148906c49cbea196f Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 20 May 2022 17:00:02 +0800 Subject: [PATCH 41/82] fix: readme relative delay and replace_content --- app/controllers/repositories_controller.rb | 3 +- app/helpers/repositories_helper.rb | 30 +++++++++++++------ .../repositories/_simple_entry.json.jbuilder | 7 +++-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 272e121a0..a2ab33b23 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -225,7 +225,8 @@ class RepositoriesController < ApplicationController @path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" @readme = result[:status] === :success ? result[:body] : nil @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) - render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha") + @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path) + render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content") rescue render json: nil end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 9fd45249c..1897f3ae0 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -88,8 +88,8 @@ module RepositoriesHelper end # author hui.he - def new_readme_render_decode64_content(str, owner, repo, ref) - path = [owner&.login, repo&.identifier, 'tree', ref].join("/") + def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name) + file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '') return nil if str.blank? content = Base64.decode64(str).force_encoding('UTF-8') s_regex = /\[.*?\]\((.*?)\)/ @@ -103,15 +103,19 @@ module RepositoriesHelper s_content = s[0] # 链接直接跳过不做替换 next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') - # 路径替换 - if s_content.starts_with?('./') || s_content.starts_with?("../") || s_content.starts_with?("/") + ext = File.extname(s_content)[1..-1] + + if image_type?(ext) || download_type(ext) + s_content = File.expand_path(s_content, file_path) + s_content = s_content.split("#{Rails.root}/")[1] + # content = content.gsub(s[0], "/#{s_content}") + s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join + content = content.gsub(s[0], s_content) + else + path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/") s_content = File.expand_path(s_content, path) s_content = s_content.split("#{Rails.root}/")[1] content = content.gsub(s[0], "/#{s_content}") - else - # 图片资源替换 - s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join - content = content.gsub(s[0], s_content) end rescue next @@ -133,13 +137,21 @@ module RepositoriesHelper date.to_time.strftime("%Y-%m-%d %H:%M") end + def readme_decode64_content(entry, owner, repo, ref, path=nil) + Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}") + content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] + Rails.logger.info("content===#{content}") + # readme_render_decode64_content(content, owner, repo, ref) + new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name']) + end + def decode64_content(entry, owner, repo, ref, path=nil) if is_readme?(entry['type'], entry['name']) Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}") content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] Rails.logger.info("content===#{content}") # readme_render_decode64_content(content, owner, repo, ref) - new_readme_render_decode64_content(content, owner, repo, ref) + return Base64.decode64(content).force_encoding('UTF-8') else file_type = File.extname(entry['name'].to_s)[1..-1] if image_type?(file_type) diff --git a/app/views/repositories/_simple_entry.json.jbuilder b/app/views/repositories/_simple_entry.json.jbuilder index 9d0998c82..3a0d16e28 100644 --- a/app/views/repositories/_simple_entry.json.jbuilder +++ b/app/views/repositories/_simple_entry.json.jbuilder @@ -8,7 +8,10 @@ if @project.forge? json.path entry['path'] json.type entry['type'] json.size entry['size'] - + is_readme = is_readme?(entry['type'], entry['name']) + if is_readme + json.replace_content readme_decode64_content(entry, @owner, @repository, @ref, @path) + end json.content direct_download ? nil : decode64_content(entry, @owner, @repository, @ref, @path) json.target entry['target'] @@ -24,7 +27,7 @@ if @project.forge? json.direct_download direct_download json.image_type image_type - json.is_readme_file is_readme?(entry['type'], entry['name']) + json.is_readme_file is_readme json.commit do json.partial! 'last_commit', latest_commit: entry['latest_commit'] end From fe23c2afbf9d5287649da474eea7c25608f81a85 Mon Sep 17 00:00:00 2001 From: yystopf Date: Sat, 21 May 2022 16:45:42 +0800 Subject: [PATCH 42/82] fix: replace content next if blank --- app/helpers/repositories_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 1897f3ae0..9cb64b355 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -102,7 +102,7 @@ module RepositoriesHelper begin s_content = s[0] # 链接直接跳过不做替换 - next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') + next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank? ext = File.extname(s_content)[1..-1] if image_type?(ext) || download_type(ext) From fbebd0a623fbbc0aec9ae2d0b488e26c536b773a Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 23 May 2022 09:27:09 +0800 Subject: [PATCH 43/82] fix --- app/libs/custom_regexp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/libs/custom_regexp.rb b/app/libs/custom_regexp.rb index 72184630a..b60a80cc6 100644 --- a/app/libs/custom_regexp.rb +++ b/app/libs/custom_regexp.rb @@ -1,7 +1,7 @@ module CustomRegexp PHONE = /1\d{10}/ EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/ - LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}/ #只含有数字、字母、下划线不能以下划线开头和结尾 + LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ #只含有数字、字母、下划线不能以下划线开头和结尾 LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/ NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/ From 05b3f2a2fb0ce327d24328c670b6e2f689b74544 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Mon, 23 May 2022 18:05:13 +0800 Subject: [PATCH 44/82] =?UTF-8?q?fixed=20timego=E6=97=B6=E9=97=B4=E5=B7=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 33 + app/helpers/application_helper.rb | 954 ++++++++++++++-------------- 2 files changed, 510 insertions(+), 477 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 9a3fab62d..47115cfe7 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -8,6 +8,7 @@ class UsersController < ApplicationController before_action :connect_to_ci_db, only: [:get_user_info] before_action :convert_image!, only: [:update, :update_image] skip_before_action :check_sign, only: [:attachment_show] + # before_action :sso_login, only: [:get_user_info] def connect_to_ci_db(options={}) if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?) @@ -321,4 +322,36 @@ class UsersController < ApplicationController render_not_found end + def sso_login + if params[:ticket].present? && !current_user.logged? && params[:websiteName].nil? + info = Base64.decode64(params[:ticket]) || Base64.decode64(params[:info].gsub(" ", "+")).force_encoding("utf-8") + # login 邮箱 手机号 姓名 学校/单位 + user_info = info.split("&&") + # Rails.logger.info("user_info====== #{info}") + login = user_info[0] + email = user_info[1] + phone = user_info[2] + real_name = user_info[3] + department_name = user_info[4] + + # 没有登录时,新建用户并登录 + if current_user.logged? + user = current_user + else + user = User.where("login = ? or phone = ? or mail = ? ", "edu_#{login}", phone, email).first + unless user + ActiveRecord::Base.transaction do + phone_rand = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sample(4).join + user_params = { status: 1, type: 'User', login: "e_#{login}", lastname: "#{real_name}", mail: "#{email}", + nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0, + password: "12345678", phone: "#{phone_rand}", profile_completed: 1 } + user = User.create!(user_params) + UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}") + end + end + successful_authentication(user) + end + end + end + end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 73b365039..999ae2c36 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,477 +1,477 @@ -# 所有的方法请按首字母的顺序依次列出 -module ApplicationHelper - include Gitlink::I18n - include GitHelper - - ONE_MINUTE = 60 * 1000 - ONE_HOUR = 60 * ONE_MINUTE - ONE_DAY = 24 * ONE_HOUR - ONE_MONTH = 30 * ONE_DAY - - ONE_YEAR = 12 * ONE_MONTH - - # 全局参数配置 - def edu_setting name - EduSetting.get(name) - end - - # xss共计问题 - def content_safe content - tags = %w( - a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl - dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark - ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td - tfoot th thead time tr u ul var wbr div span - ) - attributes = %w(href src width height alt cite datetime title class name xml:lang abbr style) - sanitize content, tags: tags, attributes: attributes - end - - def graduation_navigation graduation - graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务" - end - - def graduation_navigation_id course - course.course_modules.find_by(module_type: "graduation").try(:id) - end - - # git用户 - # git用户命名规则:login+"@educoder.net" - def git_username(email) - User.find_by_mail(email) || User.find_by_login(email.split("@").first) - end - - # 不同的类型扩展不同的目录 - def relative_path - "avatars" - end - - def replace_bytes_to_b(size_string) - return size_string.gsub("Bytes", "B").gsub("bytes", "B").gsub("字节", "B") - end - - def storage_path - File.join(Rails.root, "public", "images", relative_path) - end - - # 推荐实训 - def recommend_shixun(shixun) - tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0 - shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and - shixun_id != #{shixun.id}").pluck(:shixun_id) - - shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",") - Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id - in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3) - - end - - # shixun开启挑战对应的行为名及url - def task_operation_url current_myshixun, shixun - if current_myshixun.blank? - name = shixun.status == 0 ? "模拟实战" : "开启挑战" - url = "/shixuns/#{shixun.identifier}/shixun_exec" - else - identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier) - if current_myshixun.status == 1 - name = "查看实战" - else - name = "继续挑战" - end - url = identifier - end - [name, url] - end - - # 获取当前时间 - def time_from_now(time) - if String === time - time = Time.parse(time) - end - - lastUpdateTime = time.to_i*1000 - - currentTime = Time.now.to_i*1000 - timePassed = currentTime - lastUpdateTime - timeIntoFormat = 0 - updateAtValue = "" - if timePassed < 0 - updateAtValue = "刚刚" - elsif timePassed < ONE_MINUTE - updateAtValue = "1分钟前" - elsif timePassed < ONE_HOUR - timeIntoFormat = timePassed / ONE_MINUTE - updateAtValue = timeIntoFormat.to_s + "分钟前" - elsif (timePassed < ONE_DAY) - timeIntoFormat = timePassed / ONE_HOUR - updateAtValue = timeIntoFormat.to_s + "小时前" - elsif (timePassed < ONE_MONTH) - timeIntoFormat = timePassed / ONE_DAY - updateAtValue = timeIntoFormat.to_s + "天前" - elsif (timePassed < ONE_YEAR) - timeIntoFormat = timePassed / ONE_MONTH - updateAtValue = timeIntoFormat.to_s + "个月前" - else - timeIntoFormat = timePassed / ONE_YEAR - updateAtValue = timeIntoFormat.to_s + "年前" - end - updateAtValue - end - - # 计算到结束还有多长时间 **天**小时**分 - def how_much_time(time) - if time.nil? || time < Time.now #6.21 -hs 增加小于time.now - '' - else - result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + " 天 " - result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 " - result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + " 分 " - end - end - - def format_time(time) - time.present? ? time.strftime("%Y-%m-%d %H:%M") : '' - end - - # 用户图像url,如果不存在的话,source为匿名用户,即默认使用匿名用户图像 - def url_to_avatar(source) - if File.exist?(disk_filename(source&.class, source&.id)) - ctime = File.ctime(disk_filename(source.class, source.id)).to_i - if %w(User Organization).include?(source.class.to_s) - File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" - else - File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" - end - elsif source.class.to_s == 'User' - source.get_letter_avatar_url - end - end - - # 主页banner图 - def banner_img(source_type) - if File.exist?(disk_filename(source_type, "banner")) - ctime = File.ctime(disk_filename(source_type, "banner")).to_i - File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}" - end - end - - def disk_filename(source_type,source_id,image_file=nil) - File.join(storage_path, "#{source_type}", "#{source_id}") - end - - def disk_auth_filename(source_type, source_id, type) - File.join(storage_path, "#{source_type}", "#{source_id}#{type}") - end - - def disk_real_name_auth_filename(source_id) - disk_auth_filename('UserAuthentication', source_id, 'ID') - end - - def auth_file_url(source_type, source_id, type) - File.join('/images', relative_path, source_type, "#{source_id}#{type}") - end - - def real_name_auth_file_url(source_id) - auth_file_url('UserAuthentication', source_id, 'ID') - end - - def disk_professional_auth_filename(source_id) - disk_auth_filename('UserAuthentication', source_id, 'PRO') - end - - def professional_auth_file_url(source_id) - auth_file_url('UserAuthentication', source_id, 'PRO') - end - - def shixun_url_to_avatar(shixun) - if File.exist?(disk_filename(shixun.class, shixun.id)) - File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}") - else - File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg") - end - end - - # 选用实训的学校情况 - def school_user_detail shixun - user_ids = shixun.myshixuns.map(&:user_id).uniq # 走缓存取数据 - school_ids = UserExtension.where(user_id:user_ids).pluck(:school_id).uniq - school_names = School.where(id: school_ids[0..1]).pluck(:name) - school_size = school_ids.size - str = school_size > 0 ? "#{school_names.join("、")}等 #{school_size}所" : "0所" - end - - # 普通/分组 作业作品状态数组 - def student_work_status homework, user_id, course, work - status = [] - homework_setting = homework.homework_group_setting user_id, true - work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id) - late_time = homework.late_time || course.end_date - - if course.is_end && work && work.work_status > 0 - status << "查看作品" - elsif !course.is_end - if homework_setting.publish_time && homework_setting.publish_time < Time.now - # 作业未截止时 - if homework_setting.end_time > Time.now - if homework.homework_type == "group" && homework.homework_detail_group.base_on_project - if work.project_id.nil? || work.project_id == 0 - status << "创建项目" - status << "关联项目" - elsif work.work_status == 0 - status << "取消关联" - status << "提交作品" - else - status << "修改作品" - end - else - if work.work_status == 0 - status << "提交作品" - else - status << "修改作品" - end - end - - # 补交阶段 - elsif homework.allow_late && (late_time.nil? || late_time > Time.now) - if homework.homework_type == "group" && homework.homework_detail_group.base_on_project - if work.project_id.nil? || work.project_id == 0 - status << "创建项目" - status << "关联项目" - elsif work.work_status == 0 - status << "取消关联" - status << "补交作品" - else - status << "补交附件" - status << "查看作品" - end - else - if work.work_status == 0 - status << "补交作品" - else - status << "补交附件" - status << "查看作品" - end - end - - # 匿评阶段 - elsif work.work_status != 0 - if homework.homework_detail_manual.comment_status == 3 - work_ids = homework.student_works.has_committed.pluck(:id) - if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0 - status << "匿评作品" - end - end - status << "查看作品" - end - end - end - end - - def commit_des_status work, homework - status = [] - homework_setting = homework.homework_group_setting work.user_id - - # 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结 - if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 && - ((homework_setting.end_time && homework_setting.end_time > Time.now) || - (homework.allow_late && homework.late_time && homework.late_time > Time.now)) - work.description.present? ? status << "修改总结" : status << "提交总结" - end - end - - def download_url attachment,options={} - attachment_path(attachment,options) - end - - # 耗时:天、小时、分、秒 - # 小于1分钟则不显示 - def game_spend_time time - day = time / 86400 - hour = time % (24*60*60) / (60*60) - min = time % (24*60*60) % (60*60) / 60 - sec = time % (24*60*60) % (60*60) % 60 - if day < 1 - if hour < 1 - if min < 1 - if sec < 1 - time = "--" - else - time = "#{sec}秒" - end - else - time = "#{min}分钟 #{sec}秒" - end - else - time = "#{hour}小时 #{min}分钟 #{sec}秒" - end - else - time = "#{day}天 #{hour}小时 #{min}分钟 #{sec}秒" - end - return time - end - - def absolute_path(file_path) - file_root_directory + File.join(edu_setting('attachment_folder'), file_path) - end - - def file_root_directory - Rails.root.to_s - end - - def file_storage_directory - file_root_directory + edu_setting('attachment_folder') - end - - def local_path(file) - File.join(file.disk_directory, file.disk_filename) - end - - def update_downloads(file) - file.update_attributes(:downloads => file.downloads + 1) - end - - # 项目信息, - def project_info work, current_user, course_identity - project = work.project - if project - if project.status == 9 - {id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count} - else - project_score = project.project_score - if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT - {id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count, - all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, - attachment_score: project_score.attachment_score, message_score: project_score.message_score} - else - {id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count, - all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, - attachment_score: project_score.attachment_score, message_score: project_score.message_score} - end - end - else - {id: -1, name: "--", title: "--"} - end - end - - def message_content(content) - content = (strip_html content).strip - content = content.gsub(/\s+/, " ") - if content.gsub(" ", "") == "" - content = "[非文本消息]" - end - content - end - - def strip_html(text, len=0, endss="...") - ss = "" - if !text.nil? && text.length>0 - ss=text.gsub(/<\/?.*?>/, '').strip - ss = ss.gsub(/ */, '') - ss = ss.gsub(/\r\n/,'') #新增 - ss = ss.gsub(/\n/,'') #新增 - if len > 0 && ss.length > len - ss = ss[0, len] + endss - elsif len > 0 && ss.length <= len - ss = ss - #ss = truncate(ss, :length => len) - end - end - ss - end - - def strip_export_title(content) - con_ = "" - if content.length > 0 - con_ = strip_tags(content) - con_ = con_.gsub(/\r\n/,'').gsub(/ */, '').strip - end - con_ - end - - def pdf_load_sources(*arg) - arr = arg.map do |path| - content_tag(:script) do - File.open(Rails.root.join('public', path)).read.to_s.html_safe - end - end - - raw arr.join('') - end - - - - # 导出pdf时,转化markdown为html - def to_markdown(text,origin_url) - return nil if text.blank? - options = { - :autolink => true, - :no_intra_emphasis => true, - :fenced_code_blocks => true, - :lax_html_blocks => true, - :strikethrough => true, - :superscript => false, - :tables => true - } - markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options) - m_t = markdown.render(text) - m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t - end - - def shixun_status_class(shixun) - case shixun.status - when 0 then 'text-info' - when 1 then 'text-warning' - when 2 then 'text-success' - when 3 then 'text-secondary' - end - end - - def render_unix_time(date) - date.to_time.to_i - end - - def find_user_by_login(login) - User.find_by_login login - end - - def find_user_by_login_and_mail(login, mail) - User.find_by(login: login, mail: mail) - end - - def find_user_by_gitea_uid(gitea_uid) - User.find_by(gitea_uid: gitea_uid) - end - - def find_user_in_redis_cache(login, email) - $redis_cache.hgetall("v2-owner-common:#{login}-#{email}") - end - - def find_user_in_redis_cache_by_id(id) - $redis_cache.hgetall("v2-owner-common:#{id}") - end - - def render_base64_decoded(str) - return nil if str.blank? - Base64.decode64 str - end - - def render_admin_statistics_item - url = Rails.application.config_for(:configuration)["admin_statistics_url"] - - return if url.blank? - content_tag(:li) do - sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root') - end - end - - # 1 手机类型;0 邮箱类型 - # 注意新版的login是自动名生成的 - def phone_mail_type value - value =~ /^1\d{10}$/ ? 1 : 0 - end - - def strip(str) - str.to_s.strip.presence - end - -end +# 所有的方法请按首字母的顺序依次列出 +module ApplicationHelper + include Gitlink::I18n + include GitHelper + + ONE_MINUTE = 60 * 1000 + ONE_HOUR = 60 * ONE_MINUTE + ONE_DAY = 24 * ONE_HOUR + ONE_MONTH = 30 * ONE_DAY + + ONE_YEAR = 12 * ONE_MONTH + + # 全局参数配置 + def edu_setting name + EduSetting.get(name) + end + + # xss共计问题 + def content_safe content + tags = %w( + a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl + dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark + ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td + tfoot th thead time tr u ul var wbr div span + ) + attributes = %w(href src width height alt cite datetime title class name xml:lang abbr style) + sanitize content, tags: tags, attributes: attributes + end + + def graduation_navigation graduation + graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务" + end + + def graduation_navigation_id course + course.course_modules.find_by(module_type: "graduation").try(:id) + end + + # git用户 + # git用户命名规则:login+"@educoder.net" + def git_username(email) + User.find_by_mail(email) || User.find_by_login(email.split("@").first) + end + + # 不同的类型扩展不同的目录 + def relative_path + "avatars" + end + + def replace_bytes_to_b(size_string) + return size_string.gsub("Bytes", "B").gsub("bytes", "B").gsub("字节", "B") + end + + def storage_path + File.join(Rails.root, "public", "images", relative_path) + end + + # 推荐实训 + def recommend_shixun(shixun) + tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0 + shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and + shixun_id != #{shixun.id}").pluck(:shixun_id) + + shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",") + Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id + in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3) + + end + + # shixun开启挑战对应的行为名及url + def task_operation_url current_myshixun, shixun + if current_myshixun.blank? + name = shixun.status == 0 ? "模拟实战" : "开启挑战" + url = "/shixuns/#{shixun.identifier}/shixun_exec" + else + identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier) + if current_myshixun.status == 1 + name = "查看实战" + else + name = "继续挑战" + end + url = identifier + end + [name, url] + end + + # 获取当前时间 + def time_from_now(time) + if String === time + time = Time.parse(time) + end + + lastUpdateTime = time.to_i*1000 + + currentTime = Time.now.to_i*1000 + timePassed = currentTime - lastUpdateTime + timeIntoFormat = 0 + updateAtValue = "" + if timePassed < 0 + updateAtValue = "刚刚" + elsif timePassed < ONE_MINUTE + updateAtValue = "1分钟前" + elsif timePassed < ONE_HOUR + timeIntoFormat = timePassed / ONE_MINUTE + updateAtValue = timeIntoFormat.to_s + "分钟前" + elsif (timePassed < ONE_DAY) + timeIntoFormat = (timePassed.to_f / ONE_HOUR).ceil + updateAtValue = timeIntoFormat.to_s + "小时前" + elsif (timePassed < ONE_MONTH) + timeIntoFormat = (timePassed.to_f / ONE_DAY).ceil + updateAtValue = timeIntoFormat.to_s + "天前" + elsif (timePassed < ONE_YEAR) + timeIntoFormat = (timePassed.to_f / ONE_MONTH).ceil + updateAtValue = timeIntoFormat.to_s + "个月前" + else + timeIntoFormat = timePassed / ONE_YEAR + updateAtValue = timeIntoFormat.to_s + "年前" + end + updateAtValue + end + + # 计算到结束还有多长时间 **天**小时**分 + def how_much_time(time) + if time.nil? || time < Time.now #6.21 -hs 增加小于time.now + '' + else + result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + " 天 " + result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 " + result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + " 分 " + end + end + + def format_time(time) + time.present? ? time.strftime("%Y-%m-%d %H:%M") : '' + end + + # 用户图像url,如果不存在的话,source为匿名用户,即默认使用匿名用户图像 + def url_to_avatar(source) + if File.exist?(disk_filename(source&.class, source&.id)) + ctime = File.ctime(disk_filename(source.class, source.id)).to_i + if %w(User Organization).include?(source.class.to_s) + File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" + else + File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" + end + elsif source.class.to_s == 'User' + source.get_letter_avatar_url + end + end + + # 主页banner图 + def banner_img(source_type) + if File.exist?(disk_filename(source_type, "banner")) + ctime = File.ctime(disk_filename(source_type, "banner")).to_i + File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}" + end + end + + def disk_filename(source_type,source_id,image_file=nil) + File.join(storage_path, "#{source_type}", "#{source_id}") + end + + def disk_auth_filename(source_type, source_id, type) + File.join(storage_path, "#{source_type}", "#{source_id}#{type}") + end + + def disk_real_name_auth_filename(source_id) + disk_auth_filename('UserAuthentication', source_id, 'ID') + end + + def auth_file_url(source_type, source_id, type) + File.join('/images', relative_path, source_type, "#{source_id}#{type}") + end + + def real_name_auth_file_url(source_id) + auth_file_url('UserAuthentication', source_id, 'ID') + end + + def disk_professional_auth_filename(source_id) + disk_auth_filename('UserAuthentication', source_id, 'PRO') + end + + def professional_auth_file_url(source_id) + auth_file_url('UserAuthentication', source_id, 'PRO') + end + + def shixun_url_to_avatar(shixun) + if File.exist?(disk_filename(shixun.class, shixun.id)) + File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}") + else + File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg") + end + end + + # 选用实训的学校情况 + def school_user_detail shixun + user_ids = shixun.myshixuns.map(&:user_id).uniq # 走缓存取数据 + school_ids = UserExtension.where(user_id:user_ids).pluck(:school_id).uniq + school_names = School.where(id: school_ids[0..1]).pluck(:name) + school_size = school_ids.size + str = school_size > 0 ? "#{school_names.join("、")}等 #{school_size}所" : "0所" + end + + # 普通/分组 作业作品状态数组 + def student_work_status homework, user_id, course, work + status = [] + homework_setting = homework.homework_group_setting user_id, true + work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id) + late_time = homework.late_time || course.end_date + + if course.is_end && work && work.work_status > 0 + status << "查看作品" + elsif !course.is_end + if homework_setting.publish_time && homework_setting.publish_time < Time.now + # 作业未截止时 + if homework_setting.end_time > Time.now + if homework.homework_type == "group" && homework.homework_detail_group.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "提交作品" + else + status << "修改作品" + end + else + if work.work_status == 0 + status << "提交作品" + else + status << "修改作品" + end + end + + # 补交阶段 + elsif homework.allow_late && (late_time.nil? || late_time > Time.now) + if homework.homework_type == "group" && homework.homework_detail_group.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + else + if work.work_status == 0 + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + end + + # 匿评阶段 + elsif work.work_status != 0 + if homework.homework_detail_manual.comment_status == 3 + work_ids = homework.student_works.has_committed.pluck(:id) + if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0 + status << "匿评作品" + end + end + status << "查看作品" + end + end + end + end + + def commit_des_status work, homework + status = [] + homework_setting = homework.homework_group_setting work.user_id + + # 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结 + if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 && + ((homework_setting.end_time && homework_setting.end_time > Time.now) || + (homework.allow_late && homework.late_time && homework.late_time > Time.now)) + work.description.present? ? status << "修改总结" : status << "提交总结" + end + end + + def download_url attachment,options={} + attachment_path(attachment,options) + end + + # 耗时:天、小时、分、秒 + # 小于1分钟则不显示 + def game_spend_time time + day = time / 86400 + hour = time % (24*60*60) / (60*60) + min = time % (24*60*60) % (60*60) / 60 + sec = time % (24*60*60) % (60*60) % 60 + if day < 1 + if hour < 1 + if min < 1 + if sec < 1 + time = "--" + else + time = "#{sec}秒" + end + else + time = "#{min}分钟 #{sec}秒" + end + else + time = "#{hour}小时 #{min}分钟 #{sec}秒" + end + else + time = "#{day}天 #{hour}小时 #{min}分钟 #{sec}秒" + end + return time + end + + def absolute_path(file_path) + file_root_directory + File.join(edu_setting('attachment_folder'), file_path) + end + + def file_root_directory + Rails.root.to_s + end + + def file_storage_directory + file_root_directory + edu_setting('attachment_folder') + end + + def local_path(file) + File.join(file.disk_directory, file.disk_filename) + end + + def update_downloads(file) + file.update_attributes(:downloads => file.downloads + 1) + end + + # 项目信息, + def project_info work, current_user, course_identity + project = work.project + if project + if project.status == 9 + {id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count} + else + project_score = project.project_score + if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT + {id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count, + all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, + attachment_score: project_score.attachment_score, message_score: project_score.message_score} + else + {id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count, + all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, + attachment_score: project_score.attachment_score, message_score: project_score.message_score} + end + end + else + {id: -1, name: "--", title: "--"} + end + end + + def message_content(content) + content = (strip_html content).strip + content = content.gsub(/\s+/, " ") + if content.gsub(" ", "") == "" + content = "[非文本消息]" + end + content + end + + def strip_html(text, len=0, endss="...") + ss = "" + if !text.nil? && text.length>0 + ss=text.gsub(/<\/?.*?>/, '').strip + ss = ss.gsub(/ */, '') + ss = ss.gsub(/\r\n/,'') #新增 + ss = ss.gsub(/\n/,'') #新增 + if len > 0 && ss.length > len + ss = ss[0, len] + endss + elsif len > 0 && ss.length <= len + ss = ss + #ss = truncate(ss, :length => len) + end + end + ss + end + + def strip_export_title(content) + con_ = "" + if content.length > 0 + con_ = strip_tags(content) + con_ = con_.gsub(/\r\n/,'').gsub(/ */, '').strip + end + con_ + end + + def pdf_load_sources(*arg) + arr = arg.map do |path| + content_tag(:script) do + File.open(Rails.root.join('public', path)).read.to_s.html_safe + end + end + + raw arr.join('') + end + + + + # 导出pdf时,转化markdown为html + def to_markdown(text,origin_url) + return nil if text.blank? + options = { + :autolink => true, + :no_intra_emphasis => true, + :fenced_code_blocks => true, + :lax_html_blocks => true, + :strikethrough => true, + :superscript => false, + :tables => true + } + markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options) + m_t = markdown.render(text) + m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t + end + + def shixun_status_class(shixun) + case shixun.status + when 0 then 'text-info' + when 1 then 'text-warning' + when 2 then 'text-success' + when 3 then 'text-secondary' + end + end + + def render_unix_time(date) + date.to_time.to_i + end + + def find_user_by_login(login) + User.find_by_login login + end + + def find_user_by_login_and_mail(login, mail) + User.find_by(login: login, mail: mail) + end + + def find_user_by_gitea_uid(gitea_uid) + User.find_by(gitea_uid: gitea_uid) + end + + def find_user_in_redis_cache(login, email) + $redis_cache.hgetall("v2-owner-common:#{login}-#{email}") + end + + def find_user_in_redis_cache_by_id(id) + $redis_cache.hgetall("v2-owner-common:#{id}") + end + + def render_base64_decoded(str) + return nil if str.blank? + Base64.decode64 str + end + + def render_admin_statistics_item + url = Rails.application.config_for(:configuration)["admin_statistics_url"] + + return if url.blank? + content_tag(:li) do + sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root') + end + end + + # 1 手机类型;0 邮箱类型 + # 注意新版的login是自动名生成的 + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + end + + def strip(str) + str.to_s.strip.presence + end + +end From b0092487e699c72d96add9b34ca0e2f11de4827d Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 23 May 2022 18:10:41 +0800 Subject: [PATCH 45/82] fix: is readme use regex --- app/helpers/repositories_helper.rb | 2 +- app/libs/custom_regexp.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 9cb64b355..73ce9823e 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -22,7 +22,7 @@ module RepositoriesHelper def is_readme?(type, str) return false if type != 'file' || str.blank? readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"] - readme_types.include?(str.to_s.downcase) + readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX end def render_commit_author(author_json) diff --git a/app/libs/custom_regexp.rb b/app/libs/custom_regexp.rb index b60a80cc6..e778c5499 100644 --- a/app/libs/custom_regexp.rb +++ b/app/libs/custom_regexp.rb @@ -11,5 +11,5 @@ module CustomRegexp URL_REGEX = /\A(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?\z/i REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 - + MD_REGEX = /^.+(\.[m|M][d|D])$/ end From 2959414d563ac5826ae66650b2927c8a75140e69 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 10:25:58 +0800 Subject: [PATCH 46/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 37 +++++++------- app/views/users/get_user_info.json.jbuilder | 54 ++++++++++----------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index a04a16aa9..ef320e7bd 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -8,7 +8,7 @@ class UsersController < ApplicationController before_action :connect_to_ci_db, only: [:get_user_info] before_action :convert_image!, only: [:update, :update_image] skip_before_action :check_sign, only: [:attachment_show] - # before_action :sso_login, only: [:get_user_info] + before_action :sso_login, only: [:get_user_info] def connect_to_ci_db(options={}) if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?) @@ -331,26 +331,29 @@ class UsersController < ApplicationController end def sso_login - if params[:ticket].present? && !current_user.logged? && params[:websiteName].nil? - info = Base64.decode64(params[:ticket]) || Base64.decode64(params[:info].gsub(" ", "+")).force_encoding("utf-8") - # login 邮箱 手机号 姓名 学校/单位 - user_info = info.split("&&") - # Rails.logger.info("user_info====== #{info}") - login = user_info[0] - email = user_info[1] - phone = user_info[2] - real_name = user_info[3] - department_name = user_info[4] + if params[:login].present? && !current_user.logged? && params[:websiteName].nil? + params = { "login" => "#{params[:login]}", "private_token" => "hriEn3UwXfJs3PmyXnSH" } + api_url= "https://pre-data.educoder.net" + client = Faraday.new(url: api_url) + response = client.public_send("get", "/api/sources/get_user_info_by_login", params) + result = JSON.parse(response.body) - # 没有登录时,新建用户并登录 - if current_user.logged? - user = current_user - else - user = User.where("login = ? or phone = ? or mail = ? ", "edu_#{login}", phone, email).first + if result["status"].to_s == "0" + # login 邮箱 手机号 姓名 学校/单位 + user_info = result["data"] + Rails.logger.info("user_info====== #{user_info}") + login = user_info["login"] + email = user_info["mail"] + phone = user_info["phone"] + real_name = user_info["username"] + department_name = user_info["school"] + + # 没有用户时,新建用户并登录 + user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first unless user ActiveRecord::Base.transaction do phone_rand = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sample(4).join - user_params = { status: 1, type: 'User', login: "e_#{login}", lastname: "#{real_name}", mail: "#{email}", + user_params = { status: 1, type: 'User', login: "#{login}", lastname: "#{real_name}", mail: "#{email}", nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0, password: "12345678", phone: "#{phone_rand}", profile_completed: 1 } user = User.create!(user_params) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index d60f46ade..d4859c376 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -1,28 +1,28 @@ -json.username @user.full_name -json.real_name @user.real_name -json.nickname @user.nickname -json.gender @user.gender -json.login @user.login -json.user_id @user.id -json.image_url url_to_avatar(@user) -json.admin @user.admin? -json.is_teacher @user.user_extension&.teacher? -json.user_identity @user.identity -json.tidding_count 0 -json.user_phone_binded @user.phone.present? -json.need_edit_info @user.need_edit_info? -# json.phone @user.phone -# json.email @user.mail -json.profile_completed @user.profile_is_completed? -json.professional_certification @user.professional_certification -json.devops_step @user.devops_step -json.ci_certification @user.ci_certification? -json.email @user.mail -json.province @user.province -json.city @user.city -json.custom_department @user.custom_department -json.description @user.description -json.super_description @user.super_description -json.(@user, :show_email, :show_department, :show_location, :show_super_description) -json.message_unread_total @message_unread_total +json.username @user.full_name +json.real_name @user.real_name +json.nickname @user.nickname +json.gender @user.gender +json.login @user.login +json.user_id @user.id +json.image_url url_to_avatar(@user) +json.admin @user.admin? +json.is_teacher @user.user_extension&.teacher? +json.user_identity @user.identity +json.tidding_count 0 +json.user_phone_binded @user.phone.present? +json.need_edit_info @user.need_edit_info? +json.phone @user.phone +# json.email @user.mail +json.profile_completed @user.profile_is_completed? +json.professional_certification @user.professional_certification +json.devops_step @user.devops_step +json.ci_certification @user.ci_certification? +json.email @user.mail +json.province @user.province +json.city @user.city +json.custom_department @user.custom_department +json.description @user.description +json.super_description @user.super_description +json.(@user, :show_email, :show_department, :show_location, :show_super_description) +json.message_unread_total @message_unread_total json.has_trace_user @user.trace_user.present? \ No newline at end of file From 26bfc2c0bf22ffad4fd478a4be8a4ff75fbb7053 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 10:33:21 +0800 Subject: [PATCH 47/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ef320e7bd..98da1b880 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -331,7 +331,7 @@ class UsersController < ApplicationController end def sso_login - if params[:login].present? && !current_user.logged? && params[:websiteName].nil? + if params[:login].present? && !current_user.logged? && params[:websiteName].present? params = { "login" => "#{params[:login]}", "private_token" => "hriEn3UwXfJs3PmyXnSH" } api_url= "https://pre-data.educoder.net" client = Faraday.new(url: api_url) From ee3a14fa280cf205bf61a29c813f6ed027f36d52 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 10:34:31 +0800 Subject: [PATCH 48/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 98da1b880..ad211d42c 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -332,10 +332,10 @@ class UsersController < ApplicationController def sso_login if params[:login].present? && !current_user.logged? && params[:websiteName].present? - params = { "login" => "#{params[:login]}", "private_token" => "hriEn3UwXfJs3PmyXnSH" } - api_url= "https://pre-data.educoder.net" + req_params = { "login" => "#{params[:login]}", "private_token" => "hriEn3UwXfJs3PmyXnSH" } + api_url= "https://data.educoder.net" client = Faraday.new(url: api_url) - response = client.public_send("get", "/api/sources/get_user_info_by_login", params) + response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params) result = JSON.parse(response.body) if result["status"].to_s == "0" From b673909f9edf3e5ad74c8679b56025099d905397 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 10:47:17 +0800 Subject: [PATCH 49/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8C=E6=89=8B=E6=9C=BA=E5=8F=B7?= =?UTF-8?q?=E5=85=88=E8=AE=B0=E5=BD=95=EF=BC=8C=E5=90=8E=E7=BB=AD=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ad211d42c..72fb40fee 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -350,7 +350,10 @@ class UsersController < ApplicationController # 没有用户时,新建用户并登录 user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first - unless user + if user.present? + # 手机号先记录,后续用 + user.update_column(:phone, "#{phone}") if phone.present? + else ActiveRecord::Base.transaction do phone_rand = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sample(4).join user_params = { status: 1, type: 'User', login: "#{login}", lastname: "#{real_name}", mail: "#{email}", From c27cc063e67003e091afedc1b83d1b622281f762 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 24 May 2022 10:59:52 +0800 Subject: [PATCH 50/82] add: new update user info simple and sync gitea --- app/controllers/accounts_controller.rb | 776 ++++++++++---------- app/controllers/concerns/register_helper.rb | 28 + app/forms/gitea/user/update_form.rb | 2 +- config/routes.rb | 1 + 4 files changed, 428 insertions(+), 379 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index e40630c6b..1af348abd 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,378 +1,398 @@ -class AccountsController < ApplicationController - include ApplicationHelper - - #skip_before_action :check_account, :only => [:logout] - - def index - render json: session - end - - # 其他平台同步注册的用户 - def remote_register - Register::RemoteForm.new(remote_register_params).validate! - username = params[:username]&.gsub(/\s+/, "") - tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) - email = params[:email]&.gsub(/\s+/, "") - password = params[:password] - platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") - - ActiveRecord::Base.transaction do - result = autologin_register(username, email, password, platform) - if result[:message].blank? - render_ok({user: result[:user]}) - else - render_error(result[:message]) - end - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - - # 其他平台修改用户的信息,这边同步修改 - def remote_update - ActiveRecord::Base.transaction do - user_params = params[:user_params] - user_extension_params = params[:user_extension_params] - - u = User.find_by(login: params[:old_user_login]) - user_mail = u.try(:mail) - - if u.present? - ue = u.user_extension - u.login = user_params["login"] if user_params["login"] - u.mail = user_params["mail"] if user_params["mail"] - u.lastname = user_params["lastname"] if user_params["lastname"] - - ue.gender = user_extension_params["gender"] - ue.school_id = user_extension_params["school_id"] - ue.location = user_extension_params["location"] - ue.location_city = user_extension_params["location_city"] - ue.identity = user_extension_params["identity"] - ue.technical_title = user_extension_params["technical_title"] - ue.student_id = user_extension_params["student_id"] - ue.description = user_extension_params["description"] - ue.save! - u.save! - - sync_params = {} - - if (user_params["mail"] && user_params["mail"] != user_mail) - sync_params = sync_params.merge(email: user_params["mail"]) - end - - if sync_params.present? - interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) - if interactor.success? - render_ok - else - render_error(interactor.error) - end - end - end - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - - # 其他平台同步登录 - def remote_login - @user = User.try_to_login(params[:login], params[:password]) - if @user - successful_authentication(@user) - render_ok({user: {id: @user.id, token: @user.gitea_token}}) - else - render_error("用户不存在") - end - end - - #修改密码 - def remote_password - @user = User.find_by(login: params[:login]) - return render_error("未找到相关用户!") if @user.blank? - - sync_params = { - password: params[:password].to_s, - email: @user.mail - } - - interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) - if interactor.success? - @user.update_attribute(:password, params[:password]) - render_ok - else - render_error(interactor.error) - end - end - - - - # 用户注册 - # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 - # params[:login] 邮箱或者手机号 - # params[:namespace] 登录名 - # params[:code] 验证码 - # code_type 1:注册手机验证码 8:邮箱注册验证码 - # 本地forge注册入口需要重新更改逻辑 - def register - # type只可能是1或者8 - user = nil - begin - Register::Form.new(register_params).validate! - - user = Users::RegisterService.call(register_params) - password = register_params[:password].strip - - # gitea用户注册, email, username, password - interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) - if interactor.success? - gitea_user = interactor.result - result = Gitea::User::GenerateTokenService.call(user.login, password) - user.gitea_token = result['sha1'] - user.gitea_uid = gitea_user[:body]['id'] - if user.save! - UserExtension.create!(user_id: user.id) - successful_authentication(user) - render_ok - end - else - tip_exception(-1, interactor.error) - end - rescue Register::BaseForm::EmailError => e - render_error(-2, e.message) - rescue Register::BaseForm::LoginError => e - render_error(-3, e.message) - rescue Register::BaseForm::PhoneError => e - render_error(-4, e.message) - rescue Register::BaseForm::PasswordFormatError => e - render_error(-5, e.message) - rescue Register::BaseForm::VerifiCodeError => e - render_error(-6, e.message) - rescue Exception => e - Gitea::User::DeleteService.call(user.login) unless user.nil? - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - end - - # 用户登录 - def login - Users::LoginForm.new(account_params).validate! - @user = User.try_to_login(params[:login], params[:password]) - - return normal_status(-2, "错误的账号或密码") if @user.blank? - # user is already in local database - return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? - - login_control = LimitForbidControl::UserLogin.new(@user) - return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? - - password_ok = @user.check_password?(params[:password].to_s) - unless password_ok - if login_control.remain_times-1 == 0 - normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") - else - normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") - end - login_control.increment! - return - end - - successful_authentication(@user) - sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 - - # session[:user_id] = @user.id - end - - def change_password - @user = User.find_by(login: params[:login]) - return render_error("未找到相关用户!") if @user.blank? - return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) - - sync_params = { - password: params[:password].to_s, - email: @user.mail, - login_name: @user.login, - source_id: 0 - } - - interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) - if interactor.success? - @user.update_attribute(:password, params[:password]) - render_ok - else - render_error(interactor.error) - end - end - - # 忘记密码 - def reset_password - begin - code = params[:code] - login_type = phone_mail_type(params[:login].strip) - # 获取验证码 - if login_type == 1 - phone = params[:login] - verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last - user = User.find_by_phone(phone) - else - email = params[:login] - verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last - user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs - end - return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip - return normal_status(-2, "验证码已失效") if !verifi_code&.effective? - return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD - - user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] - ActiveRecord::Base.transaction do - user.save! - LimitForbidControl::UserLogin.new(user).clear - end - sucess_status - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end - end - - def successful_authentication(user) - uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") - # Valid user - self.logged_user = user - # generate a key and set cookie if autologin - - set_autologin_cookie(user) - UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) - user.update_column(:last_login_on, Time.now) - session[:"#{default_yun_session}"] = user.id - Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") - # 注册完成后有一天的试用申请(先去掉) - # UserDayCertification.create(user_id: user.id, status: 1) - end - - 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, - :path => '/', - :secure => false, - :httponly => true - } - if edu_setting('cookie_domain').present? - cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) - end - cookies[autologin_cookie_name] = cookie_options - cookies.signed[:user_id] ||= user.id - - logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") - end - - def logout - Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") - UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) - logout_user - render :json => {status: 1, message: "退出成功!"} - end - - # 检验邮箱是否已被注册及邮箱或者手机号是否合法 - # 参数type为事件类型 1:注册;2:忘记密码;3:绑定 - def valid_email_and_phone - check_mail_and_phone_valid(params[:login], params[:type]) - end - - # 发送验证码 - # params[:login] 手机号或者邮箱号 - # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 - # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 - # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效 - def get_verification_code - code = %W(0 1 2 3 4 5 6 7 8 9) - value = params[:login] - type = params[:type].strip.to_i - login_type = phone_mail_type(value) - send_type = verify_type(login_type, type) - verification_code = code.sample(6).join - - sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") - tip_exception(501, "请求不合理") if sign != params[:smscode] - - logger.info "########### 验证码:#{verification_code}" - logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") - - # 记录验证码 - check_verification_code(verification_code, send_type, value) - render_ok - end - - # check user's login or email or phone is used - # params[:value] 手机号或者邮箱号或者登录名 - # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) - def check - Register::CheckColumnsForm.new(check_params).validate! - render_ok - end - - private - - # type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 - # login_type 1:手机类型 2:邮箱类型 - def verify_type login_type, type - case type - when 1 - login_type == 1 ? 1 : 8 - when 2 - login_type == 1 ? 2 : 3 - when 3 - login_type == 1 ? 4 : tip_exception('请填写正确的手机号') - when 4 - login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 - when 5 - login_type == 1 ? 9 : tip_exception('请填写正确的手机号') - end - end - - def generate_login(login) - type = phone_mail_type(login.strip) - - if type == 1 - uid_logger("start register by phone: type is #{type}") - pre = 'p' - email = nil - phone = login - else - uid_logger("start register by email: type is #{type}") - pre = 'm' - email = login - phone = nil - end - code = generate_identifier User, 8, pre - - { login: pre + code, email: email, phone: phone } - end - - def user_params - params.require(:user).permit(:login, :email, :phone) - end - - def account_params - params.require(:account).permit(:login, :password) - end - - def check_params - params.permit(:type, :value) - end - - def register_params - params.permit(:login, :namespace, :password, :code) - end - - def remote_register_params - params.permit(:username, :email, :password, :platform) - end - -end +class AccountsController < ApplicationController + before_action :require_login, only: [:simple_update] + include ApplicationHelper + + #skip_before_action :check_account, :only => [:logout] + + def simple_update + simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, "")) + simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, "")) + simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, "")) + Register::RemoteForm.new(simple_update_params).validate! + + ActiveRecord::Base.transaction do + result = auto_update(current_user, simple_update_params) + if result[:message].blank? + render_ok + else + render_error(result[:message]) + end + end + end + + def index + render json: session + end + + # 其他平台同步注册的用户 + def remote_register + Register::RemoteForm.new(remote_register_params).validate! + username = params[:username]&.gsub(/\s+/, "") + tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) + email = params[:email]&.gsub(/\s+/, "") + password = params[:password] + platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") + + ActiveRecord::Base.transaction do + result = autologin_register(username, email, password, platform) + if result[:message].blank? + render_ok({user: result[:user]}) + else + render_error(result[:message]) + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + + # 其他平台修改用户的信息,这边同步修改 + def remote_update + ActiveRecord::Base.transaction do + user_params = params[:user_params] + user_extension_params = params[:user_extension_params] + + u = User.find_by(login: params[:old_user_login]) + user_mail = u.try(:mail) + + if u.present? + ue = u.user_extension + u.login = user_params["login"] if user_params["login"] + u.mail = user_params["mail"] if user_params["mail"] + u.lastname = user_params["lastname"] if user_params["lastname"] + + ue.gender = user_extension_params["gender"] + ue.school_id = user_extension_params["school_id"] + ue.location = user_extension_params["location"] + ue.location_city = user_extension_params["location_city"] + ue.identity = user_extension_params["identity"] + ue.technical_title = user_extension_params["technical_title"] + ue.student_id = user_extension_params["student_id"] + ue.description = user_extension_params["description"] + ue.save! + u.save! + + sync_params = {} + + if (user_params["mail"] && user_params["mail"] != user_mail) + sync_params = sync_params.merge(email: user_params["mail"]) + end + + if sync_params.present? + interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) + if interactor.success? + render_ok + else + render_error(interactor.error) + end + end + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + + # 其他平台同步登录 + def remote_login + @user = User.try_to_login(params[:login], params[:password]) + if @user + successful_authentication(@user) + render_ok({user: {id: @user.id, token: @user.gitea_token}}) + else + render_error("用户不存在") + end + end + + #修改密码 + def remote_password + @user = User.find_by(login: params[:login]) + return render_error("未找到相关用户!") if @user.blank? + + sync_params = { + password: params[:password].to_s, + email: @user.mail + } + + interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) + if interactor.success? + @user.update_attribute(:password, params[:password]) + render_ok + else + render_error(interactor.error) + end + end + + + + # 用户注册 + # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 + # params[:login] 邮箱或者手机号 + # params[:namespace] 登录名 + # params[:code] 验证码 + # code_type 1:注册手机验证码 8:邮箱注册验证码 + # 本地forge注册入口需要重新更改逻辑 + def register + # type只可能是1或者8 + user = nil + begin + Register::Form.new(register_params).validate! + + user = Users::RegisterService.call(register_params) + password = register_params[:password].strip + + # gitea用户注册, email, username, password + interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.call(user.login, password) + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user[:body]['id'] + if user.save! + UserExtension.create!(user_id: user.id) + successful_authentication(user) + render_ok + end + else + tip_exception(-1, interactor.error) + end + rescue Register::BaseForm::EmailError => e + render_error(-2, e.message) + rescue Register::BaseForm::LoginError => e + render_error(-3, e.message) + rescue Register::BaseForm::PhoneError => e + render_error(-4, e.message) + rescue Register::BaseForm::PasswordFormatError => e + render_error(-5, e.message) + rescue Register::BaseForm::VerifiCodeError => e + render_error(-6, e.message) + rescue Exception => e + Gitea::User::DeleteService.call(user.login) unless user.nil? + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + end + + # 用户登录 + def login + Users::LoginForm.new(account_params).validate! + @user = User.try_to_login(params[:login], params[:password]) + + return normal_status(-2, "错误的账号或密码") if @user.blank? + # user is already in local database + return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? + + login_control = LimitForbidControl::UserLogin.new(@user) + return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? + + password_ok = @user.check_password?(params[:password].to_s) + unless password_ok + if login_control.remain_times-1 == 0 + normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") + else + normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") + end + login_control.increment! + return + end + + successful_authentication(@user) + sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 + + # session[:user_id] = @user.id + end + + def change_password + @user = User.find_by(login: params[:login]) + return render_error("未找到相关用户!") if @user.blank? + return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) + + sync_params = { + password: params[:password].to_s, + email: @user.mail, + login_name: @user.login, + source_id: 0 + } + + interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) + if interactor.success? + @user.update_attribute(:password, params[:password]) + render_ok + else + render_error(interactor.error) + end + end + + # 忘记密码 + def reset_password + begin + code = params[:code] + login_type = phone_mail_type(params[:login].strip) + # 获取验证码 + if login_type == 1 + phone = params[:login] + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last + user = User.find_by_phone(phone) + else + email = params[:login] + verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last + user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs + end + return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip + return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD + + user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] + ActiveRecord::Base.transaction do + user.save! + LimitForbidControl::UserLogin.new(user).clear + end + sucess_status + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + end + + def successful_authentication(user) + uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + + set_autologin_cookie(user) + UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) + user.update_column(:last_login_on, Time.now) + session[:"#{default_yun_session}"] = user.id + Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") + # 注册完成后有一天的试用申请(先去掉) + # UserDayCertification.create(user_id: user.id, status: 1) + end + + 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, + :path => '/', + :secure => false, + :httponly => true + } + if edu_setting('cookie_domain').present? + cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) + end + cookies[autologin_cookie_name] = cookie_options + cookies.signed[:user_id] ||= user.id + + logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") + end + + def logout + Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") + UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) + logout_user + render :json => {status: 1, message: "退出成功!"} + end + + # 检验邮箱是否已被注册及邮箱或者手机号是否合法 + # 参数type为事件类型 1:注册;2:忘记密码;3:绑定 + def valid_email_and_phone + check_mail_and_phone_valid(params[:login], params[:type]) + end + + # 发送验证码 + # params[:login] 手机号或者邮箱号 + # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 + # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效 + def get_verification_code + code = %W(0 1 2 3 4 5 6 7 8 9) + value = params[:login] + type = params[:type].strip.to_i + login_type = phone_mail_type(value) + send_type = verify_type(login_type, type) + verification_code = code.sample(6).join + + sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") + tip_exception(501, "请求不合理") if sign != params[:smscode] + + logger.info "########### 验证码:#{verification_code}" + logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") + + # 记录验证码 + check_verification_code(verification_code, send_type, value) + render_ok + end + + # check user's login or email or phone is used + # params[:value] 手机号或者邮箱号或者登录名 + # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) + def check + Register::CheckColumnsForm.new(check_params).validate! + render_ok + end + + private + + # type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 + # login_type 1:手机类型 2:邮箱类型 + def verify_type login_type, type + case type + when 1 + login_type == 1 ? 1 : 8 + when 2 + login_type == 1 ? 2 : 3 + when 3 + login_type == 1 ? 4 : tip_exception('请填写正确的手机号') + when 4 + login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 + when 5 + login_type == 1 ? 9 : tip_exception('请填写正确的手机号') + end + end + + def generate_login(login) + type = phone_mail_type(login.strip) + + if type == 1 + uid_logger("start register by phone: type is #{type}") + pre = 'p' + email = nil + phone = login + else + uid_logger("start register by email: type is #{type}") + pre = 'm' + email = login + phone = nil + end + code = generate_identifier User, 8, pre + + { login: pre + code, email: email, phone: phone } + end + + def user_params + params.require(:user).permit(:login, :email, :phone) + end + + def account_params + params.require(:account).permit(:login, :password) + end + + def check_params + params.permit(:type, :value) + end + + def register_params + params.permit(:login, :namespace, :password, :code) + end + + def remote_register_params + params.permit(:username, :email, :password, :platform) + end + + def simple_update_params + params.permit(:username, :email, :password, :platform) + end +end diff --git a/app/controllers/concerns/register_helper.rb b/app/controllers/concerns/register_helper.rb index 3a23a2103..3d5b0fc03 100644 --- a/app/controllers/concerns/register_helper.rb +++ b/app/controllers/concerns/register_helper.rb @@ -27,4 +27,32 @@ module RegisterHelper result end + def auto_update(user, params={}) + return if params.blank? + result = {message: nil, user: nil} + before_login = user.login + user.login = params[:username] + user.password = params[:password] + user.mail = params[:email] + + if user.save! + sync_params = { + password: params[:password].to_s, + email: params[:email], + login_name: params[:username], + new_name: params[:username], + source_id: 0 + } + + interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params) + if interactor.success? + result[:user] = user + else + result[:message] = '用户同步Gitea失败!' + end + else + result[:message] = user.errors.full_messages.join(",") + return + end + end end diff --git a/app/forms/gitea/user/update_form.rb b/app/forms/gitea/user/update_form.rb index 7912d51fa..401282ff1 100644 --- a/app/forms/gitea/user/update_form.rb +++ b/app/forms/gitea/user/update_form.rb @@ -4,7 +4,7 @@ class Gitea::User::UpdateForm attr_accessor :username, :email, :admin, :allow_create_organization, :allow_git_hook, :allow_import_local, :full_name, :location, :login_name, :max_repo_creation, :must_change_password, :password, :prohibit_login, - :source_id, :website + :source_id, :website, :new_name validates :username, presence: true validates :email, presence: true, format: { with: EMAIL_REGEX, multiline: true } diff --git a/config/routes.rb b/config/routes.rb index 01ff4fa3c..eae7cf8eb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -203,6 +203,7 @@ Rails.application.routes.draw do post :remote_password post :change_password post :check + post :simple_update end end From 1358c23ca6e4bd498855dab49f00937df06dcb40 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 24 May 2022 11:43:47 +0800 Subject: [PATCH 51/82] fix: trasfer project member must remove old permission --- app/services/projects/transfer_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 7d1214eb8..157263962 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -24,7 +24,8 @@ class Projects::TransferService < ApplicationService private def update_owner - project.members.map{|m| m.destroy! if m.user_id == owner.id || (new_owner.is_a?(Organization) && new_owner.is_member?(m.user_id)) } + project.members.map{|m| m.destroy! if m.user_id == owner.id || project.member(new_owner.id) || (new_owner.is_a?(Organization) && new_owner.is_member?(m.user_id)) } + project.set_owner_permission(new_owner) project.update!(user_id: new_owner.id) end From aa18fe0ad42f3715019038c425acc7b7060eb1e1 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 24 May 2022 11:43:47 +0800 Subject: [PATCH 52/82] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E8=BD=AC=E7=A7=BB?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=97=B6=E6=96=B0=E6=8E=A5=E5=8F=97=E8=80=85?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E7=A7=BB=E9=99=A4=E5=8E=9F=E6=9D=A5=E7=9A=84?= =?UTF-8?q?=E6=9D=83=E9=99=90=E8=A7=92=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/projects/transfer_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 7d1214eb8..157263962 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -24,7 +24,8 @@ class Projects::TransferService < ApplicationService private def update_owner - project.members.map{|m| m.destroy! if m.user_id == owner.id || (new_owner.is_a?(Organization) && new_owner.is_member?(m.user_id)) } + project.members.map{|m| m.destroy! if m.user_id == owner.id || project.member(new_owner.id) || (new_owner.is_a?(Organization) && new_owner.is_member?(m.user_id)) } + project.set_owner_permission(new_owner) project.update!(user_id: new_owner.id) end From 643a99fdf12d010e46ba313e8c114459384a53eb Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 11:48:56 +0800 Subject: [PATCH 53/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 78 +++++++++++++++++------------ 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 72fb40fee..5f6dcf37d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -332,40 +332,56 @@ class UsersController < ApplicationController def sso_login if params[:login].present? && !current_user.logged? && params[:websiteName].present? - req_params = { "login" => "#{params[:login]}", "private_token" => "hriEn3UwXfJs3PmyXnSH" } - api_url= "https://data.educoder.net" - client = Faraday.new(url: api_url) - response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params) - result = JSON.parse(response.body) - - if result["status"].to_s == "0" - # login 邮箱 手机号 姓名 学校/单位 - user_info = result["data"] - Rails.logger.info("user_info====== #{user_info}") - login = user_info["login"] - email = user_info["mail"] - phone = user_info["phone"] - real_name = user_info["username"] - department_name = user_info["school"] - - # 没有用户时,新建用户并登录 - user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first - if user.present? - # 手机号先记录,后续用 - user.update_column(:phone, "#{phone}") if phone.present? - else - ActiveRecord::Base.transaction do - phone_rand = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sample(4).join - user_params = { status: 1, type: 'User', login: "#{login}", lastname: "#{real_name}", mail: "#{email}", - nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0, - password: "12345678", phone: "#{phone_rand}", profile_completed: 1 } - user = User.create!(user_params) - UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}") - end - end + user = User.where("login = ?", "#{params[:login].presence}").first + # 已同步注册,直接登录 + if user.present? successful_authentication(user) + else + autologin_register_by_educoder(params[:login].presence) end end end + # 通过login参数查询头歌账号信息,注册并登录 + def autologin_register_by_educoder(edu_login) + req_params = { "login" => "#{edu_login}", "private_token" => "hriEn3UwXfJs3PmyXnSH" } + api_url= "https://data.educoder.net" + client = Faraday.new(url: api_url) + response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params) + result = JSON.parse(response.body) + #查询 + return nil if result["status"].to_s != "0" + + # login 邮箱 手机号 姓名 学校/单位 + user_info = result["data"] + Rails.logger.info("user_info====== #{user_info}") + login = user_info["login"] + email = user_info["mail"] + phone = user_info["phone"] + real_name = user_info["username"] + department_name = user_info["school"] + + # 没有用户时,新建用户并登录 + user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first + if user.present? + # 手机号先记录,后续用 + user.update_column(:phone, "#{phone}") if phone.present? + else + ActiveRecord::Base.transaction do + email = "#{login}@gitlink.org.cn" if email.blank? + user_params = { status: 1, type: 'User', login: "#{login}", lastname: "#{real_name}", mail: "#{email}", + nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0, + password: "12345678", phone: "#{phone}", profile_completed: 1 } + user = User.create!(user_params) + UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}") + interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: "12345678"}) + if interactor.success? + else + Rails.logger.info("Gitea::RegisterInteractor.call error====== #{interactor.error}") + end + end + end + successful_authentication(user) if user.present? + end + end \ No newline at end of file From b45ee1123997721093c49a2387b9a3450fff1161 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 13:46:58 +0800 Subject: [PATCH 54/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 5f6dcf37d..3587b71d9 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -376,6 +376,11 @@ class UsersController < ApplicationController UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}") interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: "12345678"}) if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.call(username, password) + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user[:body]['id'] + user.save! else Rails.logger.info("Gitea::RegisterInteractor.call error====== #{interactor.error}") end From 93f8b659a1ebab31f04f97e93ae1e59d9dc4de5f Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 14:00:15 +0800 Subject: [PATCH 55/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/users/get_user_info.json.jbuilder | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index d4859c376..250c5cc4a 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -11,7 +11,7 @@ json.user_identity @user.identity json.tidding_count 0 json.user_phone_binded @user.phone.present? json.need_edit_info @user.need_edit_info? -json.phone @user.phone +# json.phone @user.phone # json.email @user.mail json.profile_completed @user.profile_is_completed? json.professional_certification @user.professional_certification @@ -25,4 +25,5 @@ json.description @user.description json.super_description @user.super_description json.(@user, :show_email, :show_department, :show_location, :show_super_description) json.message_unread_total @message_unread_total -json.has_trace_user @user.trace_user.present? \ No newline at end of file +json.has_trace_user @user.trace_user.present? +json.is_new params[:login].to_s.include?("#{@user.login}") \ No newline at end of file From 75cef14605d2a19058ccf83dd27556f1e0238ee2 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 14:08:33 +0800 Subject: [PATCH 56/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3587b71d9..69b92ceff 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -360,6 +360,7 @@ class UsersController < ApplicationController phone = user_info["phone"] real_name = user_info["username"] department_name = user_info["school"] + password = "12345678" # 没有用户时,新建用户并登录 user = User.where("login = ? or phone = ? or mail = ? ", "#{login}", phone, email).first @@ -371,13 +372,13 @@ class UsersController < ApplicationController email = "#{login}@gitlink.org.cn" if email.blank? user_params = { status: 1, type: 'User', login: "#{login}", lastname: "#{real_name}", mail: "#{email}", nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0, - password: "12345678", phone: "#{phone}", profile_completed: 1 } + password: "#{password}", phone: "#{phone}", profile_completed: 1 } user = User.create!(user_params) UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}") - interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: "12345678"}) + interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: password}) if interactor.success? gitea_user = interactor.result - result = Gitea::User::GenerateTokenService.call(username, password) + result = Gitea::User::GenerateTokenService.call(login, password) user.gitea_token = result['sha1'] user.gitea_uid = gitea_user[:body]['id'] user.save! From 85a36ca2e7e346cf7a93d2fdd87b669969f1a1b8 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 14:14:57 +0800 Subject: [PATCH 57/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 69b92ceff..80b0e6173 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -378,6 +378,7 @@ class UsersController < ApplicationController interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: password}) if interactor.success? gitea_user = interactor.result + Rails.logger.info("Gitea::RegisterInteractor.call result====== #{gitea_user}") result = Gitea::User::GenerateTokenService.call(login, password) user.gitea_token = result['sha1'] user.gitea_uid = gitea_user[:body]['id'] From ebe5fad7dd0a4bff0b9f09af5faa59c17e59989b Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 14:33:23 +0800 Subject: [PATCH 58/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/interactors/gitea/register_interactor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/interactors/gitea/register_interactor.rb b/app/interactors/gitea/register_interactor.rb index d8dbc6cad..e188809ac 100644 --- a/app/interactors/gitea/register_interactor.rb +++ b/app/interactors/gitea/register_interactor.rb @@ -13,7 +13,7 @@ module Gitea end def success? - @error.nil? + @error.nil? && @result[:status].to_s == "success" end def result From 94166a363c64f1c1ddb2a81e66eb8b4df64740e3 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Tue, 24 May 2022 15:24:15 +0800 Subject: [PATCH 59/82] =?UTF-8?q?fixed=20=E5=A2=9E=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=99=BB=E5=BD=95=EF=BC=8Cgitea=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/users/get_user_info.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index 250c5cc4a..0e8cda5e3 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -26,4 +26,4 @@ json.super_description @user.super_description json.(@user, :show_email, :show_department, :show_location, :show_super_description) json.message_unread_total @message_unread_total json.has_trace_user @user.trace_user.present? -json.is_new params[:login].to_s.include?("#{@user.login}") \ No newline at end of file +json.is_new @user.login.present? && params[:login].to_s.include?("#{@user.login}") \ No newline at end of file From 8e8ec821f24cb2a38a1af45d043b415518511d3e Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 24 May 2022 17:26:10 +0800 Subject: [PATCH 60/82] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E9=82=AE=E7=AE=B1=E6=9D=A5=E8=8E=B7=E5=8F=96=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/concerns/render_helper.rb | 2 +- app/controllers/users_controller.rb | 6 ++++++ app/views/users/email_search.json.jbuilder | 1 + config/routes.rb | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 app/views/users/email_search.json.jbuilder diff --git a/app/controllers/concerns/render_helper.rb b/app/controllers/concerns/render_helper.rb index 81e85d1ce..4b289cd0c 100644 --- a/app/controllers/concerns/render_helper.rb +++ b/app/controllers/concerns/render_helper.rb @@ -3,7 +3,7 @@ module RenderHelper render json: { status: 0, message: 'success' }.merge(data) end - def render_error(status = -1, message = '') + def render_error(message = '', status=-1) render json: { status: status, message: message } end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 532f29ba1..4b2871c76 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -301,6 +301,12 @@ class UsersController < ApplicationController end end + def email_search + return render_error('请输入email') if params[:email].blank? + @user = User.find_by(mail: params[:email]) + return render_not_found unless @user.present? + end + private def load_user @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) diff --git a/app/views/users/email_search.json.jbuilder b/app/views/users/email_search.json.jbuilder new file mode 100644 index 000000000..2b31e1826 --- /dev/null +++ b/app/views/users/email_search.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'users/user', locals: { user: @user } diff --git a/config/routes.rb b/config/routes.rb index eae7cf8eb..393dceb36 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -237,6 +237,7 @@ Rails.application.routes.draw do get :trustie_projects get :trustie_related_projects post :sync_user_info + get :email_search scope '/ci', module: :ci do scope do From e36c7a4b6aa1cb19f3872f21214fe50388275186 Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 24 May 2022 18:09:36 +0800 Subject: [PATCH 61/82] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E4=B8=8D=E9=9C=80=E8=A6=81return=20404?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/users_controller.rb | 1 - app/views/users/email_search.json.jbuilder | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4b2871c76..98a48c6ec 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -304,7 +304,6 @@ class UsersController < ApplicationController def email_search return render_error('请输入email') if params[:email].blank? @user = User.find_by(mail: params[:email]) - return render_not_found unless @user.present? end private diff --git a/app/views/users/email_search.json.jbuilder b/app/views/users/email_search.json.jbuilder index 2b31e1826..c077c3fad 100644 --- a/app/views/users/email_search.json.jbuilder +++ b/app/views/users/email_search.json.jbuilder @@ -1 +1,5 @@ -json.partial! 'users/user', locals: { user: @user } +if @user.present? + json.partial! 'users/user', locals: { user: @user } +else + json.null +end From 2ea78b4f208e578ccaf5dc8869d63f820ddc8904 Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 25 May 2022 11:47:35 +0800 Subject: [PATCH 62/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0:=20=E5=B7=B2=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E7=94=A8=E6=88=B7=E5=AF=B9=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=E3=80=81=E9=82=AE=E7=AE=B1=E3=80=81=E7=94=B5=E8=AF=9D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/accounts_controller.rb | 7 +++++- app/forms/register/base_form.rb | 24 ++++++++++++++----- .../register/login_check_columns_form.rb | 19 +++++++++++++++ config/routes.rb | 1 + 4 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 app/forms/register/login_check_columns_form.rb diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 1af348abd..531095b4b 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,5 +1,5 @@ class AccountsController < ApplicationController - before_action :require_login, only: [:simple_update] + before_action :require_login, only: [:login_check, :simple_update] include ApplicationHelper #skip_before_action :check_account, :only => [:logout] @@ -333,6 +333,11 @@ class AccountsController < ApplicationController Register::CheckColumnsForm.new(check_params).validate! render_ok end + + def login_check + Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate! + render_ok + end private diff --git a/app/forms/register/base_form.rb b/app/forms/register/base_form.rb index df5abd871..26382b7e3 100644 --- a/app/forms/register/base_form.rb +++ b/app/forms/register/base_form.rb @@ -10,28 +10,40 @@ module Register VerifiCodeError = Class.new(Error) private - def check_login(login) + def check_login(login, user=nil) login = strip(login) raise LoginError, "登录名格式有误" unless login =~ CustomRegexp::LOGIN login_exist = Owner.exists?(login: login) || ReversedKeyword.check_exists?(login) - raise LoginError, '登录名已被使用' if login_exist + if user.present? + raise LoginError, '登录名已被使用' if login_exist && login != user&.login + else + raise LoginError, '登录名已被使用' if login_exist + end end - def check_mail(mail) + def check_mail(mail, user=nil) mail = strip(mail) raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL mail_exist = Owner.exists?(mail: mail) - raise EmailError, '邮箱已被使用' if mail_exist + if user.present? + raise EmailError, '邮箱已被使用' if mail_exist && mail != user&.mail + else + raise EmailError, '邮箱已被使用' if mail_exist + end end - def check_phone(phone) + def check_phone(phone, user=nil) phone = strip(phone) raise PhoneError, "手机号格式有误" unless phone =~ CustomRegexp::PHONE phone_exist = Owner.exists?(phone: phone) - raise PhoneError, '手机号已被使用' if phone_exist + if user.present? + raise PhoneError, '手机号已被使用' if phone_exist && phone != user&.phone + else + raise PhoneError, '手机号已被使用' if phone_exist + end end def check_password(password) diff --git a/app/forms/register/login_check_columns_form.rb b/app/forms/register/login_check_columns_form.rb new file mode 100644 index 000000000..0c6a93af3 --- /dev/null +++ b/app/forms/register/login_check_columns_form.rb @@ -0,0 +1,19 @@ +module Register + class LoginCheckColumnsForm < Register::BaseForm + attr_accessor :type, :value, :user + + validates :type, presence: true, numericality: true + validates :value, presence: true + validate :check! + + def check! + # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) + case strip(type).to_i + when 1 then check_login(strip(value), user) + when 2 then check_mail(strip(value), user) + when 3 then check_phone(strip(value), user) + else raise("type值无效") + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 393dceb36..4d1e3adeb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -203,6 +203,7 @@ Rails.application.routes.draw do post :remote_password post :change_password post :check + post :login_check post :simple_update end end From bd16ca476d8d84e868b778c2a0f0f9a95dbe8a10 Mon Sep 17 00:00:00 2001 From: yystopf Date: Thu, 26 May 2022 15:08:42 +0800 Subject: [PATCH 63/82] =?UTF-8?q?=E5=A2=9E=E5=8A=A0:=20=E9=80=80=E5=87=BA?= =?UTF-8?q?=E4=BB=93=E5=BA=93api=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/docs/slate/source/includes/_projects.md | 32 ++++++++++++++ public/docs/api.html | 46 +++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/app/docs/slate/source/includes/_projects.md b/app/docs/slate/source/includes/_projects.md index d4899a710..e133bcdda 100644 --- a/app/docs/slate/source/includes/_projects.md +++ b/app/docs/slate/source/includes/_projects.md @@ -849,4 +849,36 @@ await octokit.request('POST /api/:owner/:repo/applied_transfer_projects/cancel.j "created_at": "2021-04-26 09:54", "time_ago": "1分钟前" } +``` + +## 退出项目 +供项目成员(开发者、报告者)退出项目用 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/quit.json +``` + +```javascript +await octokit.request('POST /api/:owner/:repo/quit.json') +``` + +### HTTP 请求 +`POST /api/:owner/:repo/quit.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| |string |用户登录名 | +|repo |是| |string |项目标识identifier | + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} ``` \ No newline at end of file diff --git a/public/docs/api.html b/public/docs/api.html index 45da64400..8ef6924b9 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -467,6 +467,9 @@
    • 取消迁移项目
    • +
    • + 退出项目 +
  • @@ -6026,6 +6029,49 @@ http://localhost:3000/api/ceshi1/ceshi_repo1/applied_transfer_projects/organizat "created_at": "2021-04-26 09:54", "time_ago": "1分钟前" } +

    退出项目

    +

    供项目成员(开发者、报告者)退出项目用

    + +
    +

    示例:

    +
    +
    curl -X POST http://localhost:3000/api/ceshi1/ceshi_repo1/quit.json
    +
    await octokit.request('POST /api/:owner/:repo/quit.json')
    +

    HTTP 请求

    +

    POST /api/:owner/:repo/quit.json

    +

    请求参数

    + + + + + + + + + + + + + + + + + + + + + + + +
    参数必选默认类型字段说明
    ownerstring用户登录名
    repostring项目标识identifier
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
     

    Repositories

    仓库详情

    仓库详情

    From a6e50d2a250168a0cb981d403a6a4ec65a37ea5b Mon Sep 17 00:00:00 2001 From: yystopf Date: Fri, 27 May 2022 10:48:20 +0800 Subject: [PATCH 64/82] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20devops=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=BF=80=E6=B4=BB=E9=A1=B9=E7=9B=AE=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/ci/projects_controller.rb | 2 +- .../concerns/ci/cloud_account_manageable.rb | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 69644e7a5..06e515378 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -40,9 +40,9 @@ class Ci::ProjectsController < Ci::BaseController begin ActiveRecord::Base.transaction do if @repo + @repo.destroy! if @repo&.repo_user_id == 0 return render_error('该项目已经激活') if @repo.repo_active? @repo.activate!(@project) - return render_ok else @repo = Ci::Repo.auto_create!(@ci_user, @project) @ci_user.update_column(:user_syncing, false) diff --git a/app/controllers/concerns/ci/cloud_account_manageable.rb b/app/controllers/concerns/ci/cloud_account_manageable.rb index 9f0998edc..f2157657e 100644 --- a/app/controllers/concerns/ci/cloud_account_manageable.rb +++ b/app/controllers/concerns/ci/cloud_account_manageable.rb @@ -160,9 +160,9 @@ module Ci::CloudAccountManageable 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") - clientId = client_id(oauth) - grant_url = "#{Gitea.gitea_config[:domain]}/login/oauth/authorize?client_id=#{clientId}&redirect_uri=#{redirect_uri}&response_type=code&state=#{state}" + # redirect_uri = CGI.escape("#{@cloud_account.drone_url}/login") + # clientId = client_id(oauth) + grant_url = "#{@cloud_account.drone_url}/login" logger.info "[gitea] grant_url: #{grant_url}" conn = Faraday.new(url: grant_url) do |req| @@ -179,7 +179,7 @@ module Ci::CloudAccountManageable def drone_oauth_user!(url, state) logger.info "[drone] drone_oauth_user url: #{url}" - conn = Faraday.new(url: "#{Gitea.gitea_config[:domain]}#{url}") do |req| + 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}" @@ -188,8 +188,8 @@ module Ci::CloudAccountManageable response = conn.get logger.info "[drone] response headers: #{response.headers}" - true - # response.headers['location'].include?('error') ? false : true + # true + response.headers['location'].include?('error') ? false : true end private From 48cf92a2cf7c5cf782e861d1971a5fb6ef2989c2 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 14:19:57 +0800 Subject: [PATCH 65/82] =?UTF-8?q?rake=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/tasks/sync_outer_repo.rake | 35 +++++++++++++++++++++++++++++++++ public/rcore-os_repo.xlsx | Bin 0 -> 15153 bytes 2 files changed, 35 insertions(+) create mode 100644 lib/tasks/sync_outer_repo.rake create mode 100644 public/rcore-os_repo.xlsx diff --git a/lib/tasks/sync_outer_repo.rake b/lib/tasks/sync_outer_repo.rake new file mode 100644 index 000000000..77073cdb6 --- /dev/null +++ b/lib/tasks/sync_outer_repo.rake @@ -0,0 +1,35 @@ +namespace :create_mulan_repository do + desc "sync outer repository to gitlink" + task sync_from_gitee: :environment do + file = ENV['file'] || "rcore-os_repo.xlsx" + user_type = ENV['type'] || "User" + doc = SimpleXlsxReader.open("#{Rails.root}/public/#{file}") + data = doc.sheets.first.rows + data.each_with_index do |row, index| + next if index == 0 + begin + user = (user_type == "User" ? User.find_by(login: row[1]) : Owner.find_by(login: row[1])) + project = user.projects.find_by(identifier: row[4]) + unless project.present? + p_category = ProjectCategory.find_or_create_by(name: row[6]) + p_language = ProjectLanguage.find_or_create_by(name: row[7].split("/")[0]) + p_license = License.find_by(name: row[8]) + + mirror_params = { + user_id: user.id, + name: row[5], + description: row[9], + repository_name: row[4], + project_category_id: p_category.id, + project_language_id: p_language.id, + clone_addr: row[10] + } + Projects::MigrateService.call(user, mirror_params) + end + puts "sync outer repository to gitlink Success repo: #{row[5]} username: #{row[0]}" + rescue Exception => e + puts "sync outer repository to gitlink Error repo: #{row[5]} username: #{row[0]}" + end + end + end +end \ No newline at end of file diff --git a/public/rcore-os_repo.xlsx b/public/rcore-os_repo.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..83ff6f5fa15dac212bdafc21f541b351d0399acb GIT binary patch literal 15153 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 literal 0 HcmV?d00001 From a00b1d453057885114dd3ce5ff34426dd4d62963 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 14:21:00 +0800 Subject: [PATCH 66/82] =?UTF-8?q?rake=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/tasks/sync_outer_repo.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/sync_outer_repo.rake b/lib/tasks/sync_outer_repo.rake index 77073cdb6..39c0a53da 100644 --- a/lib/tasks/sync_outer_repo.rake +++ b/lib/tasks/sync_outer_repo.rake @@ -1,6 +1,6 @@ -namespace :create_mulan_repository do +namespace :sync_ourter_repo do desc "sync outer repository to gitlink" - task sync_from_gitee: :environment do + task done: :environment do file = ENV['file'] || "rcore-os_repo.xlsx" user_type = ENV['type'] || "User" doc = SimpleXlsxReader.open("#{Rails.root}/public/#{file}") From 40a987116f38a8a294283b5f5f796d594d9d9707 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 14:25:16 +0800 Subject: [PATCH 67/82] =?UTF-8?q?rake=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/tasks/sync_outer_repo.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/sync_outer_repo.rake b/lib/tasks/sync_outer_repo.rake index 39c0a53da..e7303af03 100644 --- a/lib/tasks/sync_outer_repo.rake +++ b/lib/tasks/sync_outer_repo.rake @@ -1,4 +1,4 @@ -namespace :sync_ourter_repo do +namespace :sync_outer_repo do desc "sync outer repository to gitlink" task done: :environment do file = ENV['file'] || "rcore-os_repo.xlsx" From 95f98710d61e73e60c4c265688b518a427a32293 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 14:26:53 +0800 Subject: [PATCH 68/82] =?UTF-8?q?rake=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/tasks/sync_outer_repo.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/sync_outer_repo.rake b/lib/tasks/sync_outer_repo.rake index e7303af03..40b9b6615 100644 --- a/lib/tasks/sync_outer_repo.rake +++ b/lib/tasks/sync_outer_repo.rake @@ -28,7 +28,7 @@ namespace :sync_outer_repo do end puts "sync outer repository to gitlink Success repo: #{row[5]} username: #{row[0]}" rescue Exception => e - puts "sync outer repository to gitlink Error repo: #{row[5]} username: #{row[0]}" + puts "sync outer repository to gitlink Error repo: #{row[5]} username: #{row[0]}, error:#{e}" end end end From 0b35f56212901d937b2e7d5df22420832649142b Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 14:31:29 +0800 Subject: [PATCH 69/82] =?UTF-8?q?rake=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE,?= =?UTF-8?q?=E6=97=A0=E8=AF=AD=E8=A8=80=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/tasks/sync_outer_repo.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/sync_outer_repo.rake b/lib/tasks/sync_outer_repo.rake index 40b9b6615..6f9ba2458 100644 --- a/lib/tasks/sync_outer_repo.rake +++ b/lib/tasks/sync_outer_repo.rake @@ -12,7 +12,7 @@ namespace :sync_outer_repo do project = user.projects.find_by(identifier: row[4]) unless project.present? p_category = ProjectCategory.find_or_create_by(name: row[6]) - p_language = ProjectLanguage.find_or_create_by(name: row[7].split("/")[0]) + p_language = ProjectLanguage.find_or_create_by(name: row[7].to_s.split("/")[0]) if row[7] p_license = License.find_by(name: row[8]) mirror_params = { @@ -21,7 +21,7 @@ namespace :sync_outer_repo do description: row[9], repository_name: row[4], project_category_id: p_category.id, - project_language_id: p_language.id, + project_language_id: p_language&.id, clone_addr: row[10] } Projects::MigrateService.call(user, mirror_params) From 122022332237593e583b071d094f035d41cee436 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 14:43:16 +0800 Subject: [PATCH 70/82] =?UTF-8?q?rake=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE,?= =?UTF-8?q?=E6=97=A0=E8=AF=AD=E8=A8=80=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/organizations/teams/_detail.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/organizations/teams/_detail.json.jbuilder b/app/views/organizations/teams/_detail.json.jbuilder index 68572814f..842995432 100644 --- a/app/views/organizations/teams/_detail.json.jbuilder +++ b/app/views/organizations/teams/_detail.json.jbuilder @@ -9,7 +9,7 @@ json.num_projects team.num_projects json.num_users team.num_users json.units team.team_units.pluck(:unit_type) json.users team.team_users.each do |user| - json.partial! "organizations/user_detail", user: user&.user + json.partial! "organizations/user_detail", user: user&.user if user&.user end json.is_admin @is_admin json.is_member team.is_member?(current_user.id) From e76822eb34a639d03dda6b2e1c0088b9364241b6 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 16:54:09 +0800 Subject: [PATCH 71/82] =?UTF-8?q?fixed=20ci=E6=8A=A5=E9=94=99200=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/ci/projects_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 06e515378..c358611eb 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -41,7 +41,7 @@ class Ci::ProjectsController < Ci::BaseController ActiveRecord::Base.transaction do if @repo @repo.destroy! if @repo&.repo_user_id == 0 - return render_error('该项目已经激活') if @repo.repo_active? + return tip_exception('该项目已经激活') if @repo.repo_active? @repo.activate!(@project) else @repo = Ci::Repo.auto_create!(@ci_user, @project) @@ -55,7 +55,7 @@ class Ci::ProjectsController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end end From d27f55bb35b863b6110df7680d2e76ab9aeb0f99 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Fri, 27 May 2022 16:55:52 +0800 Subject: [PATCH 72/82] =?UTF-8?q?fixed=20ci=E6=8A=A5=E9=94=99200=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/ci/projects_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 06e515378..c358611eb 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -41,7 +41,7 @@ class Ci::ProjectsController < Ci::BaseController ActiveRecord::Base.transaction do if @repo @repo.destroy! if @repo&.repo_user_id == 0 - return render_error('该项目已经激活') if @repo.repo_active? + return tip_exception('该项目已经激活') if @repo.repo_active? @repo.activate!(@project) else @repo = Ci::Repo.auto_create!(@ci_user, @project) @@ -55,7 +55,7 @@ class Ci::ProjectsController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end end From 17fb43cea83ca814ed5c66add62de41d7b1fe2ab Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Mon, 30 May 2022 10:24:39 +0800 Subject: [PATCH 73/82] =?UTF-8?q?render=5Ferror=E6=9B=BF=E6=8D=A2=E6=88=90?= =?UTF-8?q?tip=5Fexception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/ci/projects_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 06e515378..c358611eb 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -41,7 +41,7 @@ class Ci::ProjectsController < Ci::BaseController ActiveRecord::Base.transaction do if @repo @repo.destroy! if @repo&.repo_user_id == 0 - return render_error('该项目已经激活') if @repo.repo_active? + return tip_exception('该项目已经激活') if @repo.repo_active? @repo.activate!(@project) else @repo = Ci::Repo.auto_create!(@ci_user, @project) @@ -55,7 +55,7 @@ class Ci::ProjectsController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end end From 6448a30e0301ed24eea251f1f766d1755f8991eb Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Mon, 30 May 2022 10:25:43 +0800 Subject: [PATCH 74/82] =?UTF-8?q?render=5Ferror=E6=9B=BF=E6=8D=A2=E6=88=90?= =?UTF-8?q?tip=5Fexception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ci/cloud_accounts_controller.rb | 34 +++++++++---------- app/controllers/ci/pipelines_controller.rb | 24 ++++++------- app/controllers/ci/projects_controller.rb | 6 ++-- app/controllers/ci/secrets_controller.rb | 6 ++-- app/controllers/ci/templates_controller.rb | 6 ++-- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/app/controllers/ci/cloud_accounts_controller.rb b/app/controllers/ci/cloud_accounts_controller.rb index 7d829dbd7..d22b2ba41 100644 --- a/app/controllers/ci/cloud_accounts_controller.rb +++ b/app/controllers/ci/cloud_accounts_controller.rb @@ -14,12 +14,12 @@ class Ci::CloudAccountsController < Ci::BaseController def create flag, msg = check_bind_cloud_account! - return render_error(msg) if flag === true + return tip_exception(msg) if flag === true ActiveRecord::Base.transaction do @cloud_account = bind_account! if @cloud_account.blank? - render_error('激活失败, 请检查你的云服务器信息是否正确.') + tip_exception('激活失败, 请检查你的云服务器信息是否正确.') raise ActiveRecord::Rollback else current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) @@ -27,17 +27,17 @@ class Ci::CloudAccountsController < Ci::BaseController end end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def activate - return render_error('请先认证') unless current_user.ci_certification? + return tip_exception('请先认证') 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? + return tip_exception('该项目已经激活') if @repo.repo_active? @repo.activate!(@project) else @repo = Ci::Repo.auto_create!(@ci_user, @project) @@ -50,7 +50,7 @@ class Ci::CloudAccountsController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end end @@ -59,39 +59,39 @@ class Ci::CloudAccountsController < Ci::BaseController def bind flag, msg = check_bind_cloud_account! - return render_error(msg) if flag === true + return tip_exception(msg) if flag === true ActiveRecord::Base.transaction do @cloud_account = bind_account! if @cloud_account.blank? - render_error('激活失败, 请检查你的云服务器信息是否正确.') + tip_exception('激活失败, 请检查你的云服务器信息是否正确.') raise ActiveRecord::Rollback else current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) end end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def trustie_bind account = params[:account].to_s - return render_error("account不能为空.") if account.blank? + return tip_exception("account不能为空.") if account.blank? flag, msg = check_trustie_bind_cloud_account! - return render_error(msg) if flag === true + return tip_exception(msg) if flag === true ActiveRecord::Base.transaction do @cloud_account = trustie_bind_account! if @cloud_account.blank? - render_error('激活失败, 请检查你的云服务器信息是否正确.') + tip_exception('激活失败, 请检查你的云服务器信息是否正确.') raise ActiveRecord::Rollback else current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) end end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def unbind @@ -107,18 +107,18 @@ class Ci::CloudAccountsController < Ci::BaseController render_ok end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def oauth_grant password = params[:password].to_s - return render_error('你输入的密码不正确.') unless current_user.check_password?(password) + return tip_exception('你输入的密码不正确.') unless current_user.check_password?(password) oauth = current_user.oauths.last - return render_error("服务器出小差了.") if oauth.blank? + return tip_exception("服务器出小差了.") if oauth.blank? result = gitea_oauth_grant!(password, oauth) - return render_error('授权失败.') unless result === true + return tip_exception('授权失败.') unless result === true current_user.set_drone_step!(User::DEVOPS_CERTIFICATION) end diff --git a/app/controllers/ci/pipelines_controller.rb b/app/controllers/ci/pipelines_controller.rb index ea8b25f77..288059659 100644 --- a/app/controllers/ci/pipelines_controller.rb +++ b/app/controllers/ci/pipelines_controller.rb @@ -30,7 +30,7 @@ class Ci::PipelinesController < Ci::BaseController ActiveRecord::Base.transaction do size = Ci::Pipeline.where('branch=? and identifier=? and owner=?', params[:branch], params[:repo], params[:owner]).size if size > 0 - render_error("#{params[:branch]}分支已经存在流水线!") + tip_exception("#{params[:branch]}分支已经存在流水线!") return end pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name],owner: params[:owner], @@ -53,7 +53,7 @@ class Ci::PipelinesController < Ci::BaseController render_ok({id: pipeline.id}) end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end # 在代码库创建文件 @@ -118,7 +118,7 @@ class Ci::PipelinesController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def destroy @@ -132,7 +132,7 @@ class Ci::PipelinesController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def content @@ -182,7 +182,7 @@ class Ci::PipelinesController < Ci::BaseController render_ok end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def update_stage @@ -192,7 +192,7 @@ class Ci::PipelinesController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def delete_stage @@ -205,7 +205,7 @@ class Ci::PipelinesController < Ci::BaseController render_ok end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def update_stage_index(pipeline_id, show_index, diff) @@ -229,7 +229,7 @@ class Ci::PipelinesController < Ci::BaseController unless steps.empty? steps.each do |step| unless step[:template_id] - render_error('请选择模板!') + tip_exception('请选择模板!') return end if !step[:id] @@ -246,7 +246,7 @@ class Ci::PipelinesController < Ci::BaseController render_ok end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def create_stage_step @@ -262,7 +262,7 @@ class Ci::PipelinesController < Ci::BaseController render_ok end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def update_stage_step @@ -279,7 +279,7 @@ class Ci::PipelinesController < Ci::BaseController render_ok end rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def delete_stage_step @@ -289,6 +289,6 @@ class Ci::PipelinesController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end end diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index c358611eb..53f11fb23 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -30,12 +30,12 @@ class Ci::ProjectsController < Ci::BaseController @file = interactor.result render_result(1, "更新成功") else - render_error(interactor.error) + tip_exception(interactor.error) end end def activate - return render_error('你还未认证') unless current_user.ci_certification? + return tip_exception('你还未认证') unless current_user.ci_certification? begin ActiveRecord::Base.transaction do @@ -60,7 +60,7 @@ class Ci::ProjectsController < Ci::BaseController end def deactivate - return render_error('该项目已经取消激活') if !@repo.repo_active? + return tip_exception('该项目已经取消激活') if !@repo.repo_active? @project.update_column(:open_devops, false) @repo.deactivate_repos! diff --git a/app/controllers/ci/secrets_controller.rb b/app/controllers/ci/secrets_controller.rb index 324f0bb53..3057824e2 100644 --- a/app/controllers/ci/secrets_controller.rb +++ b/app/controllers/ci/secrets_controller.rb @@ -20,14 +20,14 @@ class Ci::SecretsController < Ci::BaseController if result["id"] render_ok else - render_error(result["message"]) + tip_exception(result["message"]) end else result = Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], options).create_secret if result["id"] render_ok else - render_error(result["message"]) + tip_exception(result["message"]) end end end @@ -39,7 +39,7 @@ class Ci::SecretsController < Ci::BaseController Ci::Drone::API.new(@ci_user.user_hash, ci_drone_url, params[:owner], params[:repo], {name: name}).delete_secret render_ok else - render_error("参数名不能为空") + tip_exception("参数名不能为空") end rescue Exception => ex render_ok diff --git a/app/controllers/ci/templates_controller.rb b/app/controllers/ci/templates_controller.rb index cb49590dc..22c209523 100644 --- a/app/controllers/ci/templates_controller.rb +++ b/app/controllers/ci/templates_controller.rb @@ -50,7 +50,7 @@ class Ci::TemplatesController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def update @@ -63,7 +63,7 @@ class Ci::TemplatesController < Ci::BaseController ) render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end def destroy @@ -73,7 +73,7 @@ class Ci::TemplatesController < Ci::BaseController end render_ok rescue Exception => ex - render_error(ex.message) + tip_exception(ex.message) end #======流水线模板查询=====# From d6fd85f536f2b328faae42572da3337a4aa4417f Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Mon, 30 May 2022 11:18:24 +0800 Subject: [PATCH 75/82] =?UTF-8?q?Repository.url=E9=87=8D=E5=86=99=EF=BC=8C?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E9=A1=B9=E7=9B=AE=E6=97=B6=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/ci/pipelines_controller.rb | 1 + app/models/repository.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/app/controllers/ci/pipelines_controller.rb b/app/controllers/ci/pipelines_controller.rb index 288059659..d6eee1387 100644 --- a/app/controllers/ci/pipelines_controller.rb +++ b/app/controllers/ci/pipelines_controller.rb @@ -81,6 +81,7 @@ class Ci::PipelinesController < Ci::BaseController repo_branch: pipeline.branch, repo_config: pipeline.file_name } + Rails.logger.info("########create_params===#{create_params.to_json}") repo = Ci::Repo.create_repo(create_params) repo end diff --git a/app/models/repository.rb b/app/models/repository.rb index a012b449a..12cc2fa38 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -48,6 +48,10 @@ class Repository < ApplicationRecord self.identifier.parameterize end + def url + self['url'].blank? ? "#{Rails.application.config_for(:configuration)['platform_url']}/#{self.owner&.login}/#{self.identifier}.git" : self['url'] + end + # with repository is mirror def set_mirror! self.build_mirror(status: Mirror.statuses[:waiting]).save From 169dc84e22f933e9d0b5d1e40fecc4a0ac8dacd4 Mon Sep 17 00:00:00 2001 From: yystopf Date: Mon, 30 May 2022 14:50:12 +0800 Subject: [PATCH 76/82] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E4=B8=8B=E9=A1=B9=E7=9B=AE=E9=9C=80=E8=BF=94=E5=9B=9E=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E4=B8=BA=E5=85=AC=E6=9C=89=E9=A1=B9=E7=9B=AE=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/organizations/projects/index.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/organizations/projects/index.json.jbuilder b/app/views/organizations/projects/index.json.jbuilder index a663b0c18..5a4615fc7 100644 --- a/app/views/organizations/projects/index.json.jbuilder +++ b/app/views/organizations/projects/index.json.jbuilder @@ -1,6 +1,6 @@ json.total_count @projects.total_count json.projects @projects.each do |project| - json.(project, :id, :name, :identifier, :description, :forked_count, :praises_count, :forked_from_project_id) + json.(project, :id, :name, :identifier, :description, :forked_count, :praises_count, :forked_from_project_id, :is_public) json.mirror_url project.repository&.mirror_url json.type project.numerical_for_project_type json.praised project.praised_by?(current_user) From 9427db3e5a9c1856e8519506fada75c7dc68248b Mon Sep 17 00:00:00 2001 From: yystopf Date: Tue, 31 May 2022 16:34:08 +0800 Subject: [PATCH 77/82] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/notices_controller.rb | 14 ++++++- app/jobs/send_template_message_job.rb | 11 +++++ app/models/message_template/custom_tip.rb | 51 +++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 app/models/message_template/custom_tip.rb diff --git a/app/controllers/notices_controller.rb b/app/controllers/notices_controller.rb index bf7eb21b1..7b67412e7 100644 --- a/app/controllers/notices_controller.rb +++ b/app/controllers/notices_controller.rb @@ -1,7 +1,7 @@ class NoticesController < ApplicationController def create - tip_exception("参数有误") if params["source"].blank? + return tip_exception("参数有误") if params["source"].blank? user_id = params[:user_id] if params["source"] == "CompetitionBegin" @@ -13,9 +13,21 @@ class NoticesController < ApplicationController elsif params["source"] == "CompetitionReview" competition_id = params[:competition_id] SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id) + elsif params["source"] == "CustomTip" + users_id = params[:users_id] + props = params[:props].to_unsafe_hash + return tip_exception("参数有误") unless props.is_a?(Hash) && users_id.is_a?(Array) + template_id = params[:template_id] + SendTemplateMessageJob.perform_later('CustomTip', users_id, template_id, props) else tip_exception("#{params["source"]}未配置") end render_ok end + + + private + def params_props + params.require(:notice).permit(:props) + end end diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb index 9cc819a11..bec3f7b08 100644 --- a/app/jobs/send_template_message_job.rb +++ b/app/jobs/send_template_message_job.rb @@ -4,6 +4,17 @@ class SendTemplateMessageJob < ApplicationJob def perform(source, *args) Rails.logger.info "SendTemplateMessageJob [args] #{args}" case source + when 'CustomTip' + receivers_id, template_id, props = args[0], args[1], args[2] + template = MessageTemplate.find_by_id(template_id) + return unless template.present? + receivers = User.where(id: receivers_id) + receivers_string, content, notification_url = MessageTemplate::CustomTip.get_message_content(receivers, template, props) + Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {receivers_id: receivers_id, template_id: template_id, props: props}) + receivers.find_each do |receiver| + receivers_email_string, email_title, email_content = MessageTemplate::CustomTip.get_email_message_content(receiver, template, props) + Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) + end when 'FollowTip' watcher_id = args[0] watcher = Watcher.find_by_id(watcher_id) diff --git a/app/models/message_template/custom_tip.rb b/app/models/message_template/custom_tip.rb new file mode 100644 index 000000000..6c5a3345d --- /dev/null +++ b/app/models/message_template/custom_tip.rb @@ -0,0 +1,51 @@ +# == Schema Information +# +# Table name: message_templates +# +# id :integer not null, primary key +# type :string(255) +# sys_notice :text(65535) +# email :text(65535) +# created_at :datetime not null +# updated_at :datetime not null +# notification_url :string(255) +# email_title :string(255) +# + +# 统一模板( + +class MessageTemplate::CustomTip < MessageTemplate + + # MessageTemplate::CustomTip.get_message_content(User.where(login: 'yystopf'), "hahah") + def self.get_message_content(receivers, template, props={}) + return '', '', '' if receivers.blank? || template.blank? + content = template.sys_notice + notification_url = template.notification_url + props.each do |k, v| + content.gsub!("{#{k}}", v) + notification_url.gsub!("{#{k}}", v) + end + return receivers_string(receivers), content, notification_url + rescue => e + Rails.logger.info("MessageTemplate::CustomTip.get_message_content [ERROR] #{e}") + return '', '', '' + end + + def self.get_email_message_content(receiver, template, props={}) + return '', '', '' if receiver.blank? || template.blank? + title = template.email_title + content = template.email + props.each do |k, v| + title.gsub!("{#{k}}", v) + content.gsub!("{#{k}}", v) + end + content.gsub!('{receiver}', receiver&.real_name) + title.gsub!('{platform}', PLATFORM) + content.gsub!('{platform}', PLATFORM) + + return receiver&.mail, title, content + rescue => e + Rails.logger.info("MessageTemplate::CustomTip.get_email_message_content [ERROR] #{e}") + return '', '', '' + end +end \ No newline at end of file From dc787a35d4e0918f2c4fce8497657fe5e6d2e5fd Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Wed, 1 Jun 2022 09:23:11 +0800 Subject: [PATCH 78/82] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=92=8C=E6=8F=8F=E8=BF=B0=E5=A2=9E=E5=8A=A0=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E8=AF=8D=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/project.rb | 831 +++++++++++++++++++++--------------------- 1 file changed, 419 insertions(+), 412 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 1edc088f6..0489c8c82 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,412 +1,419 @@ -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) default(""), not null -# description :text(4294967295) -# homepage :string(255) default("") -# is_public :boolean default("1"), not null -# parent_id :integer -# created_on :datetime -# updated_on :datetime -# identifier :string(255) -# status :integer default("1"), not null -# lft :integer -# rgt :integer -# inherit_members :boolean default("0"), not null -# project_type :integer default("0") -# hidden_repo :boolean default("0"), not null -# attachmenttype :integer default("1") -# user_id :integer -# dts_test :integer default("0") -# enterprise_name :string(255) -# organization_id :integer -# project_new_type :integer -# gpid :integer -# forked_from_project_id :integer -# forked_count :integer default("0") -# publish_resource :integer default("0") -# visits :integer default("0") -# hot :integer default("0") -# invite_code :string(255) -# qrcode :string(255) -# qrcode_expiretime :integer default("0") -# script :text(65535) -# training_status :integer default("0") -# rep_identifier :string(255) -# project_category_id :integer -# project_language_id :integer -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# is_pinned :boolean default("0") -# recommend_index :integer default("0") -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_invite_code (invite_code) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_license_id (license_id) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_category_id (project_category_id) -# index_projects_on_project_language_id (project_language_id) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - -class Project < ApplicationRecord - include Matchable - include Publicable - include Watchable - include ProjectOperable - include Dcodes - - # common:开源托管项目 - # mirror:普通镜像项目,没有定时同步功能 - # sync_mirror:同步镜像项目,有系统定时同步功能,且用户可手动同步操作 - # - enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } - - # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 - enum platform: { forge: 0, educoder: 1 } - - belongs_to :ignore, optional: true - belongs_to :license, optional: true - belongs_to :owner, class_name: 'Owner', foreign_key: :user_id, optional: true - belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects - belongs_to :project_category, optional: true , :counter_cache => true - belongs_to :project_language, optional: true , :counter_cache => true - belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id - has_many :project_trends, dependent: :destroy - has_many :watchers, as: :watchable, dependent: :destroy - has_many :fork_users, dependent: :destroy - has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy - has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id - has_one :project_educoder, dependent: :destroy - - has_one :project_score, dependent: :destroy - has_one :repository, dependent: :destroy - has_many :pull_requests, dependent: :destroy - has_many :issue_tags, -> { order("issue_tags.created_at DESC") }, dependent: :destroy - has_many :issues, dependent: :destroy - # has_many :user_grades, dependent: :destroy - has_many :attachments, as: :container, dependent: :destroy - has_one :project_score, dependent: :destroy - has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy - has_many :praise_treads, as: :praise_tread_object, dependent: :destroy - has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" - has_one :project_detail, dependent: :destroy - has_many :project_units, dependent: :destroy - has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy - has_many :pinned_projects, dependent: :destroy - has_many :has_pinned_users, through: :pinned_projects, source: :user - has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id - has_many :user_trace_tasks, dependent: :destroy - after_create :incre_user_statistic, :incre_platform_statistic - after_save :check_project_members - before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data - before_destroy :decre_project_common, :decre_forked_from_project_count - after_destroy :decre_user_statistic, :decre_platform_statistic - scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} - scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} - scope :recommend, -> { visible.project_statics_select.where(recommend: true) } - scope :pinned, -> {where(is_pinned: true)} - - delegate :content, to: :project_detail, allow_nil: true - delegate :name, to: :license, prefix: true, allow_nil: true - - def self.all_visible(user_id=nil) - user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql - org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql - if user_id.present? - org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql - org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql - return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible - else - return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible - end - end - - def reset_cache_data - CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id) - if changes[:user_id].present? - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) - end - if changes[:project_language_id].present? - first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first) - last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id) - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) - end - if changes[:is_public].present? - if changes[:is_public][0] && !changes[:is_public][1] - CacheAsyncClearJob.perform_later('project_rank_service', self.id) - end - if !changes[:is_public][0] && changes[:is_public][1] - $redis_cache.srem("v2-project-rank-deleted", self.id) - end - end - end - - def decre_project_common - CacheAsyncClearJob.perform_later('project_common_service', self.id) - end - - def decre_forked_from_project_count - forked_project = self.forked_from_project - if forked_project.present? - forked_project.decrement(:forked_count, 1) - forked_project.save - end - end - - def incre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id) - end - - def decre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id) - end - - def incre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}) - end - - def decre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}) - end - - def is_full_public - owner = self.owner - if owner.is_a?(Organization) - return self.is_public && owner&.visibility == "common" - else - return self.is_public - end - end - - def reset_unmember_followed - if changes[:is_public].present? && changes[:is_public] == [true, false] - self.watchers.where.not(user_id: self.all_collaborators).destroy_all - end - end - - def set_invite_code - if self.invite_code.nil? - self.invite_code= self.generate_dcode('invite_code', 6) - end - end - - def set_recommend_and_is_pinned - self.recommend = self.recommend_index.zero? ? false : true - # 私有项目不允许设置精选和推荐 - unless self.is_public - self.recommend = false - self.recommend_index = 0 - self.is_pinned = false - end - end - - def self.search_project(search) - ransack(name_or_identifier_cont: search) - end - # 创建者 - def creator - User.find(user_id).full_name - end - - def members_user_infos - members.joins(:roles).where("roles.name in ('Manager', 'Developer', 'Reporter')").joins("left join users on members.user_id = users.id ").includes(:user).where("users.type = ?", "User") - # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") - # .pluck("users.id", "users.login","users.lastname", "users.firstname") - end - - def to_param - self.identifier.parameterize - end - - def get_issues_count(status_id) - if status_id.present? - self&.issues.issue_issue.select(:id, :status_id).where(status_id: status_id)&.pluck(:id).size - else - self&.issues.issue_issue.select(:id)&.pluck(:id).size - end - end - - def get_pull_requests_count(status_id) - if status_id.present? - self&.pull_requests.select(:id, :status).where(status: status_id)&.pluck(:id).size - else - self&.pull_requests.select(:id)&.pluck(:id).size - end - end - - #创建项目管理员 - def check_project_members - return if owner.is_a?(Organization) - unless members.present? && members.exists?(user_id: self.user_id) - member_params = { - user_id: self.user_id, - project_id: self.id - } - user_member = Member.new(member_params) - if user_member.save - role_id = Role.select(:id,:position).where(position: 3)&.first&.id - MemberRole.create!(member_id: user_member.id ,role_id: role_id) - end - end - end - - - def self.init_bluck_repository - Project.includes(:repository).find_each do |project| - puts project.id - next if project.owner.blank? - if project.repository.blank? - puts "########### start create repositoy #############" - Repository.create!(project_id: project.id, identifier: Project.generate_identifier, user_id: project&.owner&.id) - end - end - end - - def self.generate_identifier - str_arr = (("a".."z").to_a + ("A".."Z").to_a) - - str = str_arr.shuffle[0..8].join - while Repository.exists?(identifier: str) - str = str_arr.shuffle[0..8].join - end - str - end - - def self.list_user_projects(user_id) - projects = Project.is_private.select(:id,:user_id) - user_not_show_1 = projects.where("user_id != ?",user_id).pluck(:id).uniq - - user_show_2 = projects.joins(:members).where("members.user_id = ?", user_id).pluck(:id).uniq - Project.where.not(id: (user_not_show_1 - user_show_2).uniq) - end - - def members_count - members.select(:id).size - end - - - def can_visited? - is_public? || User.current.admin? || member?(User.current) - end - - def releases_size(current_user_id, type) - if current_user_id == self.user_id && type.to_s == "all" - self.repository.version_releases_count - else - self.repository.version_releases.releases_size - end - end - - def contributor_users - self.pull_requests.select(:user_id).pluck(:user_id).uniq.size - end - - def open_issues_count - issues_count - closed_issues_count - end - - def numerical_for_project_type - self.class.name.constantize.project_types["#{self.project_type}"] - end - - def watched_by? user - watchers.pluck(:user_id).include? user&.id - end - - def praised_by? user - praise_treads.pluck(:user_id).include? user&.id - end - - def get_premission user - return "Owner" if owner?(user) - return "Manager" if manager?(user) - return "Developer" if develper?(user) - return "Reporter" if reporter?(user) - - return "" - end - - def fork_project - Project.find_by(id: self.forked_from_project_id) - end - - def self.members_projects(member_user_id) - joins(:members).where(members: { user_id: member_user_id}) - end - - def self.find_with_namespace(namespace_path, identifier) - logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " - - user = Owner.find_by_login namespace_path - project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") - return nil if project.blank? - - [project, user] - end - - def ci_reactivate? - open_devops_count > 0 - end - - def ci_reactivate!(ci_repo) - ci_repo.update_column(:repo_active, 1) - update_column(:open_devops, true) - increment!(:open_devops_count) - end - - def self.sync_educoder_shixun(url, private_token, page, per_page) - SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) - end - - def self.update_common_projects_count! - ps = ProjectStatistic.first - ps.increment!(:common_projects_count) unless ps.blank? - end - - def self.update_mirror_projects_count! - ps = ProjectStatistic.first - ps.increment!(:mirror_projects_count) unless ps.blank? - end - - def set_updated_on(time) - return if time.blank? - update_column(:updated_on, time) - end - - def is_transfering - applied_transfer_project&.common? ? true : false - end -end +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# license_id :integer +# ignore_id :integer +# default_branch :string(255) default("master") +# website :string(255) +# lesson_url :string(255) +# is_pinned :boolean default("0") +# recommend_index :integer default("0") +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_invite_code (invite_code) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_license_id (license_id) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_category_id (project_category_id) +# index_projects_on_project_language_id (project_language_id) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + +class Project < ApplicationRecord + include Matchable + include Publicable + include Watchable + include ProjectOperable + include Dcodes + + # common:开源托管项目 + # mirror:普通镜像项目,没有定时同步功能 + # sync_mirror:同步镜像项目,有系统定时同步功能,且用户可手动同步操作 + # + enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } + + # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 + enum platform: { forge: 0, educoder: 1 } + + belongs_to :ignore, optional: true + belongs_to :license, optional: true + belongs_to :owner, class_name: 'Owner', foreign_key: :user_id, optional: true + belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects + belongs_to :project_category, optional: true , :counter_cache => true + belongs_to :project_language, optional: true , :counter_cache => true + belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id + has_many :project_trends, dependent: :destroy + has_many :watchers, as: :watchable, dependent: :destroy + has_many :fork_users, dependent: :destroy + has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy + has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id + has_one :project_educoder, dependent: :destroy + + has_one :project_score, dependent: :destroy + has_one :repository, dependent: :destroy + has_many :pull_requests, dependent: :destroy + has_many :issue_tags, -> { order("issue_tags.created_at DESC") }, dependent: :destroy + has_many :issues, dependent: :destroy + # has_many :user_grades, dependent: :destroy + has_many :attachments, as: :container, dependent: :destroy + has_one :project_score, dependent: :destroy + has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy + has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" + has_one :project_detail, dependent: :destroy + has_many :project_units, dependent: :destroy + has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy + has_many :pinned_projects, dependent: :destroy + has_many :has_pinned_users, through: :pinned_projects, source: :user + has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id + has_many :user_trace_tasks, dependent: :destroy + after_create :incre_user_statistic, :incre_platform_statistic + after_save :check_project_members + before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data + before_destroy :decre_project_common, :decre_forked_from_project_count + after_destroy :decre_user_statistic, :decre_platform_statistic + scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} + scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} + scope :recommend, -> { visible.project_statics_select.where(recommend: true) } + scope :pinned, -> {where(is_pinned: true)} + + delegate :content, to: :project_detail, allow_nil: true + delegate :name, to: :license, prefix: true, allow_nil: true + + validate :validate_sensitive_string + + def self.all_visible(user_id=nil) + user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql + org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql + if user_id.present? + org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql + org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql + return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible + else + return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible + end + end + + def reset_cache_data + CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id) + if changes[:user_id].present? + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) + end + if changes[:project_language_id].present? + first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first) + last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id) + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) + end + if changes[:is_public].present? + if changes[:is_public][0] && !changes[:is_public][1] + CacheAsyncClearJob.perform_later('project_rank_service', self.id) + end + if !changes[:is_public][0] && changes[:is_public][1] + $redis_cache.srem("v2-project-rank-deleted", self.id) + end + end + end + + def decre_project_common + CacheAsyncClearJob.perform_later('project_common_service', self.id) + end + + def decre_forked_from_project_count + forked_project = self.forked_from_project + if forked_project.present? + forked_project.decrement(:forked_count, 1) + forked_project.save + end + end + + def incre_user_statistic + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id) + end + + def decre_user_statistic + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id) + end + + def incre_platform_statistic + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}) + end + + def decre_platform_statistic + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}) + end + + def is_full_public + owner = self.owner + if owner.is_a?(Organization) + return self.is_public && owner&.visibility == "common" + else + return self.is_public + end + end + + def reset_unmember_followed + if changes[:is_public].present? && changes[:is_public] == [true, false] + self.watchers.where.not(user_id: self.all_collaborators).destroy_all + end + end + + def set_invite_code + if self.invite_code.nil? + self.invite_code= self.generate_dcode('invite_code', 6) + end + end + + def set_recommend_and_is_pinned + self.recommend = self.recommend_index.zero? ? false : true + # 私有项目不允许设置精选和推荐 + unless self.is_public + self.recommend = false + self.recommend_index = 0 + self.is_pinned = false + end + end + + def self.search_project(search) + ransack(name_or_identifier_cont: search) + end + # 创建者 + def creator + User.find(user_id).full_name + end + + def members_user_infos + members.joins(:roles).where("roles.name in ('Manager', 'Developer', 'Reporter')").joins("left join users on members.user_id = users.id ").includes(:user).where("users.type = ?", "User") + # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") + # .pluck("users.id", "users.login","users.lastname", "users.firstname") + end + + def to_param + self.identifier.parameterize + end + + def get_issues_count(status_id) + if status_id.present? + self&.issues.issue_issue.select(:id, :status_id).where(status_id: status_id)&.pluck(:id).size + else + self&.issues.issue_issue.select(:id)&.pluck(:id).size + end + end + + def get_pull_requests_count(status_id) + if status_id.present? + self&.pull_requests.select(:id, :status).where(status: status_id)&.pluck(:id).size + else + self&.pull_requests.select(:id)&.pluck(:id).size + end + end + + #创建项目管理员 + def check_project_members + return if owner.is_a?(Organization) + unless members.present? && members.exists?(user_id: self.user_id) + member_params = { + user_id: self.user_id, + project_id: self.id + } + user_member = Member.new(member_params) + if user_member.save + role_id = Role.select(:id,:position).where(position: 3)&.first&.id + MemberRole.create!(member_id: user_member.id ,role_id: role_id) + end + end + end + + + def self.init_bluck_repository + Project.includes(:repository).find_each do |project| + puts project.id + next if project.owner.blank? + if project.repository.blank? + puts "########### start create repositoy #############" + Repository.create!(project_id: project.id, identifier: Project.generate_identifier, user_id: project&.owner&.id) + end + end + end + + def self.generate_identifier + str_arr = (("a".."z").to_a + ("A".."Z").to_a) + + str = str_arr.shuffle[0..8].join + while Repository.exists?(identifier: str) + str = str_arr.shuffle[0..8].join + end + str + end + + def self.list_user_projects(user_id) + projects = Project.is_private.select(:id,:user_id) + user_not_show_1 = projects.where("user_id != ?",user_id).pluck(:id).uniq + + user_show_2 = projects.joins(:members).where("members.user_id = ?", user_id).pluck(:id).uniq + Project.where.not(id: (user_not_show_1 - user_show_2).uniq) + end + + def members_count + members.select(:id).size + end + + + def can_visited? + is_public? || User.current.admin? || member?(User.current) + end + + def releases_size(current_user_id, type) + if current_user_id == self.user_id && type.to_s == "all" + self.repository.version_releases_count + else + self.repository.version_releases.releases_size + end + end + + def contributor_users + self.pull_requests.select(:user_id).pluck(:user_id).uniq.size + end + + def open_issues_count + issues_count - closed_issues_count + end + + def numerical_for_project_type + self.class.name.constantize.project_types["#{self.project_type}"] + end + + def watched_by? user + watchers.pluck(:user_id).include? user&.id + end + + def praised_by? user + praise_treads.pluck(:user_id).include? user&.id + end + + def get_premission user + return "Owner" if owner?(user) + return "Manager" if manager?(user) + return "Developer" if develper?(user) + return "Reporter" if reporter?(user) + + return "" + end + + def fork_project + Project.find_by(id: self.forked_from_project_id) + end + + def self.members_projects(member_user_id) + joins(:members).where(members: { user_id: member_user_id}) + end + + def self.find_with_namespace(namespace_path, identifier) + logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " + + user = Owner.find_by_login namespace_path + project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") + return nil if project.blank? + + [project, user] + end + + def ci_reactivate? + open_devops_count > 0 + end + + def ci_reactivate!(ci_repo) + ci_repo.update_column(:repo_active, 1) + update_column(:open_devops, true) + increment!(:open_devops_count) + end + + def self.sync_educoder_shixun(url, private_token, page, per_page) + SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) + end + + def self.update_common_projects_count! + ps = ProjectStatistic.first + ps.increment!(:common_projects_count) unless ps.blank? + end + + def self.update_mirror_projects_count! + ps = ProjectStatistic.first + ps.increment!(:mirror_projects_count) unless ps.blank? + end + + def set_updated_on(time) + return if time.blank? + update_column(:updated_on, time) + end + + def is_transfering + applied_transfer_project&.common? ? true : false + end + + def validate_sensitive_string + raise("项目名称包含敏感词汇,请重新输入") if name && !HarmoniousDictionary.clean?(name) + raise("项目描述包含敏感词汇,请重新输入") if description && !HarmoniousDictionary.clean?(description) + end +end From 9a17c4865f4188cd5d266caf3ea2d08d4e185532 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Wed, 1 Jun 2022 09:27:18 +0800 Subject: [PATCH 79/82] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=92=8C=E6=8F=8F=E8=BF=B0=E5=A2=9E=E5=8A=A0=E6=95=8F=E6=84=9F?= =?UTF-8?q?=E8=AF=8D=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/project.rb | 839 +++++++++++++++++++++--------------------- 1 file changed, 423 insertions(+), 416 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 2e47c000f..9c77685f7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,416 +1,423 @@ - -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) default(""), not null -# description :text(4294967295) -# homepage :string(255) default("") -# is_public :boolean default("1"), not null -# parent_id :integer -# created_on :datetime -# updated_on :datetime -# identifier :string(255) -# status :integer default("1"), not null -# lft :integer -# rgt :integer -# inherit_members :boolean default("0"), not null -# project_type :integer default("0") -# hidden_repo :boolean default("0"), not null -# attachmenttype :integer default("1") -# user_id :integer -# dts_test :integer default("0") -# enterprise_name :string(255) -# organization_id :integer -# project_new_type :integer -# gpid :integer -# forked_from_project_id :integer -# forked_count :integer default("0") -# publish_resource :integer default("0") -# visits :integer default("0") -# hot :integer default("0") -# invite_code :string(255) -# qrcode :string(255) -# qrcode_expiretime :integer default("0") -# script :text(65535) -# training_status :integer default("0") -# rep_identifier :string(255) -# project_category_id :integer -# project_language_id :integer -# license_id :integer -# ignore_id :integer -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# is_pinned :boolean default("0") -# recommend_index :integer default("0") -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_invite_code (invite_code) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_license_id (license_id) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_category_id (project_category_id) -# index_projects_on_project_language_id (project_language_id) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - - - - -class Project < ApplicationRecord - include Matchable - include Publicable - include Watchable - include ProjectOperable - include Dcodes - - # common:开源托管项目 - # mirror:普通镜像项目,没有定时同步功能 - # sync_mirror:同步镜像项目,有系统定时同步功能,且用户可手动同步操作 - # - enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } - - # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 - enum platform: { forge: 0, educoder: 1 } - - belongs_to :ignore, optional: true - belongs_to :license, optional: true - belongs_to :owner, class_name: 'Owner', foreign_key: :user_id, optional: true - belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects - belongs_to :project_category, optional: true , :counter_cache => true - belongs_to :project_language, optional: true , :counter_cache => true - belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id - has_many :project_trends, dependent: :destroy - has_many :watchers, as: :watchable, dependent: :destroy - has_many :fork_users, dependent: :destroy - has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy - has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id - has_one :project_educoder, dependent: :destroy - - has_one :project_score, dependent: :destroy - has_one :repository, dependent: :destroy - has_many :pull_requests, dependent: :destroy - has_many :issue_tags, -> { order("issue_tags.created_at DESC") }, dependent: :destroy - has_many :issues, dependent: :destroy - # has_many :user_grades, dependent: :destroy - has_many :attachments, as: :container, dependent: :destroy - has_one :project_score, dependent: :destroy - has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy - has_many :praise_treads, as: :praise_tread_object, dependent: :destroy - has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" - has_one :project_detail, dependent: :destroy - has_many :project_units, dependent: :destroy - has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy - has_many :pinned_projects, dependent: :destroy - has_many :has_pinned_users, through: :pinned_projects, source: :user - has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id - after_create :incre_user_statistic, :incre_platform_statistic - after_save :check_project_members - before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data - before_destroy :decre_project_common, :decre_forked_from_project_count - after_destroy :decre_user_statistic, :decre_platform_statistic - scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} - scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} - scope :recommend, -> { visible.project_statics_select.where(recommend: true) } - scope :pinned, -> {where(is_pinned: true)} - - delegate :content, to: :project_detail, allow_nil: true - delegate :name, to: :license, prefix: true, allow_nil: true - - def self.all_visible(user_id=nil) - user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql - org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql - if user_id.present? - org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql - org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql - return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible - else - return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible - end - end - - def reset_cache_data - CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id) - if changes[:user_id].present? - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) - end - if changes[:project_language_id].present? - first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first) - last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id) - CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id) - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) - end - if changes[:is_public].present? - if changes[:is_public][0] && !changes[:is_public][1] - CacheAsyncClearJob.perform_later('project_rank_service', self.id) - end - if !changes[:is_public][0] && changes[:is_public][1] - $redis_cache.srem("v2-project-rank-deleted", self.id) - end - end - end - - def decre_project_common - CacheAsyncClearJob.perform_later('project_common_service', self.id) - end - - def decre_forked_from_project_count - forked_project = self.forked_from_project - if forked_project.present? - forked_project.decrement(:forked_count, 1) - forked_project.save - end - end - - def incre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id) - end - - def decre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id) - end - - def incre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}) - end - - def decre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}) - end - - def is_full_public - owner = self.owner - if owner.is_a?(Organization) - return self.is_public && owner&.visibility == "common" - else - return self.is_public - end - end - - def reset_unmember_followed - if changes[:is_public].present? && changes[:is_public] == [true, false] - self.watchers.where.not(user_id: self.all_collaborators).destroy_all - end - end - - def set_invite_code - if self.invite_code.nil? - self.invite_code= self.generate_dcode('invite_code', 6) - end - end - - def set_recommend_and_is_pinned - self.recommend = self.recommend_index.zero? ? false : true - # 私有项目不允许设置精选和推荐 - unless self.is_public - self.recommend = false - self.recommend_index = 0 - self.is_pinned = false - end - end - - def self.search_project(search) - ransack(name_or_identifier_cont: search) - end - # 创建者 - def creator - User.find(user_id).full_name - end - - def members_user_infos - members.joins(:roles).where("roles.name in ('Manager', 'Developer', 'Reporter')").joins("left join users on members.user_id = users.id ").includes(:user).where("users.type = ?", "User") - # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") - # .pluck("users.id", "users.login","users.lastname", "users.firstname") - end - - def to_param - self.identifier.parameterize - end - - def get_issues_count(status_id) - if status_id.present? - self&.issues.issue_issue.select(:id, :status_id).where(status_id: status_id)&.pluck(:id).size - else - self&.issues.issue_issue.select(:id)&.pluck(:id).size - end - end - - def get_pull_requests_count(status_id) - if status_id.present? - self&.pull_requests.select(:id, :status).where(status: status_id)&.pluck(:id).size - else - self&.pull_requests.select(:id)&.pluck(:id).size - end - end - - #创建项目管理员 - def check_project_members - return if owner.is_a?(Organization) - unless members.present? && members.exists?(user_id: self.user_id) - member_params = { - user_id: self.user_id, - project_id: self.id - } - user_member = Member.new(member_params) - if user_member.save - role_id = Role.select(:id,:position).where(position: 3)&.first&.id - MemberRole.create!(member_id: user_member.id ,role_id: role_id) - end - end - end - - - def self.init_bluck_repository - Project.includes(:repository).find_each do |project| - puts project.id - next if project.owner.blank? - if project.repository.blank? - puts "########### start create repositoy #############" - Repository.create!(project_id: project.id, identifier: Project.generate_identifier, user_id: project&.owner&.id) - end - end - end - - def self.generate_identifier - str_arr = (("a".."z").to_a + ("A".."Z").to_a) - - str = str_arr.shuffle[0..8].join - while Repository.exists?(identifier: str) - str = str_arr.shuffle[0..8].join - end - str - end - - def self.list_user_projects(user_id) - projects = Project.is_private.select(:id,:user_id) - user_not_show_1 = projects.where("user_id != ?",user_id).pluck(:id).uniq - - user_show_2 = projects.joins(:members).where("members.user_id = ?", user_id).pluck(:id).uniq - Project.where.not(id: (user_not_show_1 - user_show_2).uniq) - end - - def members_count - members.select(:id).size - end - - - def can_visited? - is_public? || User.current.admin? || member?(User.current) - end - - def releases_size(current_user_id, type) - if current_user_id == self.user_id && type.to_s == "all" - self.repository.version_releases_count - else - self.repository.version_releases.releases_size - end - end - - def contributor_users - self.pull_requests.select(:user_id).pluck(:user_id).uniq.size - end - - def open_issues_count - issues_count - closed_issues_count - end - - def numerical_for_project_type - self.class.name.constantize.project_types["#{self.project_type}"] - end - - def watched_by? user - watchers.pluck(:user_id).include? user&.id - end - - def praised_by? user - praise_treads.pluck(:user_id).include? user&.id - end - - def get_premission user - return "Owner" if owner?(user) - return "Manager" if manager?(user) - return "Developer" if develper?(user) - return "Reporter" if reporter?(user) - - return "" - end - - def fork_project - Project.find_by(id: self.forked_from_project_id) - end - - def self.members_projects(member_user_id) - joins(:members).where(members: { user_id: member_user_id}) - end - - def self.find_with_namespace(namespace_path, identifier) - logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " - - user = Owner.find_by_login namespace_path - user = Owner.new(login: namespace_path) if user.nil? - project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") - return nil if project.blank? - - [project, user] - end - - def ci_reactivate? - open_devops_count > 0 - end - - def ci_reactivate!(ci_repo) - ci_repo.update_column(:repo_active, 1) - update_column(:open_devops, true) - increment!(:open_devops_count) - end - - def self.sync_educoder_shixun(url, private_token, page, per_page) - SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) - end - - def self.update_common_projects_count! - ps = ProjectStatistic.first - ps.increment!(:common_projects_count) unless ps.blank? - end - - def self.update_mirror_projects_count! - ps = ProjectStatistic.first - ps.increment!(:mirror_projects_count) unless ps.blank? - end - - def set_updated_on(time) - return if time.blank? - update_column(:updated_on, time) - end - - def is_transfering - applied_transfer_project&.common? ? true : false - end -end + +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# license_id :integer +# ignore_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# default_branch :string(255) default("master") +# website :string(255) +# lesson_url :string(255) +# is_pinned :boolean default("0") +# recommend_index :integer default("0") +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_invite_code (invite_code) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_license_id (license_id) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_category_id (project_category_id) +# index_projects_on_project_language_id (project_language_id) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + + + + +class Project < ApplicationRecord + include Matchable + include Publicable + include Watchable + include ProjectOperable + include Dcodes + + # common:开源托管项目 + # mirror:普通镜像项目,没有定时同步功能 + # sync_mirror:同步镜像项目,有系统定时同步功能,且用户可手动同步操作 + # + enum project_type: { sync_mirror: 2, mirror: 1, common: 0 } + + # forge: trustie平台项目, educoder: educoder平台项目, 默认为forge平台 + enum platform: { forge: 0, educoder: 1 } + + belongs_to :ignore, optional: true + belongs_to :license, optional: true + belongs_to :owner, class_name: 'Owner', foreign_key: :user_id, optional: true + belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects + belongs_to :project_category, optional: true , :counter_cache => true + belongs_to :project_language, optional: true , :counter_cache => true + belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id + has_many :project_trends, dependent: :destroy + has_many :watchers, as: :watchable, dependent: :destroy + has_many :fork_users, dependent: :destroy + has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy + has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id + has_one :project_educoder, dependent: :destroy + + has_one :project_score, dependent: :destroy + has_one :repository, dependent: :destroy + has_many :pull_requests, dependent: :destroy + has_many :issue_tags, -> { order("issue_tags.created_at DESC") }, dependent: :destroy + has_many :issues, dependent: :destroy + # has_many :user_grades, dependent: :destroy + has_many :attachments, as: :container, dependent: :destroy + has_one :project_score, dependent: :destroy + has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy + has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" + has_one :project_detail, dependent: :destroy + has_many :project_units, dependent: :destroy + has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy + has_many :pinned_projects, dependent: :destroy + has_many :has_pinned_users, through: :pinned_projects, source: :user + has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id + after_create :incre_user_statistic, :incre_platform_statistic + after_save :check_project_members + before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data + before_destroy :decre_project_common, :decre_forked_from_project_count + after_destroy :decre_user_statistic, :decre_platform_statistic + scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} + scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} + scope :recommend, -> { visible.project_statics_select.where(recommend: true) } + scope :pinned, -> {where(is_pinned: true)} + + delegate :content, to: :project_detail, allow_nil: true + delegate :name, to: :license, prefix: true, allow_nil: true + + validate :validate_sensitive_string + + def self.all_visible(user_id=nil) + user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql + org_public_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'common'})).to_sql + if user_id.present? + org_limit_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension).where(organization_extensions: {visibility: 'limited'})).to_sql + org_privacy_projects_sql = Project.joins(:owner).merge(Organization.joins(:organization_extension, :organization_users).where(organization_extensions: {visibility: 'privacy'}, organization_users: {user_id: user_id})).to_sql + return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } UNION #{ org_limit_projects_sql } UNION #{org_privacy_projects_sql} ) AS projects").visible + else + return Project.from("( #{ user_projects_sql } UNION #{ org_public_projects_sql } ) AS projects").visible + end + end + + def reset_cache_data + CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id) + if changes[:user_id].present? + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) + end + if changes[:project_language_id].present? + first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first) + last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id) + CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id) + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) + end + if changes[:is_public].present? + if changes[:is_public][0] && !changes[:is_public][1] + CacheAsyncClearJob.perform_later('project_rank_service', self.id) + end + if !changes[:is_public][0] && changes[:is_public][1] + $redis_cache.srem("v2-project-rank-deleted", self.id) + end + end + end + + def decre_project_common + CacheAsyncClearJob.perform_later('project_common_service', self.id) + end + + def decre_forked_from_project_count + forked_project = self.forked_from_project + if forked_project.present? + forked_project.decrement(:forked_count, 1) + forked_project.save + end + end + + def incre_user_statistic + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id) + end + + def decre_user_statistic + CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id) + end + + def incre_platform_statistic + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}) + end + + def decre_platform_statistic + CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}) + end + + def is_full_public + owner = self.owner + if owner.is_a?(Organization) + return self.is_public && owner&.visibility == "common" + else + return self.is_public + end + end + + def reset_unmember_followed + if changes[:is_public].present? && changes[:is_public] == [true, false] + self.watchers.where.not(user_id: self.all_collaborators).destroy_all + end + end + + def set_invite_code + if self.invite_code.nil? + self.invite_code= self.generate_dcode('invite_code', 6) + end + end + + def set_recommend_and_is_pinned + self.recommend = self.recommend_index.zero? ? false : true + # 私有项目不允许设置精选和推荐 + unless self.is_public + self.recommend = false + self.recommend_index = 0 + self.is_pinned = false + end + end + + def self.search_project(search) + ransack(name_or_identifier_cont: search) + end + # 创建者 + def creator + User.find(user_id).full_name + end + + def members_user_infos + members.joins(:roles).where("roles.name in ('Manager', 'Developer', 'Reporter')").joins("left join users on members.user_id = users.id ").includes(:user).where("users.type = ?", "User") + # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") + # .pluck("users.id", "users.login","users.lastname", "users.firstname") + end + + def to_param + self.identifier.parameterize + end + + def get_issues_count(status_id) + if status_id.present? + self&.issues.issue_issue.select(:id, :status_id).where(status_id: status_id)&.pluck(:id).size + else + self&.issues.issue_issue.select(:id)&.pluck(:id).size + end + end + + def get_pull_requests_count(status_id) + if status_id.present? + self&.pull_requests.select(:id, :status).where(status: status_id)&.pluck(:id).size + else + self&.pull_requests.select(:id)&.pluck(:id).size + end + end + + #创建项目管理员 + def check_project_members + return if owner.is_a?(Organization) + unless members.present? && members.exists?(user_id: self.user_id) + member_params = { + user_id: self.user_id, + project_id: self.id + } + user_member = Member.new(member_params) + if user_member.save + role_id = Role.select(:id,:position).where(position: 3)&.first&.id + MemberRole.create!(member_id: user_member.id ,role_id: role_id) + end + end + end + + + def self.init_bluck_repository + Project.includes(:repository).find_each do |project| + puts project.id + next if project.owner.blank? + if project.repository.blank? + puts "########### start create repositoy #############" + Repository.create!(project_id: project.id, identifier: Project.generate_identifier, user_id: project&.owner&.id) + end + end + end + + def self.generate_identifier + str_arr = (("a".."z").to_a + ("A".."Z").to_a) + + str = str_arr.shuffle[0..8].join + while Repository.exists?(identifier: str) + str = str_arr.shuffle[0..8].join + end + str + end + + def self.list_user_projects(user_id) + projects = Project.is_private.select(:id,:user_id) + user_not_show_1 = projects.where("user_id != ?",user_id).pluck(:id).uniq + + user_show_2 = projects.joins(:members).where("members.user_id = ?", user_id).pluck(:id).uniq + Project.where.not(id: (user_not_show_1 - user_show_2).uniq) + end + + def members_count + members.select(:id).size + end + + + def can_visited? + is_public? || User.current.admin? || member?(User.current) + end + + def releases_size(current_user_id, type) + if current_user_id == self.user_id && type.to_s == "all" + self.repository.version_releases_count + else + self.repository.version_releases.releases_size + end + end + + def contributor_users + self.pull_requests.select(:user_id).pluck(:user_id).uniq.size + end + + def open_issues_count + issues_count - closed_issues_count + end + + def numerical_for_project_type + self.class.name.constantize.project_types["#{self.project_type}"] + end + + def watched_by? user + watchers.pluck(:user_id).include? user&.id + end + + def praised_by? user + praise_treads.pluck(:user_id).include? user&.id + end + + def get_premission user + return "Owner" if owner?(user) + return "Manager" if manager?(user) + return "Developer" if develper?(user) + return "Reporter" if reporter?(user) + + return "" + end + + def fork_project + Project.find_by(id: self.forked_from_project_id) + end + + def self.members_projects(member_user_id) + joins(:members).where(members: { user_id: member_user_id}) + end + + def self.find_with_namespace(namespace_path, identifier) + logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " + + user = Owner.find_by_login namespace_path + user = Owner.new(login: namespace_path) if user.nil? + project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}") + return nil if project.blank? + + [project, user] + end + + def ci_reactivate? + open_devops_count > 0 + end + + def ci_reactivate!(ci_repo) + ci_repo.update_column(:repo_active, 1) + update_column(:open_devops, true) + increment!(:open_devops_count) + end + + def self.sync_educoder_shixun(url, private_token, page, per_page) + SyncEducoderShixunJob.perform_later(url, private_token, page, per_page) + end + + def self.update_common_projects_count! + ps = ProjectStatistic.first + ps.increment!(:common_projects_count) unless ps.blank? + end + + def self.update_mirror_projects_count! + ps = ProjectStatistic.first + ps.increment!(:mirror_projects_count) unless ps.blank? + end + + def set_updated_on(time) + return if time.blank? + update_column(:updated_on, time) + end + + def is_transfering + applied_transfer_project&.common? ? true : false + end + + def validate_sensitive_string + raise("项目名称包含敏感词汇,请重新输入") if name && !HarmoniousDictionary.clean?(name) + raise("项目描述包含敏感词汇,请重新输入") if description && !HarmoniousDictionary.clean?(description) + end +end From 877948b0cd515eb414891801e63f8cd934e77368 Mon Sep 17 00:00:00 2001 From: yystopf Date: Wed, 1 Jun 2022 10:00:57 +0800 Subject: [PATCH 80/82] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=A8=A1=E6=9D=BF=E5=90=8E=E5=8F=B0=E5=88=9B?= =?UTF-8?q?=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admins/message_templates_controller.rb | 20 +++++++++++++++++-- app/models/message_template.rb | 3 +-- .../admins/message_templates/_list.html.erb | 4 ++-- .../admins/message_templates/index.html.erb | 8 +++++++- app/views/admins/message_templates/new.js.erb | 2 ++ config/routes.rb | 2 +- 6 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 app/views/admins/message_templates/new.js.erb diff --git a/app/controllers/admins/message_templates_controller.rb b/app/controllers/admins/message_templates_controller.rb index 23c94e784..af77858e1 100644 --- a/app/controllers/admins/message_templates_controller.rb +++ b/app/controllers/admins/message_templates_controller.rb @@ -2,8 +2,24 @@ class Admins::MessageTemplatesController < Admins::BaseController before_action :get_template, only: [:edit, :update, :destroy] def index - message_templates = MessageTemplate.group(:type).count.keys - @message_templates = kaminari_array_paginate(message_templates) + message_templates = MessageTemplate.ransack(sys_notice_or_email_or_email_title_cont: params[:search]).result + @message_templates = kaminari_paginate(message_templates) + end + + def new + @message_template = MessageTemplate::CustomTip.new + end + + def create + @message_template = MessageTemplate::CustomTip.new(ignore_params) + + if @message_template.save! + redirect_to admins_message_templates_path + flash[:success] = "创建消息模板成功" + else + render :new + flash[:danger] = "创建消息模板失败" + end end def edit diff --git a/app/models/message_template.rb b/app/models/message_template.rb index f34200132..50de7d8ef 100644 --- a/app/models/message_template.rb +++ b/app/models/message_template.rb @@ -16,8 +16,7 @@ class MessageTemplate < ApplicationRecord PLATFORM = 'GitLink' def self.build_init_data - MessageTemplate::IssueAssignerExpire.destroy_all - MessageTemplate::IssueCreatorExpire.destroy_all + MessageTemplate.where.not(type: 'MessageTemplate::CustomTip').destroy_all self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '{nickname} 关注了你', notification_url: '{baseurl}/{login}') email_html = File.read("#{email_template_html_dir}/issue_assigned.html") self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 {nickname2}/{repository} 指派给你一个疑修:{title}', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 指派给你一个疑修") diff --git a/app/views/admins/message_templates/_list.html.erb b/app/views/admins/message_templates/_list.html.erb index 4082735f5..dae87d576 100644 --- a/app/views/admins/message_templates/_list.html.erb +++ b/app/views/admins/message_templates/_list.html.erb @@ -11,8 +11,8 @@ <% if message_templates.present? %> - <% message_templates.each_with_index do |message_template_type, index| %> - <% message_template = message_template_type.constantize.last%> + <% message_templates.each_with_index do |message_template, index| %> + <%# message_template = message_template_type.constantize.last%> <%= list_index_no((params[:page] || 1).to_i, index) %> <%= message_template.simple_type %> diff --git a/app/views/admins/message_templates/index.html.erb b/app/views/admins/message_templates/index.html.erb index 54d273332..e14de841b 100644 --- a/app/views/admins/message_templates/index.html.erb +++ b/app/views/admins/message_templates/index.html.erb @@ -3,7 +3,13 @@ <% end %>
    - <%= link_to "初始化数据", init_data_admins_message_templates_path, class: "btn btn-primary pull-right", "data-disabled-with":"...初始化数据" %> + <%= form_tag(admins_message_templates_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> + <%= text_field_tag(:search, params[:search], class: 'form-control col-12 col-md-2 mr-3', placeholder: '名称检索') %> + <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> + + <% end %> + <%= link_to "初始化数据", init_data_admins_message_templates_path, class: "btn btn-primary mr-3 pull-right", "data-disabled-with":"...初始化数据" %> + <%= link_to "新增", new_admins_message_template_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
    <%= render partial: 'admins/message_templates/list', locals: { message_templates: @message_templates } %> diff --git a/app/views/admins/message_templates/new.js.erb b/app/views/admins/message_templates/new.js.erb new file mode 100644 index 000000000..e75d923d1 --- /dev/null +++ b/app/views/admins/message_templates/new.js.erb @@ -0,0 +1,2 @@ +$("#admins-message-templates-content").html("<%= j render partial: 'admins/message_templates/form', locals:{type: 'create'} %>") +createMDEditor('message-template-email-editor', { height: 500, placeholder: '请输入邮件模版' }); diff --git a/config/routes.rb b/config/routes.rb index 4d1e3adeb..b585f0775 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -694,7 +694,7 @@ Rails.application.routes.draw do get :history end end - resources :message_templates, only: [:index, :edit, :update] do + resources :message_templates, only: [:index, :new, :create, :edit, :update] do collection do get :init_data end From 7290cd64956258dc77c2ec07f02619c7e0ceb700 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Wed, 1 Jun 2022 15:23:05 +0800 Subject: [PATCH 81/82] =?UTF-8?q?=E9=80=9A=E7=9F=A5=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=94=A8=E6=88=B7=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E6=97=B6=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/send_template_message_job.rb | 9 ++++++++- app/models/message_template/custom_tip.rb | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb index bec3f7b08..557d4d0fa 100644 --- a/app/jobs/send_template_message_job.rb +++ b/app/jobs/send_template_message_job.rb @@ -8,13 +8,20 @@ class SendTemplateMessageJob < ApplicationJob receivers_id, template_id, props = args[0], args[1], args[2] template = MessageTemplate.find_by_id(template_id) return unless template.present? - receivers = User.where(id: receivers_id) + receivers = User.where(id: receivers_id).or(User.where(mail: receivers_id)) + not_exists_receivers = receivers_id - receivers.pluck(:id) - receivers.pluck(:mail) receivers_string, content, notification_url = MessageTemplate::CustomTip.get_message_content(receivers, template, props) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {receivers_id: receivers_id, template_id: template_id, props: props}) receivers.find_each do |receiver| receivers_email_string, email_title, email_content = MessageTemplate::CustomTip.get_email_message_content(receiver, template, props) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) end + not_exists_receivers.each do |mail| + valid_email_regex = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/i + next unless (mail =~ valid_email_regex) + email_title, email_content = MessageTemplate::CustomTip.get_email_content(template, props) + Notice::Write::EmailCreateService.call(mail, email_title, email_content) + end when 'FollowTip' watcher_id = args[0] watcher = Watcher.find_by_id(watcher_id) diff --git a/app/models/message_template/custom_tip.rb b/app/models/message_template/custom_tip.rb index 6c5a3345d..f1e3096f8 100644 --- a/app/models/message_template/custom_tip.rb +++ b/app/models/message_template/custom_tip.rb @@ -48,4 +48,21 @@ class MessageTemplate::CustomTip < MessageTemplate Rails.logger.info("MessageTemplate::CustomTip.get_email_message_content [ERROR] #{e}") return '', '', '' end + + def self.get_email_content(template, props = {}) + return '', '', '' if template.blank? + title = template.email_title + content = template.email + props.each do |k, v| + title.gsub!("{#{k}}", v) + content.gsub!("{#{k}}", v) + end + title.gsub!('{platform}', PLATFORM) + content.gsub!('{platform}', PLATFORM) + + return title, content + rescue => e + Rails.logger.info("MessageTemplate::CustomTip.get_email_content [ERROR] #{e}") + return '', '' + end end \ No newline at end of file From 15a0b85ae66ee5113b64743f098656bc6ac42e30 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Wed, 1 Jun 2022 16:11:18 +0800 Subject: [PATCH 82/82] =?UTF-8?q?=E9=80=9A=E7=9F=A5=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=94=A8=E6=88=B7=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E6=97=B6=E5=8F=91=E9=80=81base=5Furl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/message_template/custom_tip.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/message_template/custom_tip.rb b/app/models/message_template/custom_tip.rb index f1e3096f8..fdb68155c 100644 --- a/app/models/message_template/custom_tip.rb +++ b/app/models/message_template/custom_tip.rb @@ -25,6 +25,7 @@ class MessageTemplate::CustomTip < MessageTemplate content.gsub!("{#{k}}", v) notification_url.gsub!("{#{k}}", v) end + notification_url.gsub!('{baseurl}', base_url) return receivers_string(receivers), content, notification_url rescue => e Rails.logger.info("MessageTemplate::CustomTip.get_message_content [ERROR] #{e}") @@ -42,6 +43,7 @@ class MessageTemplate::CustomTip < MessageTemplate content.gsub!('{receiver}', receiver&.real_name) title.gsub!('{platform}', PLATFORM) content.gsub!('{platform}', PLATFORM) + content.gsub!('{baseurl}', base_url) return receiver&.mail, title, content rescue => e