diff --git a/.gitignore b/.gitignore index 4a01bd5ec..d0186c4a3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ # Ignore lock config file *.log - +.env # mac *.DS_Store .bashrc @@ -84,4 +84,5 @@ redis_data/ dump.rdb .tags* ceshi_user.xlsx -public/trace_task_results \ No newline at end of file +public/trace_task_results +public/项目活跃度排行.xls \ No newline at end of file diff --git a/Gemfile b/Gemfile index c0df6c3b6..edaae8a75 100644 --- a/Gemfile +++ b/Gemfile @@ -141,4 +141,4 @@ gem 'doorkeeper' gem 'doorkeeper-jwt' -gem 'gitea-client', '~> 1.4.2' +gem 'gitea-client', '~> 1.4.6' diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index ea26f1bd5..14d59af77 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -201,12 +201,12 @@ class AccountsController < ApplicationController 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? + 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}分钟后重新登录或找回密码") + normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") else normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") end @@ -222,6 +222,7 @@ class AccountsController < ApplicationController end def change_password + return render_error("两次输入的密码不一致") if params[:password].to_s != params[:new_password_repeat].to_s @user = User.find_by(login: params[:login]) return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691 return render_error("未找到相关用户!") if @user.blank? diff --git a/app/controllers/admins/dashboards_controller.rb b/app/controllers/admins/dashboards_controller.rb index 2c01c8bd0..6940ed1cf 100644 --- a/app/controllers/admins/dashboards_controller.rb +++ b/app/controllers/admins/dashboards_controller.rb @@ -21,13 +21,75 @@ class Admins::DashboardsController < Admins::BaseController weekly_project_ids = (CommitLog.where(created_at: current_week).pluck(:project_id).uniq + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq month_project_ids = (CommitLog.where(created_at: current_month).pluck(:project_id).uniq + Issue.where(created_on: current_month).pluck(:project_id).uniq).uniq @day_active_project_count = Project.where(updated_on: today).or(Project.where(id: day_project_ids)).count - @weekly_active_project_count = Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count - @month_active_project_count = Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count - + @weekly_active_project_count = Rails.cache.fetch("dashboardscontroller:weekly_active_project_count", expires_in: 10.minutes) do + Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count + end + @month_active_project_count = Rails.cache.fetch("dashboardscontroller:month_active_project_count", expires_in: 1.hours) do + Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count + end # 新增项目数 - @day_new_project_count = Project.where(created_on: today).count - @weekly_new_project_count = Project.where(created_on: current_week).count - @month_new_project_count = Project.where(created_on: current_month).count + @day_new_project_count = Rails.cache.fetch("dashboardscontroller:day_new_project_count", expires_in: 10.minutes) do + Project.where(created_on: today).count + end + @weekly_new_project_count = Rails.cache.fetch("dashboardscontroller:weekly_new_project_count", expires_in: 10.minutes) do + Project.where(created_on: current_week).count + end + @month_new_project_count = Rails.cache.fetch("dashboardscontroller:month_new_project_count", expires_in: 1.hours) do + Project.where(created_on: current_month).count + end + + + # 总的平台用户数 + # 总的平台项目数 + # 总的平台组织数 + # 总的平台Issue数、评论数、PR数、Commit数 + @user_count = Rails.cache.fetch("dashboardscontroller:platform:user_count", expires_in: 1.days) do + User.count + end + @project_count = Rails.cache.fetch("dashboardscontroller:platform:project_count", expires_in: 1.days) do + Project.count + end + @organization_count = Rails.cache.fetch("dashboardscontroller:platform:organization_count", expires_in: 1.days) do + Organization.count + end + @issue_count = Rails.cache.fetch("dashboardscontroller:platform:issue_count", expires_in: 1.days) do + Issue.count + end + @comment_count = Rails.cache.fetch("dashboardscontroller:platform:comment_count", expires_in: 1.days) do + Journal.count + end + @pr_count = Rails.cache.fetch("dashboardscontroller:platform:pr_count", expires_in: 1.days) do + PullRequest.count + end + @commit_count = Rails.cache.fetch("dashboardscontroller:platform:commit_count", expires_in: 1.days) do + CommitLog.count + end + + @subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数"] + @subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload"] + @subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count] + + + tongji_service = Baidu::TongjiService.new + @access_token = tongji_service.access_token + Rails.logger.info "baidu_tongji_auth access_token ===== #{@access_token}" + # @overview_data = tongji_service.api_overview + last_date = DailyPlatformStatistic.order(:date).last + start_date = last_date.date + end_date = Time.now + if @access_token.present? + @overview_data = Rails.cache.fetch("dashboardscontroller:baidu_tongji:overview_data", expires_in: 10.minutes) do + tongji_service.source_from_batch_add(start_date, end_date) + @overview_data = tongji_service.overview_batch_add(start_date, end_date) + @overview_data + end + end + + @current_week_statistic = DailyPlatformStatistic.where(date: current_week) + @pre_week_statistic = DailyPlatformStatistic.where(date: pre_week) + + + end def month_active_user @@ -42,6 +104,19 @@ class Admins::DashboardsController < Admins::BaseController render_ok(data: data) end + def baidu_tongji + tongji_service = Baidu::TongjiService.new + redirect_to tongji_service.code_url + end + + def baidu_tongji_auth + if params[:code].present? + tongji_service = Baidu::TongjiService.new + tongji_service.get_access_token(params[:code]) + end + redirect_to "/admins/" + end + def evaluate names = [] data = [] @@ -63,8 +138,12 @@ class Admins::DashboardsController < Admins::BaseController Time.now.beginning_of_day..Time.now.end_of_day end - def current_week + def pre_7_days 7.days.ago.end_of_day..Time.now.end_of_day + end + + def current_week + Time.now.beginning_of_week..Time.now.end_of_day end def current_month @@ -72,6 +151,7 @@ class Admins::DashboardsController < Admins::BaseController end def pre_week - 14.days.ago.end_of_day..7.days.ago.end_of_day + # 14.days.ago.end_of_day..7.days.ago.end_of_day + Time.now.prev_week..Time.now.prev_week.end_of_week end end \ No newline at end of file diff --git a/app/controllers/admins/identity_verifications_controller.rb b/app/controllers/admins/identity_verifications_controller.rb index 51d5e423c..1db1a9883 100644 --- a/app/controllers/admins/identity_verifications_controller.rb +++ b/app/controllers/admins/identity_verifications_controller.rb @@ -14,12 +14,14 @@ class Admins::IdentityVerificationsController < Admins::BaseController end def update - if @identity_verification.update(update_params) + if update_params[:state] == "已拒绝" && update_params[:description].blank? + flash[:danger] = '拒绝理由不能为空' + render 'edit' + else + UserAction.create(action_id: @identity_verification.id, action_type: "UpdateIdentityVerifications", user_id: current_user.id, :ip => request.remote_ip, data_bank: @identity_verification.attributes.to_json) + @identity_verification.update(update_params) redirect_to admins_identity_verifications_path flash[:success] = "更新成功" - else - redirect_to admins_identity_verifications_path - flash[:danger] = "更新失败" end end diff --git a/app/controllers/admins/issues_rank_controller.rb b/app/controllers/admins/issues_rank_controller.rb new file mode 100644 index 000000000..79450fbfb --- /dev/null +++ b/app/controllers/admins/issues_rank_controller.rb @@ -0,0 +1,29 @@ +class Admins::IssuesRankController < Admins::BaseController + + def index + @statistics = DailyProjectStatistic.where('date >= ? AND date <= ?', begin_date, end_date) + @statistics = @statistics.group(:project_id).joins(:project).select("project_id, + sum(issues) as issues, + sum(closed_issues) as closed_issues, + projects.issues_count as issues_count") + @statistics = @statistics.order("#{sort_by} #{sort_direction}").limit(50) + end + + private + def begin_date + params.fetch(:begin_date, (Date.yesterday-7.days).to_s) + end + + def end_date + params.fetch(:end_date, Date.yesterday.to_s) + end + + def sort_by + DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "issues")) ? params.fetch(:sort_by, "issues") : "issues" + end + + def sort_direction + %w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc" + end + +end \ No newline at end of file diff --git a/app/controllers/admins/projects_rank_controller.rb b/app/controllers/admins/projects_rank_controller.rb index c4f968da4..8db0961b7 100644 --- a/app/controllers/admins/projects_rank_controller.rb +++ b/app/controllers/admins/projects_rank_controller.rb @@ -1,16 +1,55 @@ class Admins::ProjectsRankController < Admins::BaseController - def index - @rank_date = rank_date - deleted_data = $redis_cache.smembers("v2-project-rank-deleted") - $redis_cache.zrem("v2-project-rank-#{rank_date}", deleted_data) unless deleted_data.blank? - @date_rank = $redis_cache.zrevrange("v2-project-rank-#{rank_date}", 0, -1, withscores: true) + @statistics = DailyProjectStatistic.where("date >= ? AND date <= ?", begin_date, end_date) + @statistics = @statistics.group(:project_id).select("project_id, + sum(score) as score, + sum(visits) as visits, + sum(watchers) as watchers, + sum(praises) as praises, + sum(forks) as forks, + sum(issues) as issues, + sum(pullrequests) as pullrequests, + sum(commits) as commits").includes(:project) + @statistics = @statistics.order("#{sort_by} #{sort_direction}") + export_excel(@statistics.limit(50)) end private - def rank_date - params.fetch(:date, Date.today.to_s) + def begin_date + params.fetch(:begin_date, (Date.yesterday-7.days).to_s) + end + + def end_date + params.fetch(:end_date, Date.yesterday.to_s) + end + + def sort_by + DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "score")) ? params.fetch(:sort_by, "score") : "score" + end + + def sort_direction + %w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc" + end + + def export_excel(data) + book = Spreadsheet::Workbook.new + sheet = book.create_worksheet :name => "项目活跃度排行" + sheet.row(0).concat %w(排名 项目全称 项目地址 得分 访问数 关注数 点赞数 fork数 疑修数 合并请求数 提交数) + data.each_with_index do |d, index| + sheet[index+1,0] = index+1 + sheet[index+1,1] = "#{d&.project&.owner&.real_name}/#{d&.project&.name}" + sheet[index+1,2] = "#{Rails.application.config_for(:configuration)['platform_url']}/#{d&.project&.owner&.login}/#{d&.project&.identifier}" + sheet[index+1,3] = d.score + sheet[index+1,4] = d.visits + sheet[index+1,5] = d.watchers + sheet[index+1,6] = d.praises + sheet[index+1,7] = d.forks + sheet[index+1,8] = d.issues + sheet[index+1,9] = d.pullrequests + sheet[index+1,10] = d.commits + end + book.write "#{Rails.root}/public/项目活跃度排行.xls" end end \ No newline at end of file diff --git a/app/controllers/admins/site_pages_controller.rb b/app/controllers/admins/site_pages_controller.rb index f0e05e71d..306c91627 100644 --- a/app/controllers/admins/site_pages_controller.rb +++ b/app/controllers/admins/site_pages_controller.rb @@ -29,8 +29,12 @@ class Admins::SitePagesController < Admins::BaseController end def update - @site_page.update(update_params) - flash[:success] = '保存成功' + if update_params[:state] == "false" && update_params[:state_description].blank? + flash[:danger] = '关闭站点理由不能为空' + else + @site_page.update(update_params) + flash[:success] = '保存成功' + end render 'edit' end diff --git a/app/controllers/admins/system_notifications_controller.rb b/app/controllers/admins/system_notifications_controller.rb index e2081f1a2..33f3f20f1 100644 --- a/app/controllers/admins/system_notifications_controller.rb +++ b/app/controllers/admins/system_notifications_controller.rb @@ -25,7 +25,7 @@ class Admins::SystemNotificationsController < Admins::BaseController @notification = SystemNotification.new(notification_params) if @notification.save redirect_to admins_system_notifications_path - flash[:success] = '系统消息创建成功' + flash[:success] = '系统公告创建成功' else redirect_to admins_system_notifications_path flash[:danger] = @notification.errors.full_messages.join(",") @@ -37,7 +37,7 @@ class Admins::SystemNotificationsController < Admins::BaseController if @notification.update_attributes(notification_params) format.html do redirect_to admins_system_notifications_path - flash[:success] = '系统消息更新成功' + flash[:success] = '系统公告更新成功' end format.js {render_ok} else @@ -53,10 +53,10 @@ class Admins::SystemNotificationsController < Admins::BaseController def destroy if @notification.destroy redirect_to admins_system_notifications_path - flash[:success] = "系统消息删除成功" + flash[:success] = "系统公告删除成功" else redirect_to admins_system_notifications_path - flash[:danger] = "系统消息删除失败" + flash[:danger] = "系统公告删除失败" end end diff --git a/app/controllers/api/v1/issues/issue_priorities_controller.rb b/app/controllers/api/v1/issues/issue_priorities_controller.rb index 319994a28..2df1288f7 100644 --- a/app/controllers/api/v1/issues/issue_priorities_controller.rb +++ b/app/controllers/api/v1/issues/issue_priorities_controller.rb @@ -7,4 +7,12 @@ class Api::V1::Issues::IssuePrioritiesController < Api::V1::BaseController @priorities = @priorities.ransack(name_cont: params[:keyword]).result if params[:keyword] @priorities = kaminary_select_paginate(@priorities) end + + def pm_index + @priorities = IssuePriority.order(position: :asc) + @priorities = @priorities.ransack(name_cont: params[:keyword]).result if params[:keyword] + @priorities = kaminary_select_paginate(@priorities) + render "index" + end + end \ No newline at end of file diff --git a/app/controllers/api/v1/issues/issue_tags_controller.rb b/app/controllers/api/v1/issues/issue_tags_controller.rb index fe2ecceab..39534c313 100644 --- a/app/controllers/api/v1/issues/issue_tags_controller.rb +++ b/app/controllers/api/v1/issues/issue_tags_controller.rb @@ -1,5 +1,5 @@ class Api::V1::Issues::IssueTagsController < Api::V1::BaseController - before_action :require_login, except: [:index] + before_action :require_login, except: [:index, :pm_index] before_action :require_public_and_member_above, only: [:index] before_action :require_operate_above, only: [:create, :update, :destroy] @@ -7,12 +7,17 @@ class Api::V1::Issues::IssueTagsController < Api::V1::BaseController @issue_tags = @project.issue_tags.reorder("#{sort_by} #{sort_direction}") @issue_tags = @issue_tags.ransack(name_cont: params[:keyword]).result if params[:keyword].present? if params[:only_name] - @issue_tags = kaminary_select_paginate(@issue_tags.select(:id, :name, :color)) + @issue_tags = kaminary_select_paginate(@issue_tags.select(:id, :name, :color)) else @issue_tags = kaminari_paginate(@issue_tags.includes(:project, :user, :issue_issues, :pull_request_issues)) end end + def pm_index + @issue_tags = IssueTag.init_mp_issues_tags + render_ok(@issue_tags) + end + def create @issue_tag = @project.issue_tags.new(issue_tag_params) if @issue_tag.save! diff --git a/app/controllers/api/v1/issues/statues_controller.rb b/app/controllers/api/v1/issues/statues_controller.rb index 5a7fbc338..c6495ee26 100644 --- a/app/controllers/api/v1/issues/statues_controller.rb +++ b/app/controllers/api/v1/issues/statues_controller.rb @@ -8,4 +8,11 @@ class Api::V1::Issues::StatuesController < Api::V1::BaseController @statues = @statues.ransack(name_cont: params[:keyword]).result if params[:keyword].present? @statues = kaminary_select_paginate(@statues) end + + def pm_index + @statues = IssueStatus.order("position asc") + @statues = @statues.ransack(name_cont: params[:keyword]).result if params[:keyword].present? + @statues = kaminary_select_paginate(@statues) + render "index" + end end \ No newline at end of file diff --git a/app/controllers/api/v1/issues_controller.rb b/app/controllers/api/v1/issues_controller.rb index ebba95e2b..1737b7c97 100644 --- a/app/controllers/api/v1/issues_controller.rb +++ b/app/controllers/api/v1/issues_controller.rb @@ -1,6 +1,6 @@ class Api::V1::IssuesController < Api::V1::BaseController - before_action :require_login, except: [:index, :show] - before_action :require_public_and_member_above, only: [:index, :show, :create, :update, :destroy] + before_action :require_login, except: [:index, :show, :show_by_id] + before_action :require_public_and_member_above, only: [:index, :show, :show_by_id, :create, :update, :destroy] before_action :require_operate_above, only: [:batch_update, :batch_destroy] def index @@ -22,6 +22,12 @@ class Api::V1::IssuesController < Api::V1::BaseController before_action :load_issue, only: [:show, :update, :destroy] before_action :check_issue_operate_permission, only: [:update, :destroy] + before_action :load_issue_by_id, only: [:show_by_id] + + def show_by_id + @issue.associate_attachment_container + @user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user) + end def show @issue.associate_attachment_container @@ -70,6 +76,13 @@ class Api::V1::IssuesController < Api::V1::BaseController end end + def load_issue_by_id + @issue = Issue.find_by_id(params[:index]) + if @issue.blank? + render_not_found("疑修不存在!") + end + end + def load_issues return render_error("请输入正确的ID数组!") unless params[:ids].is_a?(Array) params[:ids].each do |id| diff --git a/app/controllers/api/v1/projects/actions/actions_controller.rb b/app/controllers/api/v1/projects/actions/actions_controller.rb new file mode 100644 index 000000000..3825b4685 --- /dev/null +++ b/app/controllers/api/v1/projects/actions/actions_controller.rb @@ -0,0 +1,31 @@ +class Api::V1::Projects::Actions::ActionsController < Api::V1::Projects::Actions::BaseController + + def index + begin + gitea_result = $gitea_hat_client.get_repos_actions_by_owner_repo(@project&.owner&.login, @project&.identifier) + @data = gitea_result[:data]["Workflows"] + rescue + @data = [] + end + end + + def disable + return render_error("请输入正确的流水线文件!") if params[:workflow].blank? + gitea_result = $gitea_hat_client.post_repos_actions_disable(@project&.owner&.login, @project&.identifier, {query: {workflow: params[:workflow]}}) rescue nil + if gitea_result + render_ok + else + render_error("禁用流水线失败") + end + end + + def enable + return render_error("请输入正确的流水线文件!") if params[:workflow].blank? + gitea_result = $gitea_hat_client.post_repos_actions_enable(@project&.owner&.login, @project&.identifier, {query: {workflow: params[:workflow]}}) rescue nil + if gitea_result + render_ok + else + render_error("取消禁用流水线失败") + end + end +end \ No newline at end of file diff --git a/app/controllers/api/v1/projects/actions/base_controller.rb b/app/controllers/api/v1/projects/actions/base_controller.rb new file mode 100644 index 000000000..d76b446ad --- /dev/null +++ b/app/controllers/api/v1/projects/actions/base_controller.rb @@ -0,0 +1,4 @@ +class Api::V1::Projects::Actions::BaseController < Api::V1::BaseController + before_action :require_public_and_member_above + +end \ No newline at end of file diff --git a/app/controllers/api/v1/projects/actions/runs_controller.rb b/app/controllers/api/v1/projects/actions/runs_controller.rb new file mode 100644 index 000000000..05918dbe2 --- /dev/null +++ b/app/controllers/api/v1/projects/actions/runs_controller.rb @@ -0,0 +1,12 @@ +class Api::V1::Projects::Actions::RunsController < Api::V1::Projects::Actions::BaseController + + def index + @result_object = Api::V1::Projects::Actions::Runs::ListService.call(@project, {workflow: params[:workflow], page: page, limit: limit}, current_user&.gitea_token) + puts @result_object + end + + def job_show + @result_object = Api::V1::Projects::Actions::Runs::JobShowService.call(@project, params[:run_id], params[:job], params[:log_cursors], current_user&.gitea_token) + end + +end \ No newline at end of file diff --git a/app/controllers/api/v1/projects/branches_controller.rb b/app/controllers/api/v1/projects/branches_controller.rb index 40f44fea5..89ebb5825 100644 --- a/app/controllers/api/v1/projects/branches_controller.rb +++ b/app/controllers/api/v1/projects/branches_controller.rb @@ -2,14 +2,14 @@ class Api::V1::Projects::BranchesController < Api::V1::BaseController before_action :require_public_and_member_above, only: [:index, :all] def index - @result_object = Api::V1::Projects::Branches::ListService.call(@project, {name: params[:keyword], page: page, limit: limit}, current_user&.gitea_token) + @result_object = Api::V1::Projects::Branches::ListService.call(@project, {name: params[:keyword], state: params[:state], page: page, limit: limit}, current_user&.gitea_token) end def all @result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token) end - before_action :require_operate_above, only: [:create, :destroy] + before_action :require_operate_above, only: [:create, :destroy, :restore] def create @result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token) @@ -33,6 +33,15 @@ class Api::V1::Projects::BranchesController < Api::V1::BaseController end end + def restore + @result_object = Api::V1::Projects::Branches::RestoreService.call(@project, params[:branch_id], params[:branch_name], current_user&.gitea_token) + if @result_object + return render_ok + else + return render_error('恢复分支失败!') + end + end + before_action :require_manager_above, only: [:update_default_branch] def update_default_branch diff --git a/app/controllers/api/v1/projects/commits_controller.rb b/app/controllers/api/v1/projects/commits_controller.rb index a1545ae6f..21987f4fb 100644 --- a/app/controllers/api/v1/projects/commits_controller.rb +++ b/app/controllers/api/v1/projects/commits_controller.rb @@ -1,5 +1,5 @@ class Api::V1::Projects::CommitsController < Api::V1::BaseController - before_action :require_public_and_member_above, only: [:index, :diff] + before_action :require_public_and_member_above, only: [:index, :diff, :recent] def index @result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token) @@ -9,4 +9,8 @@ class Api::V1::Projects::CommitsController < Api::V1::BaseController def diff @result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token) end + + def recent + @result_object = Api::V1::Projects::Commits::RecentService.call(@project, {keyword: params[:keyword], page: page, limit: limit}, current_user&.gitea_token) + end end \ No newline at end of file diff --git a/app/controllers/api/v1/projects/tags_controller.rb b/app/controllers/api/v1/projects/tags_controller.rb index b87d48429..44fdd9ba0 100644 --- a/app/controllers/api/v1/projects/tags_controller.rb +++ b/app/controllers/api/v1/projects/tags_controller.rb @@ -1,10 +1,13 @@ class Api::V1::Projects::TagsController < Api::V1::BaseController - before_action :require_public_and_member_above, only: [:index] + before_action :require_public_and_member_above, only: [:index, :show] def index @release_tags = @repository.version_releases.pluck(:tag_name) @result_object = Api::V1::Projects::Tags::ListService.call(@project, {page: page, limit: limit}, current_user&.gitea_token) - puts @result_object + end + + def show + @result_object = Api::V1::Projects::Tags::GetService.call(@project, params[:name], current_user&.gitea_token) end before_action :require_operate_above, only: [:destroy] diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8981a0995..0c134a3bd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -715,7 +715,7 @@ class ApplicationController < ActionController::Base end def find_user_with_id - @user = User.find_by_id params[:user_id] + @user = User.find_by(type: 'User', id: params[:user_id]) # render_not_found("未找到’#{params[:login]}’相关的用户") unless @user render_error("未找到相关的用户") unless @user end diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index e5362710c..ecc4760b5 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -94,6 +94,7 @@ class AttachmentsController < ApplicationController @attachment.author_id = current_user.id @attachment.disk_directory = month_folder @attachment.cloud_url = remote_path + @attachment.uuid = SecureRandom.uuid @attachment.save! else logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" @@ -143,12 +144,14 @@ class AttachmentsController < ApplicationController private def find_file + tip_exception(404, "您访问的页面不存在或已被删除") if params[:id].blank? @file = if params[:type] == 'history' AttachmentHistory.find params[:id] else - Attachment.find params[:id] + Attachment.where_id_or_uuid(params[:id]).first end + tip_exception(404, "您访问的页面不存在或已被删除") if @file.blank? end def delete_file(file_path) @@ -218,7 +221,7 @@ class AttachmentsController < ApplicationController def attachment_candown unless current_user.admin? || current_user.business? candown = true - if @file.container + if @file.container && @file.uuid.nil? if @file.container.is_a?(Issue) project = @file.container.project candown = project.is_public || (current_user.logged? && project.member?(current_user)) diff --git a/app/controllers/bind_users_controller.rb b/app/controllers/bind_users_controller.rb index f5ed33809..b8c25dd7d 100644 --- a/app/controllers/bind_users_controller.rb +++ b/app/controllers/bind_users_controller.rb @@ -8,7 +8,7 @@ class BindUsersController < ApplicationController bind_user = User.try_to_login(params[:username], params[:password]) tip_exception '用户名或者密码错误' if bind_user.blank? tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s) - tip_exception '参数错误' unless ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s) + tip_exception '参数错误' unless ["qq", "wechat", "gitee", "github", "educoder", "acge"].include?(params[:type].to_s) tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s) "OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: bind_user, uid: session[:unionid]) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index cb7beb402..84219b89b 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -139,7 +139,7 @@ class IssuesController < ApplicationController SendTemplateMessageJob.perform_later('ProjectIssue', current_user.id, @issue&.id) if Site.has_notice_menu? if params[:attachment_ids].present? params[:attachment_ids].each do |id| - attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) + attachment = Attachment.where_id_or_uuid(id).select(:id, :container_id, :container_type)&.first unless attachment.blank? attachment.container = @issue attachment.author_id = current_user.id @@ -232,7 +232,7 @@ class IssuesController < ApplicationController if issue_files.present? change_files = true issue_files.each do |id| - attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) + attachment = Attachment.where_id_or_uuid(id).select(:id, :container_id, :container_type)&.first unless attachment.blank? attachment.container = @issue attachment.author_id = current_user.id diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index 8f7857567..6b9abd5c6 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -35,7 +35,7 @@ class JournalsController < ApplicationController if journal.save if params[:attachment_ids].present? params[:attachment_ids].each do |id| - attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) + attachment = Attachment.where_id_or_uuid(id).select(:id, :container_id, :container_type)&.first unless attachment.blank? attachment.container = journal attachment.author_id = current_user.id diff --git a/app/controllers/oauth/acge_controller.rb b/app/controllers/oauth/acge_controller.rb new file mode 100644 index 000000000..efa5cca08 --- /dev/null +++ b/app/controllers/oauth/acge_controller.rb @@ -0,0 +1,67 @@ +class Oauth::AcgeController < Oauth::BaseController + include RegisterHelper + + def create + begin + uid = params['uid'].to_s.strip + tip_exception("uid不能为空") if uid.blank? + redirect_uri = params['redirect_uri'].to_s.strip + tip_exception("redirect_uri不能为空") if redirect_uri.blank? + email = params['email'].to_s.strip + tip_exception("email不能为空") if email.blank? + phone = params['phone'].to_s.strip + tip_exception("phone不能为空") if phone.blank? + name = params['name'].to_s.strip + tip_exception("name不能为空") if name.blank? + + open_user = OpenUsers::Acge.find_by(uid: uid) + if open_user.present? && open_user.user.present? + successful_authentication(open_user.user) + redirect_to redirect_uri + return + else + if current_user.blank? || !current_user.logged? + session[:unionid] = uid + user = User.find_by(mail: email) || User.find_by(phone: phone) + if user.present? + OpenUsers::Acge.create!(user: user, uid: uid) + successful_authentication(user) + redirect_to redirect_uri + + return + else + username = uid[0..7] + password = SecureRandom.hex(4) + reg_result = autologin_register(username, email, password, 'acge', phone, name) + existing_rows = CSV.read("public/操作系统大赛用户信息.csv") + new_row = [username, email, password, phone, name] + existing_rows << new_row + CSV.open("public/操作系统大赛用户信息.csv", 'wb') do |csv| + existing_rows.each { |row| csv << row } + end + if reg_result[:message].blank? + open_user = OpenUsers::Acge.create!(user_id: reg_result[:user][:id], uid: uid) + successful_authentication(open_user.user) + redirect_to redirect_uri + + return + else + render_error(reg_result[:message]) + end + end + else + OpenUsers::Acge.create!(user: current_user, uid: uid) + successful_authentication(current_user) + redirect_to redirect_uri + + return + end + end + + Rails.logger.info("[OAuth2] session[:unionid] -> #{session[:unionid]}") + # redirect_to "/bindlogin/acge?redirect_uri=#{redirect_uri}" + rescue Exception => ex + render_error(ex.message) + end + end +end \ No newline at end of file diff --git a/app/controllers/oauth2_controller.rb b/app/controllers/oauth2_controller.rb index f1ac19a2a..9be575a1f 100644 --- a/app/controllers/oauth2_controller.rb +++ b/app/controllers/oauth2_controller.rb @@ -20,12 +20,12 @@ class Oauth2Controller < ActionController::Base return @error = {msg: '违反平台使用规范,账号已被锁定', id: 'login'} if @user.locked? login_control = LimitForbidControl::UserLogin.new(@user) - return @error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} if login_control.forbid? + return @error = {msg: "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} if login_control.forbid? password_ok = @user.check_password?(params[:password].to_s) unless password_ok if login_control.remain_times-1 == 0 - @error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} + @error = {msg: "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} else @error = {msg: "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会", id: 'account'} end diff --git a/app/controllers/organizations/organization_users_controller.rb b/app/controllers/organizations/organization_users_controller.rb index d9035dc14..171e9dcae 100644 --- a/app/controllers/organizations/organization_users_controller.rb +++ b/app/controllers/organizations/organization_users_controller.rb @@ -4,17 +4,31 @@ class Organizations::OrganizationUsersController < Organizations::BaseController before_action :check_user_can_edit_org, only: [:destroy] def index - @organization_users = @organization.organization_users.includes(:user) + # @organization_users = @organization.organization_users.includes(:user) + # if params[:search].present? + # search = params[:search].to_s.downcase + # user_condition_users = User.like(search).to_sql + # team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql + # users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users") + # + # @organization_users = @organization_users.where(user_id: users).distinct + # end + # + # @organization_users = kaminari_paginate(@organization_users) + + organization_user_ids = @organization.organization_users.pluck(:user_id).uniq + project_member_user_ids = @organization.projects.joins(:members).pluck("members.user_id").uniq + ids = organization_user_ids + project_member_user_ids + users = User.where(id: ids).reorder(Arel.sql("FIELD(users.id,#{ids.join(',')})")) if params[:search].present? search = params[:search].to_s.downcase user_condition_users = User.like(search).to_sql team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql - users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users") + user_ids = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users").pluck(:id) - @organization_users = @organization_users.where(user_id: users).distinct + users = users.where(id: user_ids) end - - @organization_users = kaminari_paginate(@organization_users) + @users = kaminari_paginate(users) end def pm_check_user diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 446e4bb31..a4e369c1f 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -4,9 +4,9 @@ class ProjectsController < ApplicationController include ProjectsHelper include Acceleratorable - before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend banner_recommend about menu_list verify_auth_token] + before_action :require_login, except: %i[index branches branches_slice group_type_list simple show mp_show fork_users praise_users watch_users recommend banner_recommend about menu_list verify_auth_token] before_action :require_profile_completed, only: [:create, :migrate,:page_migrate,:verify_auth_token] - before_action :load_repository, except: %i[index group_type_list migrate page_migrate create recommend banner_recommend verify_auth_token] + before_action :load_repository, except: %i[index mp_show group_type_list migrate page_migrate create recommend banner_recommend verify_auth_token] before_action :authorizate_user_can_edit_project!, only: %i[update] before_action :project_public?, only: %i[fork_users praise_users watch_users] before_action :request_limit, only: %i[index] @@ -193,13 +193,19 @@ class ProjectsController < ApplicationController default_branch: @project.default_branch } Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params) + elsif project_params.has_key?("has_actions") + gitea_params = { + has_actions: project_params[:has_actions] + } + Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params) else validate_params = project_params.slice(:name, :description, :project_category_id, :project_language_id, :private, :identifier) Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier, project_name: @project.name)).validate! - private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false + private = params[:private].nil? ? !@project.is_public : params[:private] + private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : private new_project_params = project_params.except(:private).merge(is_public: !private) @project.update_attributes!(new_project_params) @@ -232,6 +238,15 @@ class ProjectsController < ApplicationController def show end + def mp_show + @project = Project.joins(:owner).find params[:project_id] + data={ + owner:@project.owner.try(:login), + identifier:@project.identifier + } + render_ok(data:data) + end + def destroy if current_user.admin? || @project.manager?(current_user) ActiveRecord::Base.transaction do @@ -338,7 +353,7 @@ class ProjectsController < ApplicationController def project_params params.permit(:user_id, :name, :description, :repository_name, :website, :lesson_url, :default_branch, :identifier, - :project_category_id, :project_language_id, :license_id, :ignore_id, :private, + :project_category_id, :project_language_id, :license_id, :ignore_id, :private, :has_actions, :blockchain, :blockchain_token_all, :blockchain_init_token, :pr_view_admin) end diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb index 2487b068c..c3787c002 100644 --- a/app/controllers/pull_requests_controller.rb +++ b/app/controllers/pull_requests_controller.rb @@ -203,6 +203,7 @@ class PullRequestsController < ApplicationController def pr_merge return render_forbidden("你没有权限操作.") unless @project.operator?(current_user) + return normal_status(-1, "该分支存在冲突,无法自动合并.") unless @pull_request.conflict_files.blank? if params[:do].blank? normal_status(-1, "请选择合并方式") diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index e26559f74..c8e4380e0 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -66,6 +66,8 @@ class RepositoriesController < ApplicationController @entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" + @repo_detail = $gitea_client.get_repos_by_owner_repo(@owner.login, @project.identifier) + return render_not_found if @entries.blank? && !@repo_detail["empty"] end end diff --git a/app/controllers/site_pages_controller.rb b/app/controllers/site_pages_controller.rb index 903e037db..085f1b027 100644 --- a/app/controllers/site_pages_controller.rb +++ b/app/controllers/site_pages_controller.rb @@ -17,23 +17,31 @@ class SitePagesController < ApplicationController end def create - return normal_status(-1, "你还未开通Page服务,无法进行部署") unless current_user.website_permission - return normal_status(-1, "你已使用了 #{params[:identifier]} 作为page标识") if Page.exists?(identifier: params[:identifier], user: current_user) - return normal_status(-1, "该仓库已开通Page服务") if Page.exists?(project: @project) + return normal_status(-1, '你还未开通Page服务,无法进行部署') unless current_user.website_permission + return normal_status(-1, '你已开通Page服务') if Page.exists?(user: current_user) + return normal_status(-1, '该仓库已开通Page服务') if Page.exists?(project: @project) @page = Page.new(create_params) @page.user = current_user @page.project = @project @page.save end + def update + return normal_status(-1, '你还未开通Page服务') unless current_user.website_permission + return normal_status(-1, '你还未开通Page站点') unless Page.exists?(user: current_user) + @page = Page.find_by(user: current_user) + @page.update(language_frame: params[:language_frame]) + render_ok + end + def build - return normal_status(-1, "你还未开通Page服务,无法进行部署") unless current_user.website_permission - return normal_status(-1, "该仓库还未开通Page服务,无法进行部署") unless Page.exists?(project: @project) + return normal_status(-1, '你还未开通Page服务,无法进行部署') unless current_user.website_permission + return normal_status(-1, '该仓库还未开通Page服务,无法进行部署') unless Page.exists?(project: @project) @page = Page.find params[:id] return normal_status(-1, @page.state_description) unless @page.state response_str = @page.deploy_page(params[:branch]) - data = JSON.parse(response_str)["result"] || data = JSON.parse(response_str)["error"] - if data.to_s.include?("部署成功") + data = JSON.parse(response_str)['result'] || (data = JSON.parse(response_str)['error']) + if data.to_s.include?('部署成功') @page.update(last_build_at: Time.now, build_state: true, last_build_info: data) else @page.update(build_state:false, last_build_info: data) @@ -42,22 +50,22 @@ class SitePagesController < ApplicationController end def softbot_build - branch = params[:ref].split("/").last + branch = params[:ref].split('/').last user = User.find_by_login params[:repository][:owner][:login] - return normal_status(-1, "你还未开通Page服务,无法进行部署") unless user.website_permission + return normal_status(-1, '你还未开通Page服务,无法进行部署') unless user.website_permission project = Project.where(identifier: params[:repository][:name],user_id: user.id) - return normal_status(-1, "你没有权限操作") if project.owner?(user) - return normal_status(-1, "该仓库还未开通Page服务,无法进行部署") if Page.exists?(user: user, project: project) + return normal_status(-1, '你没有权限操作') if project.owner?(user) + return normal_status(-1, '该仓库还未开通Page服务,无法进行部署') if Page.exists?(user: user, project: project) @page = Page.find_by(user: user, project: project) response_str = @page.deploy_page(branch) - data = JSON.parse(response_str)["result"] + data = JSON.parse(response_str)['result'] if data.nil? - data = JSON.parse(response_str)["error"] + data = JSON.parse(response_str)['error'] end - if data.include?("部署成功") + if data.include?('部署成功') @page.update(last_build_at: Time.now, build_state: true, last_build_info: data) else @page.update(build_state:false, last_build_info: data) @@ -85,7 +93,7 @@ class SitePagesController < ApplicationController end def theme_params - params[:language_frame] || "hugo" + params[:language_frame] || 'hugo' end def create_params diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 34d617f19..d7608ec3d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -22,7 +22,7 @@ class UsersController < ApplicationController end def list - scope = User.active.recent.like(params[:search]).includes(:user_extension) + scope = User.active.like(params[:search]).includes(:user_extension).order(nickname: :desc, last_login_on: :desc) @total_count = scope.size @users = paginate(scope) end diff --git a/app/controllers/version_releases_controller.rb b/app/controllers/version_releases_controller.rb index 76a214d0f..ed608873e 100644 --- a/app/controllers/version_releases_controller.rb +++ b/app/controllers/version_releases_controller.rb @@ -152,11 +152,12 @@ class VersionReleasesController < ApplicationController def create_attachments(attachment_ids, target) attachment_ids.each do |id| - attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) + attachment = Attachment.where_id_or_uuid(id).select(:id, :container_id, :container_type)&.first unless attachment.blank? attachment.container = target attachment.author_id = current_user.id attachment.description = "" + attachment.uuid = SecureRandom.uuid attachment.save end end diff --git a/app/forms/organizations/create_form.rb b/app/forms/organizations/create_form.rb index 2163f477e..1f40350b3 100644 --- a/app/forms/organizations/create_form.rb +++ b/app/forms/organizations/create_form.rb @@ -1,12 +1,12 @@ class Organizations::CreateForm < BaseForm - NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 + NAME_REGEX = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*$/ #只含有数字、字母、下划线不能以下划线开头和结尾 attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname, :original_name validates :name, :nickname, :visibility, presence: true validates :name, :nickname, length: { maximum: 100 } validates :location, length: { maximum: 50 } validates :description, length: { maximum: 200 } - validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } + validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符" } validate do check_name(name) unless name.blank? || name == original_name diff --git a/app/forms/projects/create_form.rb b/app/forms/projects/create_form.rb index c133175c2..8ef7befac 100644 --- a/app/forms/projects/create_form.rb +++ b/app/forms/projects/create_form.rb @@ -28,6 +28,10 @@ class Projects::CreateForm < BaseForm raise "ignore_id值无效." if ignore_id && Ignore.find_by(id: ignore_id).blank? end + def check_auto_init + raise "auto_init值无效." if ignore_id && license_id && !auto_init + end + def check_owner @project_owner = Owner.find_by(id: user_id) raise "user_id值无效." if user_id && @project_owner.blank? diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 936452470..5d5582428 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -299,7 +299,7 @@ module ApplicationHelper end def download_url attachment,options={} - attachment_path(attachment,options) + attachment&.uuid.present? ? attachment_path(attachment.uuid,options) : attachment_path(attachment,options) end # 耗时:天、小时、分、秒 diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index f364c11ff..dac637764 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -132,6 +132,8 @@ module RepositoriesHelper src_regex_3 = /src= (.*?) / src_regex_4 = /src =(.*?) / src_regex_5 = /src =(.*?) / + href_regex = /href=\"(.*?)\"/ + href_regex_1 = /href=\'(.*?)\'/ ss_c = content.to_s.scan(s_regex_c) ss = content.to_s.scan(s_regex) ss_1 = content.to_s.scan(s_regex_1) @@ -142,7 +144,9 @@ module RepositoriesHelper ss_src_3 = content.to_s.scan(src_regex_3) ss_src_4 = content.to_s.scan(src_regex_4) ss_src_5 = content.to_s.scan(src_regex_5) - total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_2: ss_2, ss_src: ss_src, ss_src_1: ss_src_1, ss_src_2: ss_src_2, ss_src_3: ss_src_3, ss_src_4: ss_src_4, ss_src_5: ss_src_5} + ss_href = content.to_s.scan(href_regex) + ss_href_1 = content.to_s.scan(href_regex_1) + total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_2: ss_2, ss_src: ss_src, ss_src_1: ss_src_1, ss_src_2: ss_src_2, ss_src_3: ss_src_3, ss_src_4: ss_src_4, ss_src_5: ss_src_5, ss_href: ss_href, ss_href_1: ss_href_1} # total_sources.uniq! total_sources.except(:ss, :ss_c).each do |k, sources| sources.each do |s| @@ -173,13 +177,17 @@ module RepositoriesHelper content = content.gsub("src=#{s[0]}", "src=\'#{s_content}\'") when 'ss_2' content = content.gsub(/]:#{s[0]}/, "]: #{s_content.to_s.gsub(" ","").gsub("\r", "")}") - else + when 'ss_href' + content = content.gsub("href=\"#{s[0]}\"", "href=\"#{s_content}\"") + when 'ss_href_1' + content = content.gsub("href=\'#{s[0]}\'", "href=\'#{s_content}\'") + else content = content.gsub("(#{s[0]})", "(#{s_content})") end 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] + s_content = s_content.split("#{Rails.root}")[1] case k.to_s when 'ss_src' content = content.gsub("src=\"#{s[0]}\"", "src=\"/#{s_content}\"") @@ -187,7 +195,11 @@ module RepositoriesHelper content = content.gsub("src=\'#{s[0]}\'", "src=\'/#{s_content}\'") when 'ss_2' content = content.gsub(/]:#{s[0]}/, "]: /#{s_content.to_s.gsub(" ","").gsub("\r", "")}") - else + when 'ss_href' + content = content.gsub("href=\"#{s[0]}\"", "href=\"#{s_content}\"") + when 'ss_href_1' + content = content.gsub("href=\'#{s[0]}\'", "href=\'#{s_content}\'") + else content = content.gsub("(#{s[0]})", "(/#{s_content})") end end diff --git a/app/interactors/gitea/delete_file_interactor.rb b/app/interactors/gitea/delete_file_interactor.rb index 03ddf4230..f94b8a205 100644 --- a/app/interactors/gitea/delete_file_interactor.rb +++ b/app/interactors/gitea/delete_file_interactor.rb @@ -45,6 +45,7 @@ module Gitea else Rails.logger.error("Gitea::Repository::Entries::DeleteService error[#{response.status}]======#{response.body}") @error = "删除失败,请确认该分支是否是保护分支。" + @error = "删除失败,参数sha不匹配。" if response.body.to_s.include?("sha does not match") end end diff --git a/app/jobs/daily_platform_statistics_job.rb b/app/jobs/daily_platform_statistics_job.rb new file mode 100644 index 000000000..5610f304b --- /dev/null +++ b/app/jobs/daily_platform_statistics_job.rb @@ -0,0 +1,44 @@ +# 按天获取百度统计数据,pv,访问,ip和来源分类占比 +# 其他统计:前一周用户留存率 +class DailyPlatformStatisticsJob < ApplicationJob + queue_as :default + + def perform(*args) + Rails.logger.info("*********开始统计*********") + + tongji_service = Baidu::TongjiService.new + access_token = tongji_service.access_token + Rails.logger.info "job baidu_tongji_auth access_token ===== #{access_token}" + ActiveJob::Base.logger.info "job baidu_tongji_auth access_token ===== #{access_token}" + # 从最后一个记录日期开始,如果遗漏日期数据可以补充数据 + last_date = DailyPlatformStatistic.order(:date).last + start_date = last_date.date + end_date = Time.now + if access_token.present? + tongji_service.overview_batch_add(start_date, end_date) + + # 本周访问来源占比,每天记录一次,如果遗漏日期数据可以补充数据 + tongji_service.source_from_batch_add(start_date, end_date) + end + # 周用户留存率 + pre_week_user_ids = User.where(created_on: pre_week).pluck(:id).uniq + weekly_keep_user_count = User.where(id: pre_week_user_ids).where(last_login_on: current_week).count + weekly_keep_rate = format("%.2f", pre_week_user_ids.size > 0 ? weekly_keep_user_count.to_f / pre_week_user_ids.size : 0) + + job_date = 1.days.ago + daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: job_date) + daily_statistic.weekly_keep_rate = weekly_keep_rate + daily_statistic.save + end + + private + + def current_week + Time.now.beginning_of_week..Time.now.end_of_day + end + + def pre_week + # 7.days.ago.beginning_of_week..7.days.ago.beginning_of_week.end_of_week + Time.now.prev_week..Time.now.prev_week.end_of_week + end +end diff --git a/app/jobs/daily_project_statistics_job.rb b/app/jobs/daily_project_statistics_job.rb new file mode 100644 index 000000000..3672d1924 --- /dev/null +++ b/app/jobs/daily_project_statistics_job.rb @@ -0,0 +1,35 @@ +class DailyProjectStatisticsJob < ApplicationJob + queue_as :cache + + def perform + date = (Date.today - 1.days).to_s + daily_data_keys = $redis_cache.keys("v2-project-statistic:*-#{date}") + daily_data_keys.each do |key| + result = $redis_cache.hgetall(key) + project_id = key.gsub('v2-project-statistic:', '').gsub("-#{date}", '') + next unless Project.find_by_id(project_id).present? + visits = result["visits"].to_i + watchers = result["watchers"].to_i + praises = result["praises"].to_i + forks = result["forks"].to_i + issues = result["issues"].to_i + closed_issues = result["closed_issues"].to_i + pullrequests = result["pullrequests"].to_i + commits = result["commits"].to_i + score = visits *1 + watchers *5 + praises * 5 + forks * 10 + issues *5 + pullrequests * 10 + commits * 5 + DailyProjectStatistic.create!( + project_id: project_id, + date: date, + score: score , + visits: visits, + watchers: watchers, + praises: praises, + forks: forks, + issues: issues, + closed_issues: closed_issues, + pullrequests: pullrequests, + commits: commits + ) + end + end +end \ No newline at end of file diff --git a/app/jobs/delay_expired_issue_and_milestone_job.rb b/app/jobs/delay_expired_issue_and_milestone_job.rb new file mode 100644 index 000000000..4bba7aaf1 --- /dev/null +++ b/app/jobs/delay_expired_issue_and_milestone_job.rb @@ -0,0 +1,16 @@ +class DelayExpiredIssueAndMilestoneJob < ApplicationJob + queue_as :message + + def perform + Issue.where(due_date: Date.today + 1.days).find_each do |issue| + SendTemplateMessageJob.perform_later('IssueExpire', issue.id) if Site.has_notice_menu? + end + Version.where(effective_date: Date.today + 1.days).find_each do |version| + SendTemplateMessageJob.perform_later('ProjectMilestoneEarlyExpired', version.id) if Site.has_notice_menu? + end + Version.where(effective_date: Date.today - 1.days).find_each do |version| + SendTemplateMessageJob.perform_later('ProjectMilestoneExpired', version.id) if Site.has_notice_menu? + end + end + +end \ No newline at end of file diff --git a/app/jobs/delay_expired_issue_job.rb b/app/jobs/delay_expired_issue_job.rb deleted file mode 100644 index ed390e15b..000000000 --- a/app/jobs/delay_expired_issue_job.rb +++ /dev/null @@ -1,10 +0,0 @@ -class DelayExpiredIssueJob < ApplicationJob - queue_as :message - - def perform - Issue.where(due_date: Date.today + 1.days).find_each do |issue| - SendTemplateMessageJob.perform_later('IssueExpire', issue.id) if Site.has_notice_menu? - end - end - -end \ No newline at end of file diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb index 1df1d8c7d..1b309fe35 100644 --- a/app/jobs/send_template_message_job.rb +++ b/app/jobs/send_template_message_job.rb @@ -221,6 +221,20 @@ class SendTemplateMessageJob < ApplicationJob receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestone.get_email_message_content(receiver, operator, milestone) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) end + when 'ProjectMilestoneExpired' + milestone_id = args[0] + milestone = Version.find_by_id(milestone_id) + return unless milestone.present? && milestone&.project.present? + receivers = User.where(id: milestone.user_id) + receivers_string, content, notification_url = MessageTemplate::ProjectMilestoneExpired.get_message_content(receivers, milestone) + Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id, operator_id: operator_id}) + when 'ProjectMilestoneEarlyExpired' + milestone_id = args[0] + milestone = Version.find_by_id(milestone_id) + return unless milestone.present? && milestone&.project.present? + receivers = User.where(id: milestone.user_id) + receivers_string, content, notification_url = MessageTemplate::ProjectMilestoneEarlyExpired.get_message_content(receivers, milestone) + Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id, operator_id: operator_id}) when 'ProjectPraised' operator_id, project_id = args[0], args[1] operator = User.find_by_id(operator_id) diff --git a/app/models/attachment.rb b/app/models/attachment.rb index f79aca153..9fd858bf3 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -28,6 +28,7 @@ # delay_publish :boolean default("0") # memo_image :boolean default("0") # extra_type :integer default("0") +# uuid :string(255) # # Indexes # @@ -42,6 +43,7 @@ + class Attachment < ApplicationRecord include BaseModel include Publicable @@ -68,6 +70,7 @@ class Attachment < ApplicationRecord scope :simple_columns, -> { select(:id, :filename, :filesize, :created_on, :cloud_url, :author_id, :content_type, :container_type, :container_id) } scope :search_by_container, -> (ids) {where(container_id: ids)} scope :unified_setting, -> {where("unified_setting = ? ", 1)} + scope :where_id_or_uuid, -> (id) { (Float(id) rescue nil).present? ? where(id: id) : where(uuid: id) } validates_length_of :description, maximum: 100, message: "不能超过100个字符" @@ -97,6 +100,11 @@ class Attachment < ApplicationRecord downloads end + def generate_uuid + self.uuid = uuid || SecureRandom.uuid + save! + end + def quotes_count quotes.nil? ? 0 : quotes end diff --git a/app/models/concerns/project_operable.rb b/app/models/concerns/project_operable.rb index 9a5efd129..34386aae2 100644 --- a/app/models/concerns/project_operable.rb +++ b/app/models/concerns/project_operable.rb @@ -21,68 +21,69 @@ module ProjectOperable end def add_member!(user_id, role_name='Developer') - if self.owner.is_a?(Organization) - case role_name - when 'Manager' - # 构建相应的团队 - team = self.owner.teams.admin.take - if team.nil? - team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) - gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil - team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? - end - - # 设置项目在团队中的访问权限 - team_project = TeamProject.build(self.user_id, team.id, self.id) - tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil - - # 新增对应的团队成员 - team_user = TeamUser.build(self.user_id, user_id, team.id) - $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 - - # 确保组织成员中有该用户 - OrganizationUser.build(self.user_id, user_id) - when 'Developer' - # 构建相应的团队 - team = self.owner.teams.write.take - if team.nil? - team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) - gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil - team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? - end - - # 设置项目在团队中的访问权限 - team_project = TeamProject.build(self.user_id, team.id, self.id) - tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil - - # 新增对应的团队成员 - team_user = TeamUser.build(self.user_id, user_id, team.id) - $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 - - # 确保组织成员中有该用户 - OrganizationUser.build(self.user_id, user_id) - when 'Reporter' - # 构建相应的团队 - team = self.owner.teams.read.take - if team.nil? - team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) - gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil - team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? - end - - # 设置项目在团队中的访问权限 - team_project = TeamProject.build(self.user_id, team.id, self.id) - tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil - - # 新增对应的团队成员 - team_user = TeamUser.build(self.user_id, user_id, team.id) - $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 - - # 确保组织成员中有该用户 - OrganizationUser.build(self.user_id, user_id) - end - end - member = members.create!(user_id: user_id, team_user_id: team_user&.id) + # if self.owner.is_a?(Organization) + # case role_name + # when 'Manager' + # # 构建相应的团队 + # team = self.owner.teams.admin.take + # if team.nil? + # team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) + # gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil + # team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? + # end + # + # # 设置项目在团队中的访问权限 + # team_project = TeamProject.build(self.user_id, team.id, self.id) + # tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil + # + # # 新增对应的团队成员 + # team_user = TeamUser.build(self.user_id, user_id, team.id) + # $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 + # + # # 确保组织成员中有该用户 + # OrganizationUser.build(self.user_id, user_id) + # when 'Developer' + # # 构建相应的团队 + # team = self.owner.teams.write.take + # if team.nil? + # team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) + # gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil + # team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? + # end + # + # # 设置项目在团队中的访问权限 + # team_project = TeamProject.build(self.user_id, team.id, self.id) + # tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil + # + # # 新增对应的团队成员 + # team_user = TeamUser.build(self.user_id, user_id, team.id) + # $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 + # + # # 确保组织成员中有该用户 + # OrganizationUser.build(self.user_id, user_id) + # when 'Reporter' + # # 构建相应的团队 + # team = self.owner.teams.read.take + # if team.nil? + # team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) + # gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil + # team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? + # end + # + # # 设置项目在团队中的访问权限 + # team_project = TeamProject.build(self.user_id, team.id, self.id) + # tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil + # + # # 新增对应的团队成员 + # team_user = TeamUser.build(self.user_id, user_id, team.id) + # $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 + # + # # 确保组织成员中有该用户 + # OrganizationUser.build(self.user_id, user_id) + # end + # end + # member = members.create!(user_id: user_id, team_user_id: team_user&.id) + member = members.create!(user_id: user_id) set_developer_role(member, role_name) end @@ -116,71 +117,71 @@ module ProjectOperable def change_member_role!(user_id, role) member = self.member(user_id) # 所有者为组织,并且该用户属于组织成员 - if self.owner.is_a?(Organization) && member.team_user.present? - case role&.name - when 'Manager' - # 构建相应的团队 - team = self.owner.teams.admin.take - if team.nil? - team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) - gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil - team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? - end - - # 设置项目在团队中的访问权限 - team_project = TeamProject.build(self.user_id, team.id, self.id) - tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil - - # 更改对应的团队成员 - team_user = member.team_user - $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 - $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 - team_user.update_attributes!({team_id: team.id}) unless team.team_users.exists?(user_id: member.user_id) - - # 确保组织成员中有该用户 - OrganizationUser.build(self.user_id, user_id) - when 'Developer' - # 构建相应的团队 - team = self.owner.teams.write.take - if team.nil? - team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) - gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil - team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? - end - # 设置项目在团队中的访问权限 - team_project = TeamProject.build(self.user_id, team.id, self.id) - $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil - - # 更改对应的团队成员 - team_user = member.team_user - $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 - $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 - team_user.update_attributes!({team_id: team.id}) unless team.team_users.exists?(user_id: member.user_id) - - OrganizationUser.build(self.user_id, user_id) - when 'Reporter' - # 构建相应的团队 - team = self.owner.teams.read.take - if team.nil? - team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) - gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil - team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? - end - - # 设置项目在团队中的访问权限 - team_project = TeamProject.build(self.user_id, team.id, self.id) - tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil - - # 更改对应的团队成员 - team_user = member.team_user - $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 - $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 - team_user.update_attributes!({team_id: team.id}) unless team.team_users.exists?(user_id: member.user_id) - - # 确保组织成员中有该用户 - OrganizationUser.build(self.user_id, user_id) - end - end + # if self.owner.is_a?(Organization) && member.team_user.present? + # case role&.name + # when 'Manager' + # # 构建相应的团队 + # team = self.owner.teams.admin.take + # if team.nil? + # team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) + # gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil + # team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? + # end + # + # # 设置项目在团队中的访问权限 + # team_project = TeamProject.build(self.user_id, team.id, self.id) + # tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil + # + # # 更改对应的团队成员 + # team_user = member.team_user + # $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 + # $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 + # team_user.update_attributes!({team_id: team.id}) unless team.team_users.exists?(user_id: member.user_id) + # + # # 确保组织成员中有该用户 + # OrganizationUser.build(self.user_id, user_id) + # when 'Developer' + # # 构建相应的团队 + # team = self.owner.teams.write.take + # if team.nil? + # team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) + # gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil + # team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? + # end + # # 设置项目在团队中的访问权限 + # team_project = TeamProject.build(self.user_id, team.id, self.id) + # $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil + # + # # 更改对应的团队成员 + # team_user = member.team_user + # $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 + # $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 + # team_user.update_attributes!({team_id: team.id}) unless team.team_users.exists?(user_id: member.user_id) + # + # OrganizationUser.build(self.user_id, user_id) + # when 'Reporter' + # # 构建相应的团队 + # team = self.owner.teams.read.take + # if team.nil? + # team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) + # gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil + # team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? + # end + # + # # 设置项目在团队中的访问权限 + # team_project = TeamProject.build(self.user_id, team.id, self.id) + # tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil + # + # # 更改对应的团队成员 + # team_user = member.team_user + # $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 + # $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 + # team_user.update_attributes!({team_id: team.id}) unless team.team_users.exists?(user_id: member.user_id) + # + # # 确保组织成员中有该用户 + # OrganizationUser.build(self.user_id, user_id) + # end + # end member.member_roles.last.update_attributes!(role: role) end diff --git a/app/models/daily_platform_statistic.rb b/app/models/daily_platform_statistic.rb new file mode 100644 index 000000000..a904d9b1e --- /dev/null +++ b/app/models/daily_platform_statistic.rb @@ -0,0 +1,24 @@ +# == Schema Information +# +# Table name: daily_platform_statistics +# +# id :integer not null, primary key +# date :date +# pv :integer default("0") +# visitor :integer default("0") +# ip :integer default("0") +# weekly_keep_rate :float(24) default("0") +# source_through :float(24) default("0") +# source_link :float(24) default("0") +# source_search :float(24) default("0") +# source_custom :float(24) default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_daily_platform_statistics_on_date (date) UNIQUE +# + +class DailyPlatformStatistic < ApplicationRecord +end diff --git a/app/models/daily_project_statistic.rb b/app/models/daily_project_statistic.rb new file mode 100644 index 000000000..ffe51bdb3 --- /dev/null +++ b/app/models/daily_project_statistic.rb @@ -0,0 +1,30 @@ +# == Schema Information +# +# Table name: daily_project_statistics +# +# id :integer not null, primary key +# project_id :integer +# date :date +# score :integer default("0") +# visits :integer default("0") +# watchers :integer default("0") +# praises :integer default("0") +# forks :integer default("0") +# issues :integer default("0") +# pullrequests :integer default("0") +# commits :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# closed_issues :integer default("0") +# +# Indexes +# +# index_daily_project_statistics_on_date (date) +# index_daily_project_statistics_on_project_id (project_id) +# + +class DailyProjectStatistic < ApplicationRecord + + + belongs_to :project +end diff --git a/app/models/identity_verification.rb b/app/models/identity_verification.rb index 6ea6e0547..7ba4c2140 100644 --- a/app/models/identity_verification.rb +++ b/app/models/identity_verification.rb @@ -6,10 +6,10 @@ # user_id :integer not null # number :string(255) not null # name :string(255) not null -# card_front :integer -# card_back :integer -# hold_card_front :integer -# hold_card_back :integer +# card_front :string(255) +# card_back :string(255) +# hold_card_front :string(255) +# hold_card_back :string(255) # state :integer default("0") # description :string(255) # created_at :datetime not null @@ -24,9 +24,9 @@ class IdentityVerification < ApplicationRecord belongs_to :user enum state: { "待审核": 0, "已通过": 1, "已拒绝": 2} after_create do - Attachment.where(id:[card_front,card_back,hold_card_front,hold_card_back]).update_all(is_public:0) + Attachment.where(uuid:[card_front,card_back,hold_card_front,hold_card_back]).update_all(is_public:0) end - + after_save do if state == "已通过" user.update(id_card_verify: true, website_permission: true) @@ -34,18 +34,18 @@ class IdentityVerification < ApplicationRecord end def card_front_attachment - Attachment.find_by_id card_front + Attachment.where_id_or_uuid(card_front).first end def card_back_attachment - Attachment.find_by_id card_back + Attachment.where_id_or_uuid(card_back).first end def hold_card_front_attachment - Attachment.find_by_id hold_card_front + Attachment.where_id_or_uuid(hold_card_front).first end def hold_card_back_attachment - Attachment.find_by_id hold_card_back + Attachment.where_id_or_uuid(hold_card_back).first end end diff --git a/app/models/issue.rb b/app/models/issue.rb index c6f1a74bb..86da50825 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -34,12 +34,19 @@ # ref_name :string(255) # branch_name :string(255) # blockchain_token_num :integer +# pm_project_id :integer +# pm_sprint_id :integer +# pm_issue_type :integer +# time_scale :decimal(10, 2) default("0.00") +# child_count :integer default("0") +# changer_id :integer # # Indexes # # index_issues_on_assigned_to_id (assigned_to_id) # index_issues_on_author_id (author_id) # index_issues_on_category_id (category_id) +# index_issues_on_changer_id (changer_id) # index_issues_on_created_on (created_on) # index_issues_on_fixed_version_id (fixed_version_id) # index_issues_on_priority_id (priority_id) @@ -92,31 +99,46 @@ class Issue < ApplicationRecord scope :closed, ->{where(status_id: 5)} scope :opened, ->{where.not(status_id: 5)} after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic - after_save :change_versions_count, :send_update_message_to_notice_system, :associate_attachment_container + after_save :incre_or_decre_closed_issues_count, :change_versions_count, :send_update_message_to_notice_system, :associate_attachment_container after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic + def is_issuely_issue? + self.issue_classify.nil? || self.issue_classify == 'issue' + end + + def incre_or_decre_closed_issues_count + if previous_changes[:status_id].present? && is_issuely_issue? + if previous_changes[:status_id][1] == 5 + CacheAsyncSetJob.perform_later("project_common_service", {closed_issues: 1}, self.project_id) + end + if previous_changes[:status_id][0] == 5 + CacheAsyncSetJob.perform_later("project_common_service", {closed_issues: -1}, self.project_id) + end + end + end + def incre_project_common - CacheAsyncSetJob.perform_later("project_common_service", {issues: 1}, self.project_id) + CacheAsyncSetJob.perform_later("project_common_service", {issues: 1}, self.project_id) if is_issuely_issue? end def decre_project_common - CacheAsyncSetJob.perform_later("project_common_service", {issues: -1}, self.project_id) + CacheAsyncSetJob.perform_later("project_common_service", {issues: -1}, self.project_id) if is_issuely_issue? end def incre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: 1}, self.author_id) + CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: 1}, self.author_id) if is_issuely_issue? end def decre_user_statistic - CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: -1}, self.author_id) + CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: -1}, self.author_id) if is_issuely_issue? end def incre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: 1}) + CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: 1}) if is_issuely_issue? end def decre_platform_statistic - CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: -1}) + CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: -1}) if is_issuely_issue? end def get_assign_user @@ -222,13 +244,23 @@ class Issue < ApplicationRecord # 关附件到功能 def associate_attachment_container + return if self.project_id == 0 att_ids = [] # 附件的格式为(/api/attachments/ + 附件id)的形式,提取出id进行附件属性关联,做附件访问权限控制 att_ids += self.description.to_s.scan(/\(\/api\/attachments\/.+\)/).map{|s|s.match(/\d+/)[0]} att_ids += self.description.to_s.scan(/\/api\/attachments\/.+\"/).map{|s|s.match(/\d+/)[0]} att_ids += self.description.to_s.scan(/\/api\/attachments\/\d+/).map{|s|s.match(/\d+/)[0]} if att_ids.present? - Attachment.where(id: att_ids).where("container_type IS NULL OR container_type = 'Issue'").update_all(container_id: self.project_id, container_type: "Project") + Attachment.where(id: att_ids).where("container_type IS NULL OR container_type = 'Issue'").update_all(container_id: self.project_id, container_type: 'Project') + end + + att_ids2 = [] + # uuid_regex= /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/ + # 附件的格式为(/api/attachments/ + uuid)的形式,提取出id进行附件属性关联,做附件访问权限控制 + att_ids2 += self.description.to_s.scan(/\(\/api\/attachments\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\)/).map{|s|s.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/)[0]} + att_ids2 += self.description.to_s.scan(/\/api\/attachments\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/).map{|s|s.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/)[0]} + if att_ids2.present? + Attachment.where(uuid: att_ids2).where("container_type IS NULL OR container_type = 'Issue'").update_all(container_id: self.project_id, container_type: 'Project') end end diff --git a/app/models/issue_tag.rb b/app/models/issue_tag.rb index 7251e98f2..f5f0abbd8 100644 --- a/app/models/issue_tag.rb +++ b/app/models/issue_tag.rb @@ -14,6 +14,7 @@ # gid :integer # gitea_url :string(255) # pull_requests_count :integer default("0") +# pm_project_id :integer # # Indexes # @@ -32,18 +33,7 @@ class IssueTag < ApplicationRecord validates :name, uniqueness: {scope: :project_id, message: "已存在" } def self.init_data(project_id) - data = [ - ["缺陷", "表示存在意外问题或错误", "#d92d4c"], - ["功能", "表示新功能申请", "#ee955a"], - ["疑问", "表示存在疑惑", "#2d6ddc"], - ["支持", "表示特定功能或特定需求", "#019549"], - ["任务", "表示需要分配的任务", "#c1a30d"], - ["协助", "表示需要社区用户协助", "#2a0dc1"], - ["搁置", "表示此问题暂时不会继续处理", "#892794"], - ["文档", "表示文档材料补充", "#9ed600"], - ["测试", "表示需要测试的需求", "#2897b9"], - ["重复", "表示已存在类似的疑修", "#bb5332"] - ] + data = init_issue_tag_data data.each do |item| next if IssueTag.exists?(project_id: project_id, name: item[0]) IssueTag.create!(project_id: project_id, name: item[0], description: item[1], color: item[2]) @@ -57,6 +47,34 @@ class IssueTag < ApplicationRecord end + def self.init_issue_tag_data + [ + ["缺陷", "表示存在意外问题或错误", "#d92d4c"], + ["功能", "表示新功能申请", "#ee955a"], + ["疑问", "表示存在疑惑", "#2d6ddc"], + ["支持", "表示特定功能或特定需求", "#019549"], + ["任务", "表示需要分配的任务", "#c1a30d"], + ["协助", "表示需要社区用户协助", "#2a0dc1"], + ["搁置", "表示此问题暂时不会继续处理", "#892794"], + ["文档", "表示文档材料补充", "#9ed600"], + ["测试", "表示需要测试的需求", "#2897b9"], + ["重复", "表示已存在类似的疑修", "#bb5332"] + ] + end + + def self.init_mp_issues_tags + data = {"total_count": 10,} + data["issue_tags"] = init_issue_tag_data.map{|item| + { + "name": item[0], + "description": item[1], + "color": item[2], + } + } + data + end + + def to_builder Jbuilder.new do |tag| tag.(self, :id, :name, :description) diff --git a/app/models/journal.rb b/app/models/journal.rb index bea0a03c6..4ee37714b 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -27,6 +27,7 @@ # # index_journals_on_created_on (created_on) # index_journals_on_journalized_id (journalized_id) +# index_journals_on_parent_id (parent_id) # index_journals_on_review_id (review_id) # index_journals_on_user_id (user_id) # journals_journalized_id (journalized_id,journalized_type) @@ -61,6 +62,7 @@ class Journal < ApplicationRecord # 关附件到功能 def associate_attachment_container + return if self.issue&.project_id.to_i == 0 att_ids = [] # 附件的格式为(/api/attachments/ + 附件id)的形式,提取出id进行附件属性关联,做附件访问权限控制 att_ids += self.notes.to_s.scan(/\(\/api\/attachments\/.+\)/).map{|s|s.match(/\d+/)[0]} @@ -69,6 +71,15 @@ class Journal < ApplicationRecord if att_ids.present? Attachment.where(id: att_ids).where("container_type IS NULL OR container_type = 'Journal'").update_all(container_id: self.issue.project_id, container_type: "Project") end + + att_ids2 = [] + # uuid_regex= /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/ + # 附件的格式为(/api/attachments/ + uuid)的形式,提取出id进行附件属性关联,做附件访问权限控制 + att_ids2 += self.notes.to_s.scan(/\(\/api\/attachments\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\)/).map{|s|s.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/)[0]} + att_ids2 += self.notes.to_s.scan(/\/api\/attachments\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/).map{|s|s.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/)[0]} + if att_ids2.present? + Attachment.where(uuid: att_ids).where("container_type IS NULL OR container_type = 'Journal'").update_all(container_id: self.issue.project_id, container_type: "Project") + end end def operate_content @@ -78,9 +89,9 @@ class Journal < ApplicationRecord when 'issue' return "创建了疑修" when 'attachment' - old_value = Attachment.where(id: detail.old_value.split(",")).pluck(:filename).join("、") - new_value = Attachment.where(id: detail.value.split(",")).pluck(:filename).join("、") - if old_value.nil? || old_value.blank? + old_value = Attachment.where("id in (?) or uuid in (?)", detail.old_value.to_s.split(","), detail.old_value.to_s.split(",")).pluck(:filename).join("、") + new_value = Attachment.where("id in (?) or uuid in (?)", detail.value.to_s.split(","), detail.value.to_s.split(",")).pluck(:filename).join("、") + if old_value.nil? || old_value.blank? content += "添加了#{new_value}附件" else new_value = "无" if new_value.blank? diff --git a/app/models/message_template.rb b/app/models/message_template.rb index 7ab7fdad8..75d64fa95 100644 --- a/app/models/message_template.rb +++ b/app/models/message_template.rb @@ -52,6 +52,8 @@ class MessageTemplate < ApplicationRecord self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 {nickname2}/{repository} 创建了一个里程碑:{name}', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 新建了一个里程碑") email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html") self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 {nickname}/{repository} 仓库,里程碑 {name} 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: 仓库 {nickname}/{repository} 有里程碑已完成") + self.create(type: 'MessageTemplate::ProjectMilestoneEarlyExpired', sys_notice: '您创建的里程碑 {name} 已临近截止日期,请尽快处理.', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}') + self.create(type: 'MessageTemplate::ProjectMilestoneExpired', sys_notice: '您创建的里程碑 {name} 已逾期,请及时更新进度或联系项目团队.', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}') self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '{nickname1} 点赞了你管理的仓库 {nickname2}/{repository}', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::ProjectOpenDevOps', sys_notice: '您的仓库 {repository} 已成功开通引擎服务,可通过简单的节点编排完成自动化集成与部署。欢迎体验!', notification_url: '{baseurl}/{owner}/{identifier}/devops') email_html = File.read("#{email_template_html_dir}/project_pull_request.html") diff --git a/app/models/message_template/project_milestone_early_expired.rb b/app/models/message_template/project_milestone_early_expired.rb new file mode 100644 index 000000000..3db1e1908 --- /dev/null +++ b/app/models/message_template/project_milestone_early_expired.rb @@ -0,0 +1,70 @@ +# == 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::ProjectMilestoneEarlyExpired < MessageTemplate + + # MessageTemplate::ProjectMilestoneEarlyExpired.get_message_content(User.where(login: 'yystopf'), Version.find(7)) + def self.get_message_content(receivers, milestone) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + send_setting = receiver.user_template_message_setting.notification_body["ManageProject::MilestoneExpired"] + send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::MilestoneExpired"] : send_setting + receivers = receivers.where.not(id: receiver.id) unless send_setting + end + end + return '', '', '' if receivers.blank? + project = milestone&.project + owner = project&.owner + content = sys_notice.gsub('{nickname}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name) + url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s) + + return receivers_string(receivers), content, url + rescue => e + Rails.logger.info("MessageTemplate::MilestoneEarlyExpired.get_message_content [ERROR] #{e}") + return '', '', '' + end + + def self.get_email_message_content(receiver, milestone) + if receiver.user_template_message_setting.present? + send_setting = receiver.user_template_message_setting.email_body["ManageProject::MilestoneExpired"] + send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["ManageProject::MilestoneExpired"] : send_setting + return '', '', '' unless send_setting + project = milestone&.project + owner = project&.owner + title = email_title + title.gsub!('{nickname}', owner&.real_name) + title.gsub!('{repository}', project&.name) + + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{baseurl}', base_url) + content.gsub!('{nickname}', owner&.real_name) + content.gsub!('{repository}', project&.name) + content.gsub!('{login}', owner&.login) + content.gsub!('{identifier}', project&.identifier) + content.gsub!('{id}', milestone&.id.to_s) + content.gsub!('{name}', milestone&.name) + content.gsub!('{platform}', PLATFORM) + + return receiver&.mail, title, content + else + return '', '', '' + end + + rescue => e + Rails.logger.info("MessageTemplate::MilestoneEarlyExpired.get_email_message_content [ERROR] #{e}") + return '', '', '' + end +end diff --git a/app/models/message_template/project_milestone_expired.rb b/app/models/message_template/project_milestone_expired.rb new file mode 100644 index 000000000..de6b8c10c --- /dev/null +++ b/app/models/message_template/project_milestone_expired.rb @@ -0,0 +1,70 @@ +# == 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::ProjectMilestoneExpired < MessageTemplate + + # MessageTemplate::ProjectMilestoneExpired.get_message_content(User.where(login: 'yystopf'), Version.find(7)) + def self.get_message_content(receivers, milestone) + receivers.each do |receiver| + if receiver.user_template_message_setting.present? + send_setting = receiver.user_template_message_setting.notification_body["ManageProject::MilestoneExpired"] + send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::MilestoneExpired"] : send_setting + receivers = receivers.where.not(id: receiver.id) unless send_setting + end + end + return '', '', '' if receivers.blank? + project = milestone&.project + owner = project&.owner + content = sys_notice.gsub('{nickname}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name) + url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s) + + return receivers_string(receivers), content, url + rescue => e + Rails.logger.info("MessageTemplate::ProjectMilestoneExpired.get_message_content [ERROR] #{e}") + return '', '', '' + end + + def self.get_email_message_content(receiver, milestone) + if receiver.user_template_message_setting.present? + send_setting = receiver.user_template_message_setting.email_body["ManageProject::MilestoneExpired"] + send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["ManageProject::MilestoneExpired"] : send_setting + return '', '', '' unless send_setting + project = milestone&.project + owner = project&.owner + title = email_title + title.gsub!('{nickname}', owner&.real_name) + title.gsub!('{repository}', project&.name) + + content = email + content.gsub!('{receiver}', receiver&.real_name) + content.gsub!('{baseurl}', base_url) + content.gsub!('{nickname}', owner&.real_name) + content.gsub!('{repository}', project&.name) + content.gsub!('{login}', owner&.login) + content.gsub!('{identifier}', project&.identifier) + content.gsub!('{id}', milestone&.id.to_s) + content.gsub!('{name}', milestone&.name) + content.gsub!('{platform}', PLATFORM) + + return receiver&.mail, title, content + else + return '', '', '' + end + + rescue => e + Rails.logger.info("MessageTemplate::ProjectMilestoneExpired.get_email_message_content [ERROR] #{e}") + return '', '', '' + end +end diff --git a/app/models/open_users/acge.rb b/app/models/open_users/acge.rb new file mode 100644 index 000000000..59963b91f --- /dev/null +++ b/app/models/open_users/acge.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::Acge < OpenUser + def nickname + extra&.[]('nickname') + end + + def en_type + 'acge' + end +end diff --git a/app/models/organization.rb b/app/models/organization.rb index cb829626e..f978611b1 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -64,7 +64,7 @@ class Organization < Owner alias_attribute :name, :login - NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 + NAME_REGEX = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*$/ #只含有数字、字母、下划线不能以下划线开头和结尾 default_scope { where(type: "Organization") } @@ -79,7 +79,7 @@ class Organization < Owner validates :login, presence: true validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false - validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } + validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符" } delegate :description, :website, :location, :repo_admin_change_team_access, :recommend, :visibility, :max_repo_creation, :num_projects, :num_users, :num_teams, @@ -182,14 +182,6 @@ class Organization < Owner organization_users.count end - def teams_count - teams.count - end - - def organization_users_count - organization_users.count - end - def real_name name = lastname + firstname name = name.blank? ? (nickname.blank? ? login : nickname) : name @@ -217,4 +209,11 @@ class Organization < Owner enabling_cla == true end + def num_users + organization_user_ids = self.organization_users.pluck(:user_id).uniq + project_member_user_ids = self.projects.joins(:members).pluck("members.user_id").uniq + ids = organization_user_ids + project_member_user_ids + ids.uniq.size + end + end diff --git a/app/models/page.rb b/app/models/page.rb index 57a30acad..1c606760e 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -34,6 +34,10 @@ class Page < ApplicationRecord PageService.genernate_user(user_id) end + before_destroy do + PageService.close_site(user_id, identifier) + end + before_save do if state_changed? && state == false PageService.close_site(user_id, identifier) @@ -46,7 +50,7 @@ class Page < ApplicationRecord def url @deploy_domain = EduSetting.find_by_name("site_page_deploy_domain").try(:value) - "http://#{user.login}.#{@deploy_domain}/#{identifier}" + "http://#{identifier}" end def build_script_path diff --git a/app/models/project.rb b/app/models/project.rb index 5f9fcef68..34e981508 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -136,6 +136,7 @@ class Project < ApplicationRecord has_many :project_topic_ralates, dependent: :destroy has_many :project_topics, through: :project_topic_ralates has_many :commit_logs, dependent: :destroy + has_many :daily_project_statistics, 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/template_message_setting/create_or_assign.rb b/app/models/template_message_setting/create_or_assign.rb index 629051305..8f0817070 100644 --- a/app/models/template_message_setting/create_or_assign.rb +++ b/app/models/template_message_setting/create_or_assign.rb @@ -28,5 +28,6 @@ class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting self.find_or_create_by(name: "疑修状态变更", key: "IssueChanged") self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged") self.find_or_create_by(name: "疑修截止日期到达最后一天", key: "IssueExpire", notification_disabled: false) + self.find_or_create_by(name: "里程碑逾期提醒", key: "MilestoneExpired", notification_disabled: false, email_disabled: true) end end diff --git a/app/models/trace_user.rb b/app/models/trace_user.rb index 69198706e..6e032e9fd 100644 --- a/app/models/trace_user.rb +++ b/app/models/trace_user.rb @@ -43,8 +43,9 @@ class TraceUser < ApplicationRecord def build_token return if username.blank? || password.blank? || unit.blank? || email.blank? || name.blank? - response = Trace::AddUserService.call(username, password, unit, telnumber, email, name) - self.token = response[1]['token'] + response1 = Trace::AddUserService.call(username, password, unit, telnumber, email, name) + response2 = Trace::LoginService.call(username, password) + self.token = response2[1]['token'] self.expired_at = Time.now + 1.hours end diff --git a/app/models/user.rb b/app/models/user.rb index 8f1e29547..9d623f949 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -115,7 +115,7 @@ class User < Owner # trustie: 来自Trustie平台 # forge: 平台本身注册的用户 # military: 军科的用户 - enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat, :bot], default: :forge, scope: :shallow + enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat, :bot, :acge], default: :forge, scope: :shallow belongs_to :laboratory, optional: true has_one :user_extension, dependent: :destroy @@ -189,7 +189,7 @@ class User < Owner has_many :user_clas, :dependent => :destroy has_many :clas, through: :user_clas - has_many :pages, :dependent => :destroy + has_one :page, :dependent => :destroy # Groups and active users scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } @@ -465,7 +465,7 @@ class User < Owner $gitea_client.delete_users_tokens_by_username_token(self.login, e["name"], {query: {sudo: self.login} }) } end - new_result = $gitea_client.post_users_tokens_by_username(self.login, { query: {sudo: self.login}, body:{ name: self.login} }) + new_result = $gitea_client.post_users_tokens_by_username(self.login, { query: {sudo: self.login}, body:{ name: "#{self.login}-#{SecureRandom.hex(6)}", scopes: ["all"]}.to_json }) if new_result["sha1"].present? update(gitea_token: new_result["sha1"]) end @@ -773,7 +773,7 @@ class User < Owner def check_website_permission if website_permission_changed? && website_permission == false - self.pages.update_all(state: false, state_description:"因违规使用,现关闭Page服务") + self.page.update(state: false, state_description:"因违规使用,现关闭Page服务") PageService.close_site(self.id) end end diff --git a/app/models/user_template_message_setting.rb b/app/models/user_template_message_setting.rb index 49db51d4d..befd2be87 100644 --- a/app/models/user_template_message_setting.rb +++ b/app/models/user_template_message_setting.rb @@ -36,6 +36,7 @@ class UserTemplateMessageSetting < ApplicationRecord "CreateOrAssign::IssueChanged": true, "CreateOrAssign::PullRequestChanged": true, "CreateOrAssign::IssueExpire": true, + "CreateOrAssign::MilestoneExpired": true, "ManageProject::Issue": true, "ManageProject::PullRequest": true, "ManageProject::Member": true, @@ -44,6 +45,8 @@ class UserTemplateMessageSetting < ApplicationRecord "ManageProject::Forked": true, "ManageProject::Milestone": true, "ManageProject::MilestoneCompleted": true, + "ManageProject::MilestoneExpired": true, + "ManageProject::MilestoneEarlyExpired": true, }.stringify_keys! end @@ -57,6 +60,7 @@ class UserTemplateMessageSetting < ApplicationRecord "CreateOrAssign::IssueChanged": false, "CreateOrAssign::PullRequestChanged": false, "CreateOrAssign::IssueExpire": false, + "CreateOrAssign::MilestoneExpired": false, "ManageProject::Issue": false, "ManageProject::PullRequest": false, "ManageProject::Member": false, @@ -65,6 +69,8 @@ class UserTemplateMessageSetting < ApplicationRecord "ManageProject::Forked": false, "ManageProject::Milestone": false, "ManageProject::MilestoneCompleted": false, + "ManageProject::MilestoneExpired": false, + "ManageProject::MilestoneEarlyExpired": false, }.stringify_keys! end diff --git a/app/models/version.rb b/app/models/version.rb index ec2ad68cd..871f63dfd 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -68,5 +68,7 @@ class Version < ApplicationRecord def send_update_message_to_notice_system SendTemplateMessageJob.perform_later('ProjectMilestoneCompleted', self.id) if Site.has_notice_menu? && self.issue_percent == 1.0 + SendTemplateMessageJob.perform_later('ProjectMilestoneEarlyExpired', self.id) if Site.has_notice_menu? && self.effective_date == Date.today + 1.days + SendTemplateMessageJob.perform_later('ProjectMilestoneExpired', self.id) if Site.has_notice_menu? && self.effective_date == Date.today - 1.days end end diff --git a/app/services/api/v1/issues/concerns/checkable.rb b/app/services/api/v1/issues/concerns/checkable.rb index b19c245ed..5eef81584 100644 --- a/app/services/api/v1/issues/concerns/checkable.rb +++ b/app/services/api/v1/issues/concerns/checkable.rb @@ -31,8 +31,8 @@ module Api::V1::Issues::Concerns::Checkable def check_attachments (attachment_ids) raise ApplicationService::Error, "请输入正确的附件ID数组!" unless attachment_ids.is_a?(Array) attachment_ids.each do |aid| - raise ApplicationService::Error, "请输入正确的附件ID!" unless Attachment.exists?(id: aid) - end + raise ApplicationService::Error, "请输入正确的附件ID!" unless Attachment.where_id_or_uuid(aid).exists? + end end def check_atme_receivers(receivers_login) diff --git a/app/services/api/v1/issues/concerns/loadable.rb b/app/services/api/v1/issues/concerns/loadable.rb index df30042e0..547ff50d7 100644 --- a/app/services/api/v1/issues/concerns/loadable.rb +++ b/app/services/api/v1/issues/concerns/loadable.rb @@ -9,7 +9,7 @@ module Api::V1::Issues::Concerns::Loadable end def load_attachments(attachment_ids) - @attachments = Attachment.where(id: attachment_ids) + @attachments = Attachment.where("id in (?) or uuid in (?)", attachment_ids, attachment_ids) end def load_atme_receivers(receivers_login) diff --git a/app/services/api/v1/issues/list_service.rb b/app/services/api/v1/issues/list_service.rb index 184eaa4f1..983e97c18 100644 --- a/app/services/api/v1/issues/list_service.rb +++ b/app/services/api/v1/issues/list_service.rb @@ -60,13 +60,31 @@ class Api::V1::Issues::ListService < ApplicationService issues = issues.where(author_id: author_id) if author_id.present? # issue_tag_ids - issues = issues.ransack(issue_tags_value_cont: issue_tag_ids.sort!.join(',')).result unless issue_tag_ids.blank? + if issue_tag_ids.present? + if issue_tag_ids.include?('-1') + issues = issues.where(issue_tags_value: nil).or(issues.where(issue_tags_value: "")) + else + issues = issues.ransack(issue_tags_value_cont: issue_tag_ids.sort!.join(',')).result + end + end # milestone_id - issues = issues.where(fixed_version_id: milestone_id) if milestone_id.present? + if milestone_id.present? + if milestone_id.to_i == -1 + issues = issues.where(fixed_version_id: nil) + else + issues = issues.where(fixed_version_id: milestone_id) + end + end # assigner_id - issues = issues.joins(:assigners).where(users: {id: assigner_id}) if assigner_id.present? + if assigner_id.present? + if assigner_id.to_i == -1 + issues = issues.left_joins(:assigners).where(users: {id: nil}) + else + issues = issues.joins(:assigners).where(users: {id: assigner_id}) + end + end # status_id issues = issues.where(status_id: status_id) if status_id.present? && category != 'closed' diff --git a/app/services/api/v1/projects/actions/runs/job_show_service.rb b/app/services/api/v1/projects/actions/runs/job_show_service.rb new file mode 100644 index 000000000..e80e882be --- /dev/null +++ b/app/services/api/v1/projects/actions/runs/job_show_service.rb @@ -0,0 +1,42 @@ +class Api::V1::Projects::Actions::Runs::JobShowService < ApplicationService + include ActiveModel::Model + + attr_reader :project, :token, :owner, :repo, :run, :job, :log_cursors + attr_accessor :gitea_data + + validates :run, :job, :log_cursors, presence: true + + def initialize(project, run, job, log_cursors, token = nil) + @project = project + @owner = project&.owner.login + @repo = project&.identifier + @run = run + @job = job + @log_cursors = log_cursors + @token = token + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + load_gitea_data + + @gitea_data + end + + private + def request_params + { + access_token: token + } + end + + def request_body + { + logCursors: log_cursors + } + end + + def load_gitea_data + @gitea_data = $gitea_hat_client.post_repos_actions_runs_jobs_by_owner_repo_run_job(owner, repo, run, job, {query: request_params, body: request_body.to_json}) + end +end \ No newline at end of file diff --git a/app/services/api/v1/projects/actions/runs/list_service.rb b/app/services/api/v1/projects/actions/runs/list_service.rb new file mode 100644 index 000000000..5889518ce --- /dev/null +++ b/app/services/api/v1/projects/actions/runs/list_service.rb @@ -0,0 +1,40 @@ +class Api::V1::Projects::Actions::Runs::ListService < ApplicationService + include ActiveModel::Model + + attr_reader :project, :token, :owner, :repo, :workflow, :page, :limit + attr_accessor :gitea_data + + validates :workflow, presence: true + + def initialize(project, params, token =nil) + @project = project + @owner = project&.owner.login + @repo = project&.identifier + @workflow = params[:workflow] + @page = params[:page] || 1 + @limit = params[:limit] || 15 + @token = token + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + load_gitea_data + + @gitea_data + end + + private + def request_params + { + access_token: token, + workflow: workflow, + page: page, + limit: limit + } + end + + def load_gitea_data + @gitea_data = $gitea_hat_client.get_repos_actions_by_owner_repo(owner, repo, {query: request_params}) rescue nil + raise Error, '获取流水线执行记录失败!' unless @gitea_data.is_a?(Hash) + end +end \ No newline at end of file diff --git a/app/services/api/v1/projects/branches/delete_service.rb b/app/services/api/v1/projects/branches/delete_service.rb index 28836c797..341079273 100644 --- a/app/services/api/v1/projects/branches/delete_service.rb +++ b/app/services/api/v1/projects/branches/delete_service.rb @@ -32,7 +32,7 @@ class Api::V1::Projects::Branches::DeleteService < ApplicationService def excute_data_to_gitea begin - @gitea_data = $gitea_client.delete_repos_branches_by_owner_repo_branch(owner, repo, branch_name, {query: request_params}) + @gitea_data = $gitea_client.delete_repos_branches_by_owner_repo_branch(owner, repo, CGI.escape(branch_name), {query: request_params}) rescue => e raise Error, '保护分支无法删除!' if e.to_s.include?("branch protected") raise Error, '删除分支失败!' diff --git a/app/services/api/v1/projects/branches/list_service.rb b/app/services/api/v1/projects/branches/list_service.rb index 590c4884f..6980b71ea 100644 --- a/app/services/api/v1/projects/branches/list_service.rb +++ b/app/services/api/v1/projects/branches/list_service.rb @@ -1,6 +1,6 @@ class Api::V1::Projects::Branches::ListService < ApplicationService - attr_accessor :project, :token, :owner, :repo, :name, :page, :limit + attr_accessor :project, :token, :owner, :repo, :name, :state, :page, :limit attr_accessor :gitea_data, :gitea_repo_data def initialize(project, params, token=nil) @@ -9,6 +9,7 @@ class Api::V1::Projects::Branches::ListService < ApplicationService @repo = project&.identifier @token = token @name = params[:name] + @state = params[:state] @page = params[:page] @limit = params[:limit] end @@ -18,7 +19,6 @@ class Api::V1::Projects::Branches::ListService < ApplicationService load_default_branch @gitea_data[:default_branch] = @gitea_repo_data["default_branch"] - @gitea_data end @@ -30,7 +30,8 @@ class Api::V1::Projects::Branches::ListService < ApplicationService limit: limit } params.merge!({name: name}) if name.present? - + params.merge!({state: state}) if state.present? + params end diff --git a/app/services/api/v1/projects/branches/restore_service.rb b/app/services/api/v1/projects/branches/restore_service.rb new file mode 100644 index 000000000..fbd6220ed --- /dev/null +++ b/app/services/api/v1/projects/branches/restore_service.rb @@ -0,0 +1,47 @@ +class Api::V1::Projects::Branches::RestoreService < ApplicationService + + include ActiveModel::Model + + attr_accessor :project, :token, :owner, :repo, :branch_id, :branch_name + attr_accessor :gitea_data + + validates :branch_id, :branch_name, presence: true + + def initialize(project, branch_id, branch_name, token= nil) + @project = project + @owner = project&.owner&.login + @repo = project&.identifier + @branch_id = branch_id + @branch_name = branch_name + @token = token + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + excute_data_to_gitea + + true + end + + private + def request_params + { + access_token: token + } + end + + def request_body + { + branch_id: branch_id, + name: branch_name, + } + end + + def excute_data_to_gitea + begin + @gitea_data = $gitea_hat_client.post_repos_branches_restore_by_owner_repo(owner, repo, {query: request_params, body: request_body.to_json}) + rescue => e + raise Error, '恢复分支失败!' + end + end +end \ No newline at end of file diff --git a/app/services/api/v1/projects/commits/recent_service.rb b/app/services/api/v1/projects/commits/recent_service.rb new file mode 100644 index 000000000..9bc77dfc2 --- /dev/null +++ b/app/services/api/v1/projects/commits/recent_service.rb @@ -0,0 +1,39 @@ +class Api::V1::Projects::Commits::RecentService < ApplicationService + + attr_reader :project, :page, :limit, :keyword, :owner, :repo, :token + attr_accessor :gitea_data + + def initialize(project, params, token=nil) + @project = project + @page = params[:page] || 1 + @limit = params[:limit] || 15 + @keyword = params[:keyword] + @owner = project&.owner&.login + @repo = project&.identifier + @token = token + end + + def call + load_gitea_data + + gitea_data + end + + private + def request_params + param = { + access_token: token, + page: page, + limit: limit + } + param.merge!(keyword: keyword) if keyword.present? + + param + end + + def load_gitea_data + @gitea_data = $gitea_hat_client.get_repos_recent_commits_by_owner_repo(owner, repo, {query: request_params}) rescue nil + raise Error, "获取最近提交列表失败" unless @gitea_data.is_a?(Hash) + end + +end \ No newline at end of file diff --git a/app/services/api/v1/projects/compare_service.rb b/app/services/api/v1/projects/compare_service.rb index 23a248305..9e646326f 100644 --- a/app/services/api/v1/projects/compare_service.rb +++ b/app/services/api/v1/projects/compare_service.rb @@ -29,6 +29,6 @@ class Api::V1::Projects::CompareService < ApplicationService end def load_gitea_data - @gitea_data = $gitea_client.get_repos_compare_by_owner_repo_from_to(owner, repo, from, to, {query: request_params}) rescue nil + @gitea_data = $gitea_hat_client.get_repos_compare_by_owner_repo_baseref_headref(owner, repo, to, from, {query: request_params}) rescue nil end end \ No newline at end of file diff --git a/app/services/api/v1/projects/tags/delete_service.rb b/app/services/api/v1/projects/tags/delete_service.rb index d0d317aa8..8f898bf1a 100644 --- a/app/services/api/v1/projects/tags/delete_service.rb +++ b/app/services/api/v1/projects/tags/delete_service.rb @@ -32,7 +32,7 @@ class Api::V1::Projects::Tags::DeleteService < ApplicationService def excute_data_to_gitea begin - @gitea_data = $gitea_client.delete_repos_tags_by_owner_repo_tag(owner, repo, tag_name, {query: request_params}) + @gitea_data = $gitea_client.delete_repos_tags_by_owner_repo_tag(owner, repo, CGI.escape(tag_name), {query: request_params}) rescue => e raise Error, '请先删除发行版!' if e.to_s.include?("409") raise Error, '删除标签失败!' diff --git a/app/services/api/v1/projects/tags/get_service.rb b/app/services/api/v1/projects/tags/get_service.rb new file mode 100644 index 000000000..bfceab4c2 --- /dev/null +++ b/app/services/api/v1/projects/tags/get_service.rb @@ -0,0 +1,48 @@ +class Api::V1::Projects::Tags::GetService < ApplicationService + include ActiveModel::Model + + attr_reader :project, :token, :owner, :repo, :tag_name + attr_accessor :gitea_data + + validates :tag_name, presence: true + + def initialize(project, tag_name, token=nil) + @project = project + @owner = project&.owner&.login + @repo = project&.identifier + @tag_name = tag_name.to_s + @token = token + end + + def call + + raise Error, errors.full_messages.join(",") unless valid? + + check_tag_exist + + load_gitea_data + + gitea_data + end + + private + def request_params + params = { + access_token: token + } + + params + end + + def load_gitea_data + @gitea_data = $gitea_hat_client.get_repos_tags_by_owner_repo_tag(owner, repo, URI.escape(tag_name), {query: request_params}) rescue nil + raise Error, '获取标签失败!' unless @gitea_data.is_a?(Hash) + end + + def check_tag_exist + result = $gitea_hat_client.get_repos_tag_name_set_by_owner_repo(owner, repo, {query: request_params}) rescue nil + + raise Error, '查询标签名称失败!' unless result.is_a?(Array) + raise Error, '标签不存在!' if !result.include?(@tag_name) + end +end \ No newline at end of file diff --git a/app/services/baidu/tongji_service.rb b/app/services/baidu/tongji_service.rb new file mode 100644 index 000000000..a2a4f28fc --- /dev/null +++ b/app/services/baidu/tongji_service.rb @@ -0,0 +1,221 @@ +module Baidu + class TongjiService < ApplicationService + attr_reader :client_id, :client_secret, :site_id + # login、code、password、password_confirmation + def initialize + @client_id = "6dMO2kqKUaMZkBrMaUMxQSNAT49v0Mjq" + @client_secret = "qvWqF33AOmGs1tPCgsROvis9EQCuNmd3" + @site_id = 18657013 + end + + def call + + end + + + def init_overview_data_by(start_date = nil, end_date = nil) + start_date = Time.now.prev_year.beginning_of_year if start_date.nil? + end_date = Time.now + Rails.logger.info("*********开始百度统计-概览:#{start_date}-#{end_date}*********") + sql_connection = ActiveRecord::Base.connection + sql_connection.begin_db_transaction + + # 如果存在数据 先清空 + # sql_connection.execute("delete from daily_platform_statistics where date between '#{start_date}' and '#{end_date}'") + multiple_days_data = overview_multiple_days_data(start_date, end_date) + if multiple_days_data.present? + sql = "replace into daily_platform_statistics (date,pv,visitor,ip,created_at,updated_at) values #{multiple_days_data.join(",")}" + sql_connection.execute(sql) + end + sql_connection.commit_db_transaction + Rails.logger.info("*********结束百度统计-概览:#{start_date}-#{end_date}*********") + end + + def init_source_from_data_by(start_date = nil, end_date = nil) + start_date = Time.now.prev_year.beginning_of_year if start_date.nil? + end_date = Time.now + Rails.logger.info("*********开始百度统计-来源:#{start_date}-#{end_date}*********") + source_from_batch_add(start_date, end_date) + Rails.logger.info("*********结束百度统计-来源:#{start_date}-#{end_date}*********") + end + + # 按日期获取来源数据 + def source_from_batch_add(start_date,end_date) + # 补充更新开始时间的当天数据 + source_from_by_date(start_date) + diff_days(start_date, end_date).times.each do |t| + new_start_date = start_date + (t + 1).days + source_from_by_date(new_start_date) + end + # 补充更新最后时间一天数据 + source_from_by_date(end_date) + end + + # 按天获取来源数据 + def source_from_by_date(start_date) + return [] unless access_token.present? && start_date.present? + source_from_data = api("source/all/a", start_date, start_date, "pv_count,visitor_count,ip_count") + source_from = [] + source_from_data['items'][1].each_with_index do |source, index| + source_from.push(((source[0].to_f / source_from_data['sum'][0][0].to_f) * 100).round(2)) + end + daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: start_date) + daily_statistic.source_through = source_from[0] + daily_statistic.source_link = source_from[1] + daily_statistic.source_search = source_from[2] + daily_statistic.source_custom = source_from[3] + daily_statistic.save + end + + def diff_days(start_date, end_date) + (end_date.beginning_of_day.to_i - start_date.beginning_of_day.to_i) / (24 * 3600) + end + + def overview_batch_add(start_date, end_date) + return [] unless access_token.present? && start_date.present? && end_date.present? + start_date = Time.now - 1.days if start_date.strftime("%Y%m%d") == end_date.strftime("%Y%m%d") + overview_data = api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count") + overview_data['items'][0].each_with_index do |date, index| + pv = overview_data['items'][1][index][0] + visitor = overview_data['items'][1][index][1] + ip = overview_data['items'][1][index][2] + job_date = date[0].to_s.gsub("/", "-") + daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: job_date) + daily_statistic.date = job_date + daily_statistic.pv = pv + daily_statistic.visitor = visitor + daily_statistic.ip = ip + daily_statistic.save + end + overview_data + end + + def overview_multiple_days_data(start_date, end_date) + return [] unless access_token.present? && start_date.present? && end_date.present? + overview_data = api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count") + data = [] + created_at = Time.now.strftime("%Y-%m-%d 00:00:00") + overview_data['items'][0].each_with_index do |date, index| + pv = overview_data['items'][1][index][0] + visitor = overview_data['items'][1][index][1] + ip = overview_data['items'][1][index][2] + data.push("('#{date[0].to_s.gsub("/", "-")}', #{pv.to_s.gsub("--","0")}, #{visitor.to_s.gsub("--","0")}, #{ip.to_s.gsub("--","0")},\"#{created_at}\",\"#{created_at}\")") + end + data + end + + def code_url + "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=#{client_id}&redirect_uri=oob&scope=basic&display=popup" + end + + def oauth_url(code) + "http://openapi.baidu.com/oauth/2.0/token?grant_type=authorization_code&code=#{code}&client_id=#{client_id}&client_secret=#{client_secret}&redirect_uri=oob" + end + + def get_access_token(code) + uri = URI.parse(oauth_url(code)) + response = Net::HTTP.get_response(uri) + Rails.logger.info "baidu_tongji_auth response.body ===== #{response.body}" + if response.code.to_i == 200 + data = JSON.parse(response.body) + access_token = data['access_token'] + refresh_token = data['refresh_token'] + expires_in = data['expires_in'] + if access_token.present? + Rails.cache.write("baidu_tongji_auth/access_token", access_token, expires_in: expires_in) + Rails.cache.write("baidu_tongji_auth/refresh_token", refresh_token, expires_in: 1.year) + end + end + end + + def refresh_access_token + url = "http://openapi.baidu.com/oauth/2.0/token?grant_type=refresh_token&refresh_token=#{refresh_token}&client_id=#{client_id}&client_secret=#{client_secret}" + uri = URI.parse(url) + response = Net::HTTP.get_response(uri) + Rails.logger.info "baidu_tongji_auth response.body ===== #{response.body}" + if response.code.to_i == 200 + data = JSON.parse(response.body) + access_token = data['access_token'] + refresh_token = data['refresh_token'] + expires_in = data['expires_in'] + if access_token.present? + Rails.cache.write("baidu_tongji_auth/access_token", access_token, expires_in: expires_in) + Rails.cache.write("baidu_tongji_auth/refresh_token", refresh_token, expires_in: 1.year) + end + end + end + + def access_token + access_token = Rails.cache.read("baidu_tongji_auth/access_token") + if access_token.blank? && refresh_token.present? + refresh_access_token + access_token = Rails.cache.read("baidu_tongji_auth/access_token") + end + access_token + end + + def refresh_token + refresh_token = Rails.cache.read("baidu_tongji_auth/refresh_token") + # 如果刷新token失效,access_token也重置 + if refresh_token.blank? + Rails.cache.delete("baidu_tongji_auth/access_token") + end + refresh_token + end + + # 网站概况(趋势数据) + def api_overview + start_date = Time.now.beginning_of_week + end_date = Time.now + start_date = Time.now - 1.days if start_date.strftime("%Y%m%d") == end_date.strftime("%Y%m%d") + api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count") + end + + # 网站概况(来源网站、搜索词、入口页面、受访页面) + def api_overview_getCommonTrackRpt + start_date = Time.now.beginning_of_week + end_date = Time.now + api("overview/getCommonTrackRpt", start_date, end_date, "pv_count") + end + + # 全部来源 + def source_from + start_date = Time.now.beginning_of_week + end_date = Time.now + api("source/all/a", start_date, end_date, "pv_count,visitor_count,ip_count") + end + + def api(api_method, start_date, end_date, metrics = nil) + start_date_fmt = start_date.strftime("%Y%m%d") + end_date_fmt = end_date.strftime("%Y%m%d") + api_url = "https://openapi.baidu.com/rest/2.0/tongji/report/getData?access_token=#{access_token}&site_id=#{site_id}&method=#{api_method}&start_date=#{start_date_fmt}&end_date=#{end_date_fmt}&metrics=#{metrics}" + data = url_http_post(api_url, {}) + data['result'] + end + + def url_http_post(api_url, params) + Rails.logger.info "api_url==#{api_url}" + uri = URI.parse(api_url) + http = Net::HTTP.new uri.host, uri.port + http.open_timeout = 60 + http.read_timeout = 60 + if uri.scheme == 'https' + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + http.use_ssl = true + end + begin + request = Net::HTTP::Post.new(uri) + request.set_form_data(params) if params.present? + request['Content-Type'] = 'application/json;charset=utf-8' + # request['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8' + response = http.start { |http| http.request(request) } + Rails.logger.info "api response.body==#{response.body}" + JSON.parse response.body + rescue => err + Rails.logger.error("#############api_url:#{api_url},error:#{err.message.size}") + # Rails.logger.error("#############api_url:#{api_url},error:#{err.message}") + return {} + end + end + end +end diff --git a/app/services/cache/v2/project_common_service.rb b/app/services/cache/v2/project_common_service.rb index 0d167c2a7..1e85f3e08 100644 --- a/app/services/cache/v2/project_common_service.rb +++ b/app/services/cache/v2/project_common_service.rb @@ -1,5 +1,5 @@ class Cache::V2::ProjectCommonService < ApplicationService - attr_reader :project_id, :owner_id, :name, :identifier, :description, :visits, :watchers, :praises, :forks, :issues, :pullrequests, :commits + attr_reader :project_id, :owner_id, :name, :identifier, :description, :visits, :watchers, :praises, :forks, :issues, :closed_issues, :pullrequests, :commits attr_accessor :project def initialize(project_id, params={}) @@ -13,6 +13,7 @@ class Cache::V2::ProjectCommonService < ApplicationService @praises = params[:praises] @forks = params[:forks] @issues = params[:issues] + @closed_issues = params[:closed_issues] @pullrequests = params[:pullrequests] @commits = params[:commits] end @@ -78,6 +79,10 @@ class Cache::V2::ProjectCommonService < ApplicationService "issues" end + def closed_issues_key + "closed_issues" + end + def pullrequests_key "pullrequests" end @@ -151,6 +156,10 @@ class Cache::V2::ProjectCommonService < ApplicationService Cache::V2::ProjectRankService.call(@project_id, {issues: @issues}) Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {issues: @issues}) end + if @closed_issues.present? + $redis_cache.hincrby(project_common_key, closed_issues_key, @closed_issues) + Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {closed_issues: @closed_issues}) + end if @pullrequests.present? $redis_cache.hincrby(project_common_key, pullrequests_key, @pullrequests) Cache::V2::ProjectRankService.call(@project_id, {pullrequests: @pullrequests}) @@ -202,6 +211,10 @@ class Cache::V2::ProjectCommonService < ApplicationService $redis_cache.hset(project_common_key, issues_key, Issue.issue_issue.where(project_id: @project_id).count) end + def reset_project_closed_issues + $redis_cache.hset(project_common_key, closed_issues_key, Issue.issue_issue.closed.where(project_id: @project_id).count) + end + def reset_project_pullrequests $redis_cache.hset(project_common_key, pullrequests_key, PullRequest.where(project_id: @project_id).count) end @@ -224,6 +237,7 @@ class Cache::V2::ProjectCommonService < ApplicationService reset_project_praises reset_project_forks reset_project_issues + reset_project_closed_issues reset_project_pullrequests reset_project_commits diff --git a/app/services/cache/v2/project_date_rank_service.rb b/app/services/cache/v2/project_date_rank_service.rb index 9df69bbb4..bf661f0a2 100644 --- a/app/services/cache/v2/project_date_rank_service.rb +++ b/app/services/cache/v2/project_date_rank_service.rb @@ -1,6 +1,6 @@ # 项目日活跃度计算存储 class Cache::V2::ProjectDateRankService < ApplicationService - attr_reader :project_id, :rank_date, :visits, :praises, :forks, :issues, :pullrequests, :commits + attr_reader :project_id, :rank_date, :visits, :praises, :forks, :issues, :closed_issues, :pullrequests, :commits attr_accessor :project_common def initialize(project_id, rank_date=Date.today, params={}) @@ -11,6 +11,7 @@ class Cache::V2::ProjectDateRankService < ApplicationService @praises = params[:praises] @forks = params[:forks] @issues = params[:issues] + @closed_issues = params[:closed_issues] @pullrequests = params[:pullrequests] @commits = params[:commits] end @@ -57,6 +58,9 @@ class Cache::V2::ProjectDateRankService < ApplicationService $redis_cache.zincrby(project_rank_key, @issues.to_i * 5, @project_id) $redis_cache.hincrby(project_rank_statistic_key, "issues", @issues.to_i) end + if @closed_issues.present? + $redis_cache.hincrby(project_rank_statistic_key, "closed_issues", @closed_issues.to_i) + end if @pullrequests.present? $redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id) $redis_cache.hincrby(project_rank_statistic_key, "pullrequests", @pullrequests.to_i) diff --git a/app/services/getway/cms/get_service.rb b/app/services/getway/cms/get_service.rb index 6b7050e84..76c5f27e8 100644 --- a/app/services/getway/cms/get_service.rb +++ b/app/services/getway/cms/get_service.rb @@ -16,6 +16,6 @@ class Getway::Cms::GetService < Getway::ClientService end def url - "/cms/doc/open/#{doc_id}".freeze + "/cms/doc/open/baseInfo/#{doc_id}".freeze end end \ No newline at end of file diff --git a/app/services/gitea/repository/entries/create_service.rb b/app/services/gitea/repository/entries/create_service.rb index ac27b3afb..406106744 100644 --- a/app/services/gitea/repository/entries/create_service.rb +++ b/app/services/gitea/repository/entries/create_service.rb @@ -59,7 +59,11 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService if @body[:new_branch].present? && (@body[:new_branch].include?('/') || @body[:new_branch].include?('\'') || @body[:new_branch].include?('^') || @body[:new_branch].include?('*')) error("不合法的分支名称!") else - error("#{filepath}文件已存在,不能重复创建!") + if json_parse!(body)["message"].present? && json_parse!(body)["message"].starts_with?("branch already exists") + error("#{@body[:new_branch]}分支已存在!") + else + error("#{filepath}文件已存在,不能重复创建!") + end end else Rails.logger.error("Gitea api url==#{url},status:#{status},body=#{body}") diff --git a/app/services/gitea/user/generate_token_service.rb b/app/services/gitea/user/generate_token_service.rb index 946bd68ce..e2dd6b0f4 100644 --- a/app/services/gitea/user/generate_token_service.rb +++ b/app/services/gitea/user/generate_token_service.rb @@ -29,7 +29,7 @@ class Gitea::User::GenerateTokenService < Gitea::ClientService end def request_params - { name: "#{@username}-#{token_name}" } + { name: "#{@username}-#{token_name}", scopes: ["all"] } end def token_name diff --git a/app/services/page_service.rb b/app/services/page_service.rb index 687added1..5c166e82c 100644 --- a/app/services/page_service.rb +++ b/app/services/page_service.rb @@ -26,7 +26,7 @@ class PageService Rails.logger.info "################### PageService close_site #{user_id} / #{identifier}" user = User.find user_id uri = if identifier.present? - URI.parse("http://gitlink.#{@deploy_domain}/gitlink_execute_script?key=#{@deploy_key}&script_path=remove_dir&owner=#{user.login.downcase}/#{identifier}/") + URI.parse("http://gitlink.#{@deploy_domain}/gitlink_execute_script?key=#{@deploy_key}&script_path=remove_dir&owner=#{user.login.downcase}/*") else URI.parse("http://gitlink.#{@deploy_domain}/gitlink_execute_script?key=#{@deploy_key}&script_path=remove_dir&owner=#{user.login.downcase}/") end diff --git a/app/services/repositories/create_service.rb b/app/services/repositories/create_service.rb index e7ff8bd1d..4583838f1 100644 --- a/app/services/repositories/create_service.rb +++ b/app/services/repositories/create_service.rb @@ -67,7 +67,7 @@ class Repositories::CreateService < ApplicationService end def repository_params - params.merge(project_id: project.id) + params.merge(project_id: project.id).except(:auto_init) end def gitea_repository_params diff --git a/app/views/admins/carousels/index.html.erb b/app/views/admins/carousels/index.html.erb index 299d1dcfd..e9529c862 100644 --- a/app/views/admins/carousels/index.html.erb +++ b/app/views/admins/carousels/index.html.erb @@ -1,6 +1,6 @@ <% define_admin_breadcrumbs do - add_admin_breadcrumb('云上实验室', admins_laboratories_path) + add_admin_breadcrumb('导航栏配置', admins_laboratories_path) add_admin_breadcrumb('轮播图') end %> diff --git a/app/views/admins/dashboards/_baidu_tongji.html.erb b/app/views/admins/dashboards/_baidu_tongji.html.erb new file mode 100644 index 000000000..75fd1cde3 --- /dev/null +++ b/app/views/admins/dashboards/_baidu_tongji.html.erb @@ -0,0 +1,68 @@ +
+ 数据来源百度统计,本周 [<%= @current_week_statistic.first&.date %> / <%= @current_week_statistic.last&.date %>] +
+ + + + + + + + + + + + + + + <% if @current_week_statistic.size ==1 && @pre_week_statistic.present? %> + + + + + + + + + + + + <% end %> + <% @current_week_statistic.each_with_index do |week, index| %> + + + + + + + + + + + + <% end %> + + <% current_week_size = @current_week_statistic.size %> + + + + + + + + + + + +
日期访问量访客数IP数直接访问占比外部链接占比搜索引擎占比自定义
上周合计<%= @pre_week_statistic.map(&:pv).sum %><%= @pre_week_statistic.map(&:visitor).sum %><%= @pre_week_statistic.map(&:ip).sum %><%= (@pre_week_statistic.map(&:source_through).sum.to_f / 7).round(2) %>%<%= (@pre_week_statistic.map(&:source_link).sum.to_f / 7).round(2) %>%<%= (@pre_week_statistic.map(&:source_search).sum.to_f / 7).round(2) %>%<%= ((@pre_week_statistic.map(&:source_custom) - [nil]).sum.to_f / 7).round(2) %>%
<%= week.date %> <%= week.pv %><%= week.visitor %><%= week.ip %><%= week.source_through %>%<%= week.source_link %>%<%= week.source_search %>%<%= week.source_custom.to_f %>%
本周合计<%= @current_week_statistic.map(&:pv).sum %><%= @current_week_statistic.map(&:visitor).sum %><%= @current_week_statistic.map(&:ip).sum %><%= (@current_week_statistic.map(&:source_through).sum.to_f / current_week_size).round(2) %>%<%= (@current_week_statistic.map(&:source_link).sum.to_f / current_week_size).round(2) %>%<%= (@current_week_statistic.map(&:source_search).sum.to_f / current_week_size).round(2) %>%<%= ((@current_week_statistic.map(&:source_custom) - [nil]).sum.to_f / current_week_size).round(2) %>%
+ + +<% unless @access_token.present? && @overview_data.present? %> +
+ 1.百度统计需人工授权,点击去授权 +
+
+ 2.获取百度统计授权码 + +
+<% end %> \ No newline at end of file diff --git a/app/views/admins/dashboards/_baidu_tongji_api.html.erb b/app/views/admins/dashboards/_baidu_tongji_api.html.erb new file mode 100644 index 000000000..3a18dc405 --- /dev/null +++ b/app/views/admins/dashboards/_baidu_tongji_api.html.erb @@ -0,0 +1,67 @@ +<% if @access_token.present? && @overview_data.present? %> +
+ 数据来源百度统计,本周 <%= @overview_data['timeSpan'] %> +
+ + + + + + + + + + + <% pv_count = [] %> + <% visitor_count = [] %> + <% ip_count = [] %> + <% @overview_data['items'][0].each_with_index do |date, index| %> + <% pv = @overview_data['items'][1][index][0] %> + <% visitor = @overview_data['items'][1][index][1] %> + <% ip = @overview_data['items'][1][index][2] %> + + + + + + + + <% pv_count.push(pv) %> + <% visitor_count.push(visitor) %> + <% ip_count.push(ip) %> + <% end %> + + + + + + + + +
日期访问量访客数IP数
<%= date[0] %> <%= pv %><%= visitor %><%= ip %>
合计<%= pv_count %><%= visitor_count %><%= ip_count %>
+ + + + + + + + + + + + <% @source_from_data['items'][1].each_with_index do |source, index| %> + + <% end %> + + +
直接访问占比外部链接占比搜索引擎占比自定义
<%= ((source[0].to_f / @source_from_data['sum'][0][0].to_f) * 100).round(2).to_s %>%
+<% else %> +
+ 1.百度统计需人工授权,点击去授权 +
+
+ 2.获取百度统计授权码 + +
+<% end %> \ No newline at end of file diff --git a/app/views/admins/dashboards/index.html.erb b/app/views/admins/dashboards/index.html.erb index 2d86b4b6c..5441a1802 100644 --- a/app/views/admins/dashboards/index.html.erb +++ b/app/views/admins/dashboards/index.html.erb @@ -2,6 +2,38 @@ <% add_admin_breadcrumb('概览', admins_path) %> <% end %> +<% cache "/admin/dashboards/#{Time.now.strftime('%Y-%m-%d')}", :expires_in => 1.days do %> +
+
+
+ +
+ <%@subject_name.each_with_index do |subject, index| %> +
+
+
+
+
+
<%=subject %>
+ <%= @subject_data[index] %> +
+
+
+ +
+
+
+
+
+
+ <% end %> + +
+
+
+
+<%end %> +
@@ -53,6 +85,7 @@
+ <%= render partial: 'admins/dashboards/baidu_tongji' %>
\ No newline at end of file diff --git a/app/views/admins/identity_verifications/edit.html.erb b/app/views/admins/identity_verifications/edit.html.erb index 580c86f3f..28289e74f 100644 --- a/app/views/admins/identity_verifications/edit.html.erb +++ b/app/views/admins/identity_verifications/edit.html.erb @@ -106,7 +106,7 @@
- <%= f.input :description, as: :text,label: '拒绝理由:(拒绝时请填写拒绝理由,可以为空)', wrapper_html: { class: 'col-md-12' }, input_html: { maxlength: 100, size: 40, class: 'col-md-11' , value: @identity_verification.description } %> + <%= f.input :description, as: :text,label: '拒绝理由:(拒绝时请填写拒绝理由,不可以为空)', wrapper_html: { class: 'col-md-12' }, input_html: { maxlength: 100, size: 40, class: 'col-md-11' , value: @identity_verification.description } %>
<%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4' %> diff --git a/app/views/admins/issues_rank/index.html.erb b/app/views/admins/issues_rank/index.html.erb new file mode 100644 index 000000000..45ef1e6d2 --- /dev/null +++ b/app/views/admins/issues_rank/index.html.erb @@ -0,0 +1,37 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('疑修排行榜', admins_path) %> +<% end %> + + +
+ <%= form_tag(admins_issues_rank_index_path, method: :get, class: 'form-inline search-form flex-1', id: 'issue-rank-date-form') do %> +
+ 开始日期 + +
+
+ 截止日期 + +
+ <% end %> +
+ +
+ <%= render partial: 'admins/issues_rank/shared/data_list', locals: { statistics: @statistics } %> +
+ \ No newline at end of file diff --git a/app/views/admins/issues_rank/index.js.erb b/app/views/admins/issues_rank/index.js.erb new file mode 100644 index 000000000..189206df0 --- /dev/null +++ b/app/views/admins/issues_rank/index.js.erb @@ -0,0 +1 @@ +$('.issue-rank-list-container').html("<%= j( render partial: 'admins/issues_rank/shared/data_list', locals: { statistics: @statistics } ) %>"); \ No newline at end of file diff --git a/app/views/admins/issues_rank/shared/_data_list.html.erb b/app/views/admins/issues_rank/shared/_data_list.html.erb new file mode 100644 index 000000000..9512028c3 --- /dev/null +++ b/app/views/admins/issues_rank/shared/_data_list.html.erb @@ -0,0 +1,26 @@ + + + + + + + + + + + + <% statistics.each_with_index do |item, index| %> + + + + + + + + <% end %> + +
排名项目新增疑修数关闭疑修数当前疑修数量
<%= index + 1%> + "> + <%= "#{item&.project&.owner&.real_name}/#{item&.project&.name}" %> + + <%= item&.issues %><%= item&.closed_issues %><%= item&.project&.issues&.issue_issue.count %>
\ No newline at end of file diff --git a/app/views/admins/laboratories/index.html.erb b/app/views/admins/laboratories/index.html.erb index 8811f4ab3..adf34d6f4 100644 --- a/app/views/admins/laboratories/index.html.erb +++ b/app/views/admins/laboratories/index.html.erb @@ -1,5 +1,5 @@ <% define_admin_breadcrumbs do %> - <% add_admin_breadcrumb('云上实验室') %> + <% add_admin_breadcrumb('导航栏配置') %> <% end %>
diff --git a/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb b/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb index 0a77477d3..77ec0bd8b 100644 --- a/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb +++ b/app/views/admins/laboratories/shared/_create_laboratory_modal.html.erb @@ -2,7 +2,7 @@