forgeplus/app/controllers/projects_controller.rb

430 lines
20 KiB
Ruby
Raw Permalink Normal View History

2020-03-09 00:40:16 +08:00
class ProjectsController < ApplicationController
include ApplicationHelper
include OperateProjectAbilityAble
2020-06-29 16:05:22 +08:00
include ProjectsHelper
2021-04-29 18:35:57 +08:00
include Acceleratorable
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]
2023-08-10 14:29:26 +08:00
before_action :require_profile_completed, only: [:create, :migrate,:page_migrate,: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]
2020-03-09 00:40:16 +08:00
before_action :authorizate_user_can_edit_project!, only: %i[update]
before_action :project_public?, only: %i[fork_users praise_users watch_users]
2023-06-08 11:25:03 +08:00
before_action :request_limit, only: %i[index]
2020-03-09 00:40:16 +08:00
2021-03-17 11:52:36 +08:00
def menu_list
menu = []
2022-05-05 10:00:02 +08:00
user_is_admin = current_user.admin? || @project.manager?(current_user)
2021-03-17 11:52:36 +08:00
menu.append(menu_hash_by_name("home"))
2021-03-28 19:56:11 +08:00
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code")
2021-03-17 11:52:36 +08:00
menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues")
2021-12-09 15:54:21 +08:00
menu.append(menu_hash_by_name("pulls")) if @project.has_menu_permission("pulls") && @project.forge?
menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") && @project.forge?
2024-04-01 15:24:34 +08:00
menu.append(menu_hash_by_name("dataset")) if @project.has_menu_permission("dataset") && @project.forge?
2021-03-17 11:52:36 +08:00
menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions")
2021-12-13 11:45:58 +08:00
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
menu.append(menu_hash_by_name("services")) if @project.has_menu_permission("services") && @project.forge? && (current_user.admin? || @project.member?(current_user.id))
2021-12-09 15:54:21 +08:00
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge?
2021-03-17 11:52:36 +08:00
menu.append(menu_hash_by_name("activity"))
2022-05-05 10:00:02 +08:00
menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge?
menu.append(menu_hash_by_name("quit")) if !user_is_admin && @project.member(current_user.id) && @project.forge?
2021-03-28 19:56:11 +08:00
2021-03-17 11:52:36 +08:00
render json: menu
end
2020-03-09 00:40:16 +08:00
def index
2021-09-07 17:19:38 +08:00
scope = current_user.logged? ? Projects::ListQuery.call(params, current_user.id) : Projects::ListQuery.call(params)
2020-04-22 13:37:15 +08:00
2024-06-06 10:04:30 +08:00
# scope = scope.joins(repository: :mirror).where.not(mirrors: {status: 2}) # 导入失败项目不显示
2023-03-21 15:37:26 +08:00
@projects = kaminari_paginate(scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units, :project_topics))
2021-10-27 14:20:27 +08:00
# @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)
2020-10-23 00:07:26 +08:00
category_id = params[:category_id]
@total_count =
if category_id.blank? && params[:search].blank? && params[:topic_id].blank? && params[:topic_name].blank?
# 默认查询时count性能问题处理
not_category_count = Project.where(project_category_id: nil).count
ProjectCategory.sum("projects_count") - Project.visible.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id").where("organization_extensions.visibility =2").count + not_category_count
elsif params[:search].present? || params[:topic_id].present? || params[:topic_name].present?
2022-11-08 17:18:04 +08:00
@projects.total_count
2020-10-23 00:07:26 +08:00
else
2023-06-08 11:25:03 +08:00
cate = ProjectCategory.find_by(id: category_id)
cate&.projects_count || 0
2020-10-23 00:07:26 +08:00
end
2020-03-09 00:40:16 +08:00
end
def create
ActiveRecord::Base.transaction do
Projects::CreateForm.new(project_params).validate!
@project = Projects::CreateService.new(current_user, project_params).call
OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(@project&.id, current_user.id)
UpdateProjectTopicJob.perform_later(@project.id) if @project.id.present?
2020-03-09 00:40:16 +08:00
end
rescue Gitea::Api::ServerError => ex
uid_logger_error(ex.message)
# tip_exception(ex.http_code, ex.message)
tip_exception(ex.message)
rescue ApplicationService::Error => e
2020-03-09 00:40:16 +08:00
uid_logger_error(e.message)
tip_exception(e.message)
end
2023-06-20 15:27:03 +08:00
def verify_auth_token
data = Projects::VerifyAuthTokenService.call(params[:clone_addr], params[:auth_token])
2023-06-20 15:50:11 +08:00
render_ok({data: data})
2023-06-20 15:27:03 +08:00
end
2020-03-09 00:40:16 +08:00
def migrate
2020-06-23 11:57:24 +08:00
Projects::MigrateForm.new(mirror_params).validate!
2021-04-29 18:35:57 +08:00
2023-06-08 11:25:03 +08:00
@project =
2022-02-14 16:53:29 +08:00
if EduSetting.get("mirror_address").to_s.include?("github") && enable_accelerator?(mirror_params[:clone_addr])
2021-04-29 18:35:57 +08:00
source_clone_url = mirror_params[:clone_addr]
2022-02-11 16:27:22 +08:00
uid_logger("########## 已动加速器 ##########")
result = Gitea::Accelerator::MigrateService.call(mirror_params)
if result[:status] == :success
Rails.logger.info "########## 加速镜像成功 ########## "
2023-06-08 11:25:03 +08:00
Projects::MigrateService.call(current_user,
mirror_params.merge(source_clone_url: source_clone_url,
clone_addr: accelerator_url(mirror_params[:repository_name])))
2022-02-11 16:27:22 +08:00
else
Projects::MigrateService.call(current_user, mirror_params)
end
2022-02-14 16:53:29 +08:00
elsif EduSetting.get("mirror_address").to_s.include?("cnpmjs") && mirror_params[:clone_addr].include?("github.com")
source_clone_url = mirror_params[:clone_addr]
clone_url = source_clone_url.gsub('github.com', 'github.com.cnpmjs.org')
uid_logger("########## 更改clone_addr ##########")
Projects::MigrateService.call(current_user, mirror_params.merge(source_clone_url: source_clone_url, clone_addr: clone_url))
2021-04-29 18:35:57 +08:00
else
Projects::MigrateService.call(current_user, mirror_params)
end
2020-03-09 00:40:16 +08:00
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
2023-08-10 14:29:26 +08:00
def page_migrate
return normal_status(-1, "您还未开通Page服务无法进行新建站点") unless current_user.id_card_verify
2023-08-24 17:21:26 +08:00
return normal_status(-1, "你已使用了 #{page_site_params[:identifier]} 作为page标识") if Page.exists?(identifier: page_site_params[:identifier], user: current_user)
2023-08-10 14:29:26 +08:00
Projects::MigrateForm.new(mirror_params).validate!
@project =
if EduSetting.get("mirror_address").to_s.include?("github") && enable_accelerator?(mirror_params[:clone_addr])
source_clone_url = mirror_params[:clone_addr]
uid_logger("########## 已动加速器 ##########")
result = Gitea::Accelerator::MigrateService.call(mirror_params)
if result[:status] == :success
Rails.logger.info "########## 加速镜像成功 ########## "
Projects::MigrateService.call(current_user,
mirror_params.merge(source_clone_url: source_clone_url,
clone_addr: accelerator_url(mirror_params[:repository_name])))
else
Projects::MigrateService.call(current_user, mirror_params)
end
elsif EduSetting.get("mirror_address").to_s.include?("cnpmjs") && mirror_params[:clone_addr].include?("github.com")
source_clone_url = mirror_params[:clone_addr]
clone_url = source_clone_url.gsub('github.com', 'github.com.cnpmjs.org')
uid_logger("########## 更改clone_addr ##########")
Projects::MigrateService.call(current_user, mirror_params.merge(source_clone_url: source_clone_url, clone_addr: clone_url))
else
Projects::MigrateService.call(current_user, mirror_params)
end
if @project.present?
page = Page.new page_site_params
page.user = current_user
page.project = @project
2023-08-17 14:13:38 +08:00
end
if page.save
render json: page
2023-08-10 14:29:26 +08:00
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
2020-03-09 00:40:16 +08:00
def branches
2021-03-28 19:56:11 +08:00
return @branches = [] unless @project.forge?
2022-01-07 15:41:50 +08:00
# result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
2022-04-26 17:15:59 +08:00
result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier, params[:name])
2023-06-08 11:25:03 +08:00
@branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result) : result
2020-03-09 00:40:16 +08:00
end
2021-09-07 18:39:11 +08:00
def branches_slice
return @branches = [] unless @project.forge?
slice_result = Gitea::Repository::Branches::ListSliceService.call(@owner, @project.identifier)
@branches_slice = slice_result.is_a?(Hash) && slice_result.key?(:status) ? [] : slice_result
end
2020-03-09 00:40:16 +08:00
def group_type_list
2020-10-21 11:45:55 +08:00
project_statics = ProjectStatistic.first
@project_statics_list = [
{
project_type: 'common',
name: '开源托管项目',
projects_count: project_statics&.common_projects_count || 0
},
{
project_type: 'mirror',
name: '开源镜像项目',
projects_count: project_statics&.mirror_projects_count || 0
}
]
# projects = Project.no_anomory_projects.visible
# @project_group_list = projects.group(:project_type).size
2020-03-09 00:40:16 +08:00
end
def update
ActiveRecord::Base.transaction do
2021-05-15 10:19:25 +08:00
# TODO:
# 临时特殊处理修改website、lesson_url操作方法
2023-06-08 11:25:03 +08:00
if project_params.has_key?("website")
2023-04-14 11:19:23 +08:00
if params[:project_topic_names].is_a?(Array)
ProjectTopicRalate.where(project: @project).destroy_all
params[:project_topic_names].each do |name|
project_topic = ProjectTopic.find_or_create_by!(name: name.downcase)
project_topic.project_topic_ralates.find_or_create_by!(project: @project)
end
end
2021-05-15 10:19:25 +08:00
@project.update(project_params)
elsif project_params.has_key?("default_branch")
@project.update(project_params)
gitea_params = {
default_branch: @project.default_branch
}
Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
2024-03-07 11:18:39 +08:00
elsif project_params.has_key?("has_actions")
gitea_params = {
has_actions: project_params[:has_actions]
}
Gitea::Repository::UpdateService.call(@owner, @project.identifier, gitea_params)
2021-05-15 10:19:25 +08:00
else
2023-06-08 11:25:03 +08:00
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!
2023-06-08 11:25:03 +08:00
2024-03-21 11:25:05 +08:00
private = params[:private].nil? ? !@project.is_public : params[:private]
private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : private
2021-05-15 10:19:25 +08:00
new_project_params = project_params.except(:private).merge(is_public: !private)
@project.update_attributes!(new_project_params)
fork_pull_requests = PullRequest.where(fork_project_id: @project.id)
if fork_pull_requests.present?
fork_pull_requests.update_all(fork_project_identifier: @project.identifier)
end
@project.forked_projects.map{|p| p.update!(is_public: @project.is_public)}
2021-05-15 10:19:25 +08:00
gitea_params = {
private: private,
default_branch: @project.default_branch,
2021-10-12 17:08:25 +08:00
website: @project.website,
name: @project.identifier
2021-05-15 10:19:25 +08:00
}
2021-10-12 17:15:50 +08:00
gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
2023-06-08 11:25:03 +08:00
@project.repository.update_attributes({ hidden: gitea_repo["private"], identifier: gitea_repo["name"] })
# 更新对应所属分类下的项目数量(私有)
before_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][0] : @project.is_public
after_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][1] : @project.is_public
before_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][0] : @project.project_category_id
after_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][1] : @project.project_category_id
before_pc = ProjectCategory.find_by_id(before_pc_id)
after_pc = ProjectCategory.find_by_id(after_pc_id)
before_pc.decrement!(:private_projects_count, 1) if before_pc.present? && !before_is_public
after_pc.increment!(:private_projects_count, 1) if after_pc.present? && !after_is_public
2020-03-09 00:40:16 +08:00
end
2021-10-21 11:23:12 +08:00
SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu?
2020-03-09 00:40:16 +08:00
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def show
end
def destroy
2021-03-30 17:27:50 +08:00
if current_user.admin? || @project.manager?(current_user)
2020-03-09 00:40:16 +08:00
ActiveRecord::Base.transaction do
2024-09-27 14:27:36 +08:00
UserAction.create(action_id: @project.id, action_type: "DestroyProject", user_id: current_user.id, :ip => request.remote_ip, data_bank: @project.attributes.to_json)
close_fork_pull_requests_by(@project)
2024-06-03 10:36:31 +08:00
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier,current_user.gitea_token).call
2020-03-09 00:40:16 +08:00
@project.destroy!
2021-06-29 18:05:37 +08:00
@project.forked_projects.update_all(forked_from_project_id: nil)
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
@project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public
2020-03-09 00:40:16 +08:00
render_ok
end
else
render_forbidden('你没有权限操作')
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
2020-05-07 18:27:19 +08:00
end
2020-03-09 00:40:16 +08:00
2022-05-05 10:00:02 +08:00
def quit
user_is_admin = current_user.admin? || @project.manager?(current_user)
2023-06-08 11:25:03 +08:00
if !user_is_admin && @project.member(current_user.id) && @project.forge?
2022-05-05 10:00:02 +08:00
ActiveRecord::Base.transaction do
Projects::DeleteMemberInteractor.call(@project.owner, @project, current_user)
SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, current_user.id, @project.id) if Site.has_notice_menu?
render_ok
end
2023-06-08 11:25:03 +08:00
else
2022-05-05 10:00:02 +08:00
render_forbidden('你不能退出该仓库')
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def watch_users
2024-11-07 11:44:26 +08:00
start_at = params[:start_at]
end_at = params[:end_at]
2020-06-08 09:55:54 +08:00
watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct
2024-11-07 11:44:26 +08:00
watchers = watchers.where("watchers.created_at > ? and watchers.created_at < ?", Time.at(start_at.to_i), Time.at(end_at.to_i)) if start_at.present? && end_at.present?
@watchers_count = watchers.size
@watchers = paginate(watchers)
end
2020-05-15 17:31:53 +08:00
def praise_users
2024-11-07 11:44:26 +08:00
start_at = params[:start_at]
end_at = params[:end_at]
2020-06-08 09:55:54 +08:00
praises = @project.praise_treads.includes(:user).order("praise_treads.created_at desc").distinct
2024-11-07 11:44:26 +08:00
praises = praises.where("praise_treads.created_at > ? and praise_treads.created_at < ?", Time.at(start_at.to_i), Time.at(end_at.to_i)) if start_at.present? && end_at.present?
@praises_count = praises.size
@praises = paginate(praises)
end
2020-06-03 11:18:46 +08:00
def fork_users
2022-05-07 11:57:58 +08:00
fork_users = @project.fork_users.includes(:owner, :project, :fork_project).order("fork_users.created_at desc").distinct
@forks_count = fork_users.size
@fork_users = paginate(fork_users)
end
2020-06-29 16:05:22 +08:00
def simple
2024-06-03 10:36:31 +08:00
if !@project.common? && @project&.repository&.mirror&.waiting?
2024-09-05 09:18:07 +08:00
gitea_result = $gitea_client.get_repos_by_owner_repo(@project&.owner&.login, @project&.identifier) rescue nil
if gitea_result.present? && !gitea_result["empty"]
2024-06-03 10:36:31 +08:00
@project&.update_columns(gpid: gitea_result["id"])
@project&.repository&.mirror&.succeeded!
project_id = @project&.id
user_id = @project&.owner&.id
2024-06-03 17:45:34 +08:00
Rails.logger.info "############ mirror project_id,user_id: #{project_id},#{user_id} ############"
2024-06-03 10:36:31 +08:00
OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(project_id, user_id) if project_id.present? && user_id.present?
UpdateProjectTopicJob.set(wait: 1.seconds).perform_later(project_id) if project_id.present?
2024-06-03 17:45:34 +08:00
Rails.logger.info "############ mirror status: #{@project&.repository&.mirror&.status} ############"
2024-06-03 10:36:31 +08:00
end
elsif !@project.common? && @project&.repository&.mirror&.failed?
# 导入失败的项目标记 project.status=0, 在列表中不显示
@project&.update_columns(status: 0) if @project&.status == 1
# Rails.logger.info "############ mirror status: #{@project&.repository&.mirror&.status}"
# Gitea::Repository::DeleteService.new(@project.owner, @project.identifier,current_user.gitea_token).call
# @project.destroy!
# @project.forked_projects.update_all(forked_from_project_id: nil)
# # 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
# @project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public
2024-06-05 15:48:26 +08:00
# return render_error("导入失败,请重试!")
2024-06-03 17:45:34 +08:00
end
2021-10-26 15:22:42 +08:00
# 为了缓存活跃项目的基本信息,后续删除
2021-11-01 16:20:52 +08:00
Cache::V2::ProjectCommonService.new(@project.id).read
# 项目名称,标识,所有者变化时重置缓存
project_common = $redis_cache.hgetall("v2-project-common:#{@project.id}")
if project_common.present?
if project_common["name"] != @project.name || project_common["identifier"] != @project.identifier || project_common["owner_id"] != @project.user_id
Cache::V2::ProjectCommonService.new(@project.id).reset
end
end
json_response(@project, current_user)
2020-06-29 16:05:22 +08:00
end
2020-10-04 12:01:26 +08:00
def recommend
2021-06-04 11:33:21 +08:00
@projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc)
2020-10-04 12:01:26 +08:00
end
2021-10-27 14:20:27 +08:00
def banner_recommend
@projects = Project.recommend.where.not(recommend_index: 0).includes(:project_category, :owner, :project_language).order(recommend_index: :desc)
end
2020-10-04 17:32:37 +08:00
def about
@project_detail = @project.project_detail
@attachments = Array(@project_detail&.attachments) if request.get?
ActiveRecord::Base.transaction do
if request.post?
2020-10-09 11:40:20 +08:00
require_login
2020-10-04 17:32:37 +08:00
authorizate_user_can_edit_project!
unless @project_detail.present?
@project_detail = ProjectDetail.new(
content: params[:content],
project_id: @project.id)
else
@project_detail.content = params[:content]
end
if @project_detail.save!
attachment_ids = Array(params[:attachment_ids])
logger.info "=============> #{Array(params[:attachment_ids])}"
@attachments = Attachment.where(id: attachment_ids).or(Attachment.where(uuid: attachment_ids))
2020-10-04 17:32:37 +08:00
@attachments.update_all(
container_id: @project_detail.id,
container_type: @project_detail.model_name.name,
author_id: current_user.id,
description: "")
end
end
end
end
2020-08-12 10:38:45 +08:00
2020-03-09 00:40:16 +08:00
private
2023-06-08 11:25:03 +08:00
2020-03-09 00:40:16 +08:00
def project_params
2021-10-12 16:41:01 +08:00
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, :has_actions,
2023-05-30 14:46:15 +08:00
:blockchain, :blockchain_token_all, :blockchain_init_token, :pr_view_admin)
2020-03-09 00:40:16 +08:00
end
def mirror_params
2024-08-23 10:02:07 +08:00
params.permit(:user_id, :name, :description, :repository_name, :is_mirror, :auth_username, :auth_token, :service,
:auth_password, :project_category_id, :project_language_id, :clone_addr, :private)
2020-03-09 00:40:16 +08:00
end
2023-08-10 14:29:26 +08:00
def page_site_params
params.permit(:site_name, :identifier,:language_frame,:theme)
end
2020-06-03 11:18:46 +08:00
def project_public?
2020-08-12 10:58:16 +08:00
return if @project.is_public?
if current_user
return if current_user.admin? || @project.member?(current_user.id)
render_forbidden('你没有权限访问.')
else
render_unauthorized('你还未登录.')
end
end
def close_fork_pull_requests_by(project)
open_pull_requests = PullRequest.where(fork_project_id: project.id)
if open_pull_requests.present?
open_pull_requests.each do |pull_request|
closed = PullRequests::CloseService.call(pull_request&.project.owner, pull_request&.project.repository, pull_request, current_user)
if closed === true
pull_request.project_trends.create!(user: current_user, project: pull_request&.project,action_type: ProjectTrend::CLOSE)
# 合并请求下issue处理为关闭
pull_request.issue&.update_attributes!({status_id:5})
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, pull_request.id) if Site.has_notice_menu?
end
end
end
end
2020-03-09 00:40:16 +08:00
end