diff --git a/Gemfile b/Gemfile
index d573a4cc2..41c3e1394 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,4 +1,5 @@
-source 'https://gems.ruby-china.com'
+#source 'https://gems.ruby-china.com'
+source 'https://mirrors.cloud.tencent.com/rubygems/'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 5.2.0'
@@ -139,4 +140,4 @@ gem 'doorkeeper'
gem 'doorkeeper-jwt'
-gem 'gitea-client', '~> 0.11.1'
\ No newline at end of file
+gem 'gitea-client', '~> 0.11.6'
\ No newline at end of file
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 4a104129b..0d1660a0f 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -213,6 +213,7 @@ class AccountsController < ApplicationController
def change_password
@user = User.find_by(login: params[:login])
+ return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691
return render_error("未找到相关用户!") if @user.blank?
return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
diff --git a/app/controllers/admins/projects_rank_controller.rb b/app/controllers/admins/projects_rank_controller.rb
new file mode 100644
index 000000000..c4f968da4
--- /dev/null
+++ b/app/controllers/admins/projects_rank_controller.rb
@@ -0,0 +1,16 @@
+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)
+ end
+
+ private
+
+ def rank_date
+ params.fetch(:date, Date.today.to_s)
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/admins/users_rank_controller.rb b/app/controllers/admins/users_rank_controller.rb
new file mode 100644
index 000000000..2c7a62ae5
--- /dev/null
+++ b/app/controllers/admins/users_rank_controller.rb
@@ -0,0 +1,15 @@
+class Admins::UsersRankController < Admins::BaseController
+
+ def index
+ @rank_date = rank_date
+ @date_rank = $redis_cache.zrevrange("v2-user-rank-#{rank_date}", 0, -1, withscores: true)
+ end
+
+ private
+
+ def rank_date
+ params.fetch(:date, Date.today.to_s)
+ 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 bc4919616..0c89f6012 100644
--- a/app/controllers/api/v1/projects/branches_controller.rb
+++ b/app/controllers/api/v1/projects/branches_controller.rb
@@ -1,16 +1,40 @@
class Api::V1::Projects::BranchesController < Api::V1::BaseController
- before_action :require_public_and_member_above, only: [:all]
+ 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)
+ end
def all
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
end
- before_action :require_operate_above, only: [:create]
+ before_action :require_operate_above, only: [:create, :destroy]
def create
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
end
+ def destroy
+ @result_object = Api::V1::Projects::Branches::DeleteService.call(@project, params[: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
+ @result_object = Api::V1::Projects::Branches::UpdateDefaultBranchService.call(@project, params[:name], current_user&.gitea_token)
+ if @result_object
+ return render_ok
+ else
+ return render_error('更新默认分支失败!')
+ end
+ end
+
private
def branch_params
params.require(:branch).permit(:new_branch_name, :old_branch_name)
diff --git a/app/controllers/api/v1/projects/tags_controller.rb b/app/controllers/api/v1/projects/tags_controller.rb
new file mode 100644
index 000000000..06c3b1c8e
--- /dev/null
+++ b/app/controllers/api/v1/projects/tags_controller.rb
@@ -0,0 +1,19 @@
+class Api::V1::Projects::TagsController < Api::V1::BaseController
+ before_action :require_public_and_member_above, only: [:index]
+
+ 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)
+ end
+
+ before_action :require_operate_above, only: [:destroy]
+
+ def destroy
+ @result_object = Api::V1::Projects::Tags::DeleteService.call(@project, params[:name], current_user&.gitea_token)
+ if @result_object
+ return render_ok
+ else
+ return render_error('删除标签失败!')
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7490cb27f..8129df8f1 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,4 +1,6 @@
require 'oauth2'
+# require 'openssl'
+# require 'jwt'
class ApplicationController < ActionController::Base
include CodeExample
@@ -295,17 +297,24 @@ class ApplicationController < ActionController::Base
# Find the current user
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
if request.headers["Authorization"].present? && request.headers["Authorization"].start_with?('Bearer')
- tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
- if @doorkeeper_token.present?
- # client方法对接,需要一直带着用户标识uid
- if @doorkeeper_token.resource_owner_id.blank?
- tip_exception(-1, "缺少用户标识!") if params[:uid].nil?
- User.current = User.find(params[:uid])
- else
- User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
+ if !valid_doorkeeper_token?
+ header = request.authorization
+ pattern = /^Bearer /i
+ token = header.gsub(pattern, "")
+ User.current, message = Bot.decode_jwt_token(token)
+ tip_exception(401, message) if message.present?
+ else
+ if @doorkeeper_token.present?
+ # client方法对接,需要一直带着用户标识uid
+ if @doorkeeper_token.resource_owner_id.blank?
+ tip_exception(-1, "缺少用户标识!") if params[:uid].nil?
+ User.current = User.find(params[:uid])
+ else
+ User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
+ end
end
end
- else
+ else
User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
diff --git a/app/controllers/concerns/api/project_helper.rb b/app/controllers/concerns/api/project_helper.rb
index 52967e784..44cac08c7 100644
--- a/app/controllers/concerns/api/project_helper.rb
+++ b/app/controllers/concerns/api/project_helper.rb
@@ -6,7 +6,8 @@ module Api::ProjectHelper
repo = params[:repo]
@project, @owner = Project.find_with_namespace(namespace, repo)
-
+ @repository = @project&.repository
+
if @project
logger.info "###########:project founded"
@project
diff --git a/app/controllers/installations_controller.rb b/app/controllers/installations_controller.rb
new file mode 100644
index 000000000..20dd25e40
--- /dev/null
+++ b/app/controllers/installations_controller.rb
@@ -0,0 +1,67 @@
+class InstallationsController < ApplicationController
+ include RegisterHelper
+ before_action :require_login
+
+ def index
+ @install_bots = BotInstall.where(:installer_id => current_user.id)
+ end
+
+ def update_secret
+ ActiveRecord::Base.transaction do
+ bot = Bot.find params[:id]
+ application = Doorkeeper::Application.find_by(uid: bot.client_id, secret: bot.client_secret)
+ bot.client_secret = Doorkeeper::OAuth::Helpers::UniqueToken.generate
+ bot.save!
+ application.secret = bot.client_secret
+ application.save!
+ render_ok
+ end
+ end
+
+ def update_private_key
+ bot = Bot.find params[:id]
+ bot.private_key = OpenSSL::PKey::RSA::generate(2048).to_s
+ bot.save!
+ render_ok
+ end
+
+ def auth_active
+ begin
+ @bot = Bot.find params[:id]
+ tip_exception("该Bot已激活") if Doorkeeper::Application.find_by(uid: @bot.client_id, secret: @bot.client_secret).present?
+ @bot.client_id = Doorkeeper::OAuth::Helpers::UniqueToken.generate if params[:client_id].blank?
+ @bot.client_secret = Doorkeeper::OAuth::Helpers::UniqueToken.generate if params[:client_secret].blank?
+ @bot.private_key = OpenSSL::PKey::RSA::generate(2048).to_s
+ @bot.owner_id = current_user.id
+ ActiveRecord::Base.transaction do
+ # 注册bot对应oauth应用
+ Doorkeeper::Application.create!(name: @bot.name, uid: @bot.client_id, secret: @bot.client_secret, redirect_uri: "https://gitlink.org.cn")
+ # 注册bot对应用户
+ result = autologin_register(User.generate_user_login('b'), nil, "#{SecureRandom.hex(6)}", 'bot', nickname: @bot.name)
+ tip_exception(-1, result[:message]) if result[:message].present?
+ @bot.uid = result[:user][:id]
+ @bot.save
+ render_ok
+ end
+ rescue Exception => e
+ tip_exception(-1, e.message)
+ end
+ end
+
+ def access_tokens
+ @install_bot = BotInstall.find params[:id]
+ @bot = @install_bot.bot
+ @application = Doorkeeper::Application.find_by(uid: @bot.client_id, secret: @bot.client_secret)
+ tip_exception("该Bot未激活") if @application.blank?
+ # 给bot生成token,因为bot是机器人操作
+ @access_token = Doorkeeper::AccessToken.create!({ :application_id => @application.id,
+ :resource_owner_id => @bot.uid,
+ :scopes => "public write",
+ :expires_in => "604800",
+ :use_refresh_token => true
+ })
+ render_ok(token: @access_token.token)
+ end
+
+end
+
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index ddb0facdf..efc7d3ea4 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -154,6 +154,8 @@ class IssuesController < ApplicationController
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
+ # 新增时向grimoirelab推送事件
+ IssueWebhookJob.set(wait: 5.seconds).perform_later(@issue.id)
render json: {status: 0, message: "创建成功", id: @issue.id}
else
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 53f6d1aea..52c776477 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -53,7 +53,7 @@ class ProjectsController < ApplicationController
ActiveRecord::Base.transaction do
Projects::CreateForm.new(project_params).validate!
@project = Projects::CreateService.new(current_user, project_params).call
- OpenProjectDevOpsJob.perform_later(@project&.id, current_user.id)
+ OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(@project&.id, current_user.id)
end
rescue Exception => e
uid_logger_error(e.message)
diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb
index 69491282d..c98174777 100644
--- a/app/helpers/repositories_helper.rb
+++ b/app/helpers/repositories_helper.rb
@@ -213,5 +213,12 @@ module RepositoriesHelper
def tmp_dir
"repo"
end
-
+
+ def repo_git_submodule_url(owner, repo, path)
+ unless (path.starts_with?('http://') || path.starts_with?('https://'))
+ path = File.expand_path(path, "/#{owner&.login}/#{repo&.identifier}")
+ end
+
+ return path
+ end
end
diff --git a/app/jobs/issue_webhook_job.rb b/app/jobs/issue_webhook_job.rb
new file mode 100644
index 000000000..4027a55b2
--- /dev/null
+++ b/app/jobs/issue_webhook_job.rb
@@ -0,0 +1,186 @@
+class IssueWebhookJob < ApplicationJob
+ include ApplicationHelper
+ queue_as :message
+
+ def perform(issue_id)
+ issue = Issue.find_by(id: issue_id)
+ return if issue.blank?
+ project = issue.project
+ user = issue.user
+ domain = "#{Rails.application.config_for(:configuration)['platform_url']}"
+ gitea_domain = GiteaService.gitea_config[:domain]
+ ssh_url = "git@#{gitea_domain.gsub("https://", "")}:#{project.owner.login}/#{project.identifier}.git"
+ event_json = {
+ "action": "opened",
+ "number": 1,
+ "issue": {
+ "id": issue.id,
+ "url": "#{domain}/api/v1/#{project.owner.login}/#{project.identifier}/issues/#{issue.id}",
+ "html_url": "#{domain}/#{project.owner.login}/#{project.identifier}/issues/#{issue.id}",
+ "number": 1,
+ "user": {
+ "id": user.id,
+ "login": "#{user.login}",
+ "full_name": "",
+ "email": "#{user.mail}",
+ "avatar_url": "#{domain}/#{url_to_avatar(user)}",
+ "language": "",
+ "is_admin": false,
+ "last_login": "#{user.last_login_on}",
+ "created": "#{user.created_on}",
+ "restricted": false,
+ "active": false,
+ "prohibit_login": false,
+ "location": "",
+ "website": "",
+ "description": "",
+ "visibility": "public",
+ "followers_count": 0,
+ "following_count": 0,
+ "starred_repos_count": 0,
+ "username": "#{user.login}"
+ },
+ "original_author": "",
+ "original_author_id": 0,
+ "title": "#{issue.subject}",
+ "body": "#{issue.description}",
+ "ref": "",
+ "labels": [],
+ "milestone": nil,
+ "assignee": nil,
+ "assignees": nil,
+ "state": "open",
+ "is_locked": false,
+ "comments": 0,
+ "created_at": "#{issue.created_on}",
+ "updated_at": "#{issue.updated_on}",
+ "closed_at": nil,
+ "due_date": nil,
+ "pull_request": nil,
+ "repository": {
+ "id": 11307,
+ "name": "#{project.identifier}",
+ "owner": "#{project.owner.login}",
+ "full_name": "#{project.owner.login}/#{project.identifier}"
+ }
+ },
+ "repository": {
+ "id": project.id,
+ "owner": {
+ "id": project.owner.id,
+ "login": "#{project.owner.login}",
+ "full_name": "",
+ "email": "#{project.owner.mail}",
+ "avatar_url": "#{domain}/#{url_to_avatar(project.owner)}",
+ "language": "",
+ "is_admin": false,
+ "last_login": "#{project.owner.last_login_on}",
+ "created": "#{project.owner.created_on}",
+ "restricted": false,
+ "active": false,
+ "prohibit_login": false,
+ "location": "",
+ "website": "",
+ "description": "",
+ "visibility": "public",
+ "followers_count": 0,
+ "following_count": 0,
+ "starred_repos_count": 0,
+ "username": "#{project.owner.login}"
+ },
+ "name": "#{project.identifier}",
+ "full_name": "#{project.owner.login}/#{project.identifier}",
+ "description": "",
+ "empty": false,
+ "private": false,
+ "fork": false,
+ "template": false,
+ "parent": nil,
+ "mirror": false,
+ "size": 843,
+ "html_url": "#{domain}/#{project.owner.login}/#{project.identifier}",
+ "ssh_url": "#{ssh_url}",
+ "clone_url": "#{domain}/#{project.owner.login}/#{project.identifier}.git",
+ "original_url": "#{project.repository.mirror_url}",
+ "website": "",
+ "stars_count": 0,
+ "forks_count": 0,
+ "watchers_count": 1,
+ "open_issues_count": 1,
+ "open_pr_counter": 0,
+ "release_counter": 0,
+ "default_branch": "master",
+ "archived": false,
+ "created_at": "#{project.created_on}",
+ "updated_at": "#{project.updated_on}",
+ "permissions": {
+ "admin": true,
+ "push": true,
+ "pull": true
+ },
+ "has_issues": true,
+ "internal_tracker": {
+ "enable_time_tracker": true,
+ "allow_only_contributors_to_track_time": true,
+ "enable_issue_dependencies": true
+ },
+ "has_wiki": true,
+ "has_pull_requests": true,
+ "has_projects": false,
+ "ignore_whitespace_conflicts": false,
+ "allow_merge_commits": true,
+ "allow_rebase": true,
+ "allow_rebase_explicit": true,
+ "allow_squash_merge": true,
+ "default_merge_style": "merge",
+ "avatar_url": "",
+ "internal": false,
+ "mirror_interval": ""
+ },
+ "sender": {
+ "id": user.id,
+ "login": "#{user.login}",
+ "full_name": "",
+ "email": "#{user.mail}",
+ "avatar_url": "#{domain}/#{url_to_avatar(user)}",
+ "language": "",
+ "is_admin": false,
+ "last_login": "#{user.last_login_on}",
+ "created": "#{user.created_on}",
+ "restricted": false,
+ "active": false,
+ "prohibit_login": false,
+ "location": "",
+ "website": "",
+ "description": "",
+ "visibility": "public",
+ "followers_count": 0,
+ "following_count": 0,
+ "starred_repos_count": 0,
+ "username": "#{user.login}"
+ }
+ }
+ # puts "event_json:#{event_json.to_json}"
+ begin
+ url = URI("http://117.50.185.50:80")
+ http = Net::HTTP.new(url.host, url.port)
+ request = Net::HTTP::Post.new(url)
+ request["Content-Type"] = "application/json"
+ uuid = SecureRandom.uuid
+ request['X-GitHub-Delivery'] = uuid
+ request['X-Gitea-Delivery'] = uuid
+ request['X-Gogs-Delivery'] = uuid
+ request['X-GitHub-Event'] = 'issues'
+ request['X-Gitea-Event'] = 'issues'
+ request['X-Gogs-Event'] = 'issues'
+ request.body = JSON.dump(event_json)
+
+ response = http.request(request)
+ Rails.logger.info "issue #{issue_id} webhook event======#{response.read_body}"
+ rescue Exception => e
+ Rails.logger.info "issue #{issue_id} webhook event error======#{e.message}"
+ puts "issue: #{issue_id} webhook event error======#{e.message}"
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/app/jobs/migrate_remote_repository_job.rb b/app/jobs/migrate_remote_repository_job.rb
index 5e56901a0..696607ae3 100644
--- a/app/jobs/migrate_remote_repository_job.rb
+++ b/app/jobs/migrate_remote_repository_job.rb
@@ -15,7 +15,7 @@ class MigrateRemoteRepositoryJob < ApplicationJob
## open jianmu devops
project_id = repo&.project&.id
puts "############ mirror project_id,user_id: #{project_id},#{user_id} ############"
- OpenProjectDevOpsJob.perform_later(project_id, user_id) if project_id.present? && user_id.present?
+ OpenProjectDevOpsJob.set(wait: 5.seconds).perform_later(project_id, user_id) if project_id.present? && user_id.present?
puts "############ mirror status: #{repo.mirror.status} ############"
else
repo&.mirror&.failed!
diff --git a/app/models/bot.rb b/app/models/bot.rb
new file mode 100644
index 000000000..2098ac1e2
--- /dev/null
+++ b/app/models/bot.rb
@@ -0,0 +1,51 @@
+# == Schema Information
+#
+# Table name: bot
+#
+# id :integer not null, primary key
+# bot_name :string(255)
+# bot_des :text(4294967295)
+# webhook :string(255)
+# is_public :integer
+# logo :string(255)
+# state :integer
+# client_id :string(255)
+# client_secret :string(255)
+# web_url :string(255)
+# category :string(255)
+# install_num :integer default("0")
+# update_time :datetime not null
+# create_time :datetime not null
+# private_key :text(65535)
+# uid :integer
+# owner_id :integer
+#
+# Indexes
+#
+# name (bot_name) UNIQUE
+#
+
+class Bot < ApplicationRecord
+ self.table_name = "bot"
+
+ has_many :install_bots
+
+ def name
+ self.bot_name
+ end
+
+ def self.decode_jwt_token(token)
+ decoded_token = JWT.decode token, nil, false
+ return [nil, "Token已过期"] if Time.now.to_i - 60 - decoded_token[0]["exp"].to_i > 0
+ bot = Bot.find_by(id: decoded_token[0]["iss"])
+ return [nil, "Token不存在"] if bot.blank?
+ rsa_private = OpenSSL::PKey::RSA.new(bot.private_key)
+ rsa_public = rsa_private.public_key
+ JWT.decode token, rsa_public, true, { algorithm: 'RS256' }
+ [User.find_by(id: bot.owner_id), ""]
+ rescue JWT::DecodeError
+ Rails.logger.error "jwt token decode error:#{token}"
+ [nil, "无效Token"]
+ end
+
+end
diff --git a/app/models/bot_install.rb b/app/models/bot_install.rb
new file mode 100644
index 000000000..d5283c131
--- /dev/null
+++ b/app/models/bot_install.rb
@@ -0,0 +1,20 @@
+# == Schema Information
+#
+# Table name: install_bot
+#
+# id :integer not null, primary key
+# bot_id :integer not null
+# installer_id :integer not null
+# store_id :integer not null
+# state :integer not null
+# create_time :datetime not null
+# update_time :datetime not null
+#
+
+# frozen_string_literal: true
+
+class BotInstall < ApplicationRecord
+ self.table_name = "install_bot"
+ belongs_to :bot
+
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index a8816bd76..e1670bf53 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -188,7 +188,7 @@ class Project < ApplicationRecord
forked_project = self.forked_from_project
if forked_project.present?
forked_project.decrement(:forked_count, 1)
- forked_project.update_column(:forked_count, forked_project.forked_count)
+ forked_project.update_attribute(:forked_count, forked_project.forked_count)
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index df35f3a2f..b43e289ed 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -114,7 +114,7 @@ class User < Owner
# trustie: 来自Trustie平台
# forge: 平台本身注册的用户
# military: 军科的用户
- enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat], default: :forge, scope: :shallow
+ enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat, :bot], default: :forge, scope: :shallow
belongs_to :laboratory, optional: true
has_one :user_extension, dependent: :destroy
diff --git a/app/queries/projects/list_query.rb b/app/queries/projects/list_query.rb
index 447ab5070..6b0843540 100644
--- a/app/queries/projects/list_query.rb
+++ b/app/queries/projects/list_query.rb
@@ -11,21 +11,19 @@ class Projects::ListQuery < ApplicationQuery
end
def call
- collection = Project.visible
- # 增加私有组织中项目过滤
- collection = collection.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id")
- .where("organization_extensions.visibility is null or organization_extensions.visibility in (0,1)")
- .where("projects.user_id > 0")
+ collection = main_collection
collection = filter_projects(collection)
sort = params[:sort_by] || "updated_on"
sort_direction = params[:sort_direction] || "desc"
collection = optimize_sorting(collection, sort) if params[:category_id].present?
- custom_sort(collection, sort, sort_direction)
-
- # scope = scope.reorder("projects.#{sort} #{sort_direction}")
- # scope
+ # 如果有搜索关键字根据ES搜索结果排序
+ if params[:search].present? && @ids.present?
+ collection.reorder(Arel.sql("FIELD(projects.id,#{@ids.join(',')})"))
+ else
+ custom_sort(collection, sort, sort_direction)
+ end
end
def filter_projects(collection)
@@ -37,15 +35,25 @@ class Projects::ListQuery < ApplicationQuery
collection
end
+ def main_collection
+ collection = Project.visible
+ # 增加私有组织中项目过滤
+ collection = collection.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id")
+ .where("organization_extensions.visibility is null or organization_extensions.visibility in (0,1)")
+ .where("projects.user_id > 0")
+ collection
+ end
+
def by_search(items)
- ids = Projects::ElasticsearchService.call(params[:search])
+ @ids = Projects::ElasticsearchService.call(params[:search])
items = items.where(platform: 'forge')
- if ids.present?
- items = items.where(id: ids).by_name_or_identifier(params[:search])
+ if @ids.present?
+ # items = items.where(id: @ids).by_name_or_identifier(params[:search])
+ items = items.where(id: @ids)
else
- items = items.by_name_or_identifier(params[:search])
+ items = items.by_name_or_identifier(params[:search]).or(main_collection.where(user_id: Owner.like(params[:search]).pluck(:id)))
end
- items.or(items.where(user_id: Owner.like(params[:search]).pluck(:id)))
+ items
end
def by_project_type(items)
@@ -78,5 +86,14 @@ class Projects::ListQuery < ApplicationQuery
relations
end
end
-
+
+ def by_recommend(items)
+ params[:recommend].to_s == "true" ? items.where(recommend: true) : items
+ end
+
+ def exclude_fork(items)
+ return items if params[:exclude_forked].blank?
+ params[:exclude_forked].to_s == "true" ? items.where("forked_from_project_id is null") : items.where("forked_from_project_id is not null")
+ end
+
end
diff --git a/app/services/api/v1/projects/branches/create_service.rb b/app/services/api/v1/projects/branches/create_service.rb
index 2837dfcf4..eae3779f8 100644
--- a/app/services/api/v1/projects/branches/create_service.rb
+++ b/app/services/api/v1/projects/branches/create_service.rb
@@ -18,7 +18,7 @@ class Api::V1::Projects::Branches::CreateService < ApplicationService
def call
raise Error, errors.full_messages.join(",") unless valid?
- check_new_branch_exist
+ check_branch_exist
excute_data_to_gitea
gitea_data
@@ -43,9 +43,10 @@ class Api::V1::Projects::Branches::CreateService < ApplicationService
raise Error, '创建分支失败!' unless @gitea_data.is_a?(Hash)
end
- def check_new_branch_exist
+ def check_branch_exist
result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params}) rescue nil
raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
- raise Error, '分支已存在!' if result['branch_name'].include?(@new_branch_name)
+ raise Error, '旧分支不存在!' if !result['branch_name'].include?(@old_branch_name)
+ raise Error, '新分支已存在!' if result['branch_name'].include?(@new_branch_name)
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
new file mode 100644
index 000000000..79a6ba0db
--- /dev/null
+++ b/app/services/api/v1/projects/branches/delete_service.rb
@@ -0,0 +1,47 @@
+class Api::V1::Projects::Branches::DeleteService < ApplicationService
+ include ActiveModel::Model
+
+ attr_accessor :project, :token, :owner, :repo, :branch_name
+ attr_accessor :gitea_data
+
+ validates :branch_name, presence: true
+
+ def initialize(project, branch_name, token=nil)
+ @project = project
+ @owner = project&.owner.login
+ @repo = project&.identifier
+ @branch_name = branch_name
+ @token = token
+ end
+
+ def call
+ raise Error, errors.full_messages.join(",") unless valid?
+
+ check_branch_exist
+ excute_data_to_gitea
+
+ true
+ end
+
+ private
+ def request_params
+ {
+ access_token: token
+ }
+ end
+
+ def excute_data_to_gitea
+ begin
+ @gitea_data = $gitea_client.delete_repos_branches_by_owner_repo_branch(owner, repo, branch_name, {query: request_params})
+ rescue => e
+ raise Error, '保护分支无法删除!' if e.to_s.include?("branch protected")
+ raise Error, '删除分支失败!'
+ end
+ end
+
+ def check_branch_exist
+ result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params}) rescue nil
+ raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
+ raise Error, '分支不存在!' if !result['branch_name'].include?(@branch_name)
+ end
+end
\ No newline at end of file
diff --git a/app/services/api/v1/projects/branches/list_service.rb b/app/services/api/v1/projects/branches/list_service.rb
new file mode 100644
index 000000000..e5c6fe442
--- /dev/null
+++ b/app/services/api/v1/projects/branches/list_service.rb
@@ -0,0 +1,40 @@
+class Api::V1::Projects::Branches::ListService < ApplicationService
+
+ attr_accessor :project, :token, :owner, :repo, :name, :page, :limit
+ attr_accessor :gitea_data
+
+ def initialize(project, params, token=nil)
+ @project = project
+ @owner = project&.owner.login
+ @repo = project&.identifier
+ @token = token
+ @name = params[:name]
+ @page = params[:page]
+ @limit = params[:limit]
+ end
+
+ def call
+ load_gitea_data
+
+ gitea_data
+ end
+
+ private
+ def request_params
+ params = {
+ access_token: token,
+ page: page,
+ limit: limit
+ }
+ params.merge!({name: name}) if name.present?
+
+ params
+ end
+
+ def load_gitea_data
+ puts request_params
+ @gitea_data = $gitea_client.get_repos_branches_by_owner_repo(owner, repo, {query: request_params}) rescue nil
+ puts @gitea_data
+ 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/update_default_branch_service.rb b/app/services/api/v1/projects/branches/update_default_branch_service.rb
new file mode 100644
index 000000000..5c220aa5d
--- /dev/null
+++ b/app/services/api/v1/projects/branches/update_default_branch_service.rb
@@ -0,0 +1,55 @@
+class Api::V1::Projects::Branches::UpdateDefaultBranchService < ApplicationService
+ include ActiveModel::Model
+
+ attr_accessor :project, :token, :owner, :repo, :new_default_branch
+ attr_accessor :gitea_data
+
+ validates :new_default_branch, presence: true
+
+ def initialize(project, new_default_branch, token=nil)
+ @project = project
+ @owner = project&.owner.login
+ @repo = project&.identifier
+ @new_default_branch = new_default_branch
+ @token = token
+ end
+
+ def call
+ raise Error, errors.full_messages.join(",") unless valid?
+
+ check_branch_exist
+ update_project
+ excute_data_to_gitea
+
+ gitea_data
+ end
+
+ private
+ def request_params
+ {
+ access_token: token
+ }
+ end
+
+ def request_body
+ {
+ default_branch: new_default_branch
+ }
+ end
+
+ def update_project
+ @project.attributes = request_body
+ raise Error, '更新默认分支失败!' unless @project.save
+ end
+
+ def excute_data_to_gitea
+ @gitea_data = $gitea_client.patch_repos_by_owner_repo(owner, repo, {body: request_body.to_json, query: request_params}) rescue nil
+ raise Error, '更新默认分支失败!' unless @gitea_data.is_a?(Hash)
+ end
+
+ def check_branch_exist
+ result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params}) rescue nil
+ raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
+ raise Error, '新默认分支不存在!' if !result['branch_name'].include?(@new_default_branch)
+ end
+end
\ No newline at end of file
diff --git a/app/services/api/v1/projects/code_stats/list_service.rb b/app/services/api/v1/projects/code_stats/list_service.rb
index 84f4bac36..a5e330e21 100644
--- a/app/services/api/v1/projects/code_stats/list_service.rb
+++ b/app/services/api/v1/projects/code_stats/list_service.rb
@@ -1,6 +1,6 @@
class Api::V1::Projects::CodeStats::ListService < ApplicationService
- attr_reader :project, :ref, :owner, :repo, :token
+ attr_reader :project, :ref, :owner, :repo, :token, :page, :limit
attr_accessor :gitea_data
def initialize(project, params, token=nil)
diff --git a/app/services/api/v1/projects/tags/delete_service.rb b/app/services/api/v1/projects/tags/delete_service.rb
new file mode 100644
index 000000000..492898b53
--- /dev/null
+++ b/app/services/api/v1/projects/tags/delete_service.rb
@@ -0,0 +1,47 @@
+class Api::V1::Projects::Tags::DeleteService < ApplicationService
+ include ActiveModel::Model
+
+ attr_accessor :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
+ @token = token
+ end
+
+ def call
+ raise Error, errors.full_messages.join(",") unless valid?
+
+ check_tag_exist
+ excute_data_to_gitea
+
+ true
+ end
+
+ private
+ def request_params
+ {
+ access_token: token
+ }
+ end
+
+ def excute_data_to_gitea
+ begin
+ @gitea_data = $gitea_client.delete_repos_tags_by_owner_repo_tag(owner, repo, tag_name, {query: request_params})
+ rescue => e
+ raise Error, '请先删除发行版!' if e.to_s.include?("409")
+ raise Error, '删除标签失败!'
+ end
+ end
+
+ def check_tag_exist
+ result = $gitea_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/api/v1/projects/tags/list_service.rb b/app/services/api/v1/projects/tags/list_service.rb
new file mode 100644
index 000000000..a7743fe00
--- /dev/null
+++ b/app/services/api/v1/projects/tags/list_service.rb
@@ -0,0 +1,36 @@
+class Api::V1::Projects::Tags::ListService < ApplicationService
+
+ attr_accessor :project, :token, :owner, :repo, :page, :limit
+ attr_accessor :gitea_data
+
+ def initialize(project, params, token=nil)
+ @project = project
+ @owner = project&.owner.login
+ @repo = project&.identifier
+ @token = token
+ @page = params[:page]
+ @limit = params[:limit]
+ end
+
+ def call
+ load_gitea_data
+
+ gitea_data
+ end
+
+ private
+ def request_params
+ params = {
+ access_token: token,
+ page: page,
+ limit: limit
+ }
+
+ params
+ end
+
+ def load_gitea_data
+ @gitea_data = $gitea_client.get_repos_tags_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/users/update_email_service.rb b/app/services/api/v1/users/update_email_service.rb
index bd1b5723c..9418cac6f 100644
--- a/app/services/api/v1/users/update_email_service.rb
+++ b/app/services/api/v1/users/update_email_service.rb
@@ -18,6 +18,7 @@ class Api::V1::Users::UpdateEmailService < ApplicationService
end
def call
+ raise Error, "此用户禁止修改邮箱." if @user.id.to_i === 104691
raise Error, errors.full_messages.join(",") unless valid?
raise Error, "密码不正确." unless @user.check_password?(@password)
exist_owner = Owner.find_by(mail: @mail)
@@ -31,6 +32,7 @@ class Api::V1::Users::UpdateEmailService < ApplicationService
change_user_email
excute_data_to_gitea
excute_change_email_from_gitea
+ remove_old_cache_for_user
end
return gitea_data
@@ -68,4 +70,8 @@ class Api::V1::Users::UpdateEmailService < ApplicationService
$gitea_client.delete_user_emails({body: {emails: [@old_mail]}.to_json, query: request_params})
$gitea_client.post_user_emails({body: {emails: [@mail]}.to_json, query: request_params})
end
+
+ def remove_old_cache_for_user
+ $redis_cache.del("v2-owner-common:#{@user.login}-#{@old_mail}")
+ end
end
\ No newline at end of file
diff --git a/app/services/api/v1/users/update_phone_service.rb b/app/services/api/v1/users/update_phone_service.rb
index e41178e3d..ed53d7eb5 100644
--- a/app/services/api/v1/users/update_phone_service.rb
+++ b/app/services/api/v1/users/update_phone_service.rb
@@ -15,6 +15,7 @@ class Api::V1::Users::UpdatePhoneService < ApplicationService
end
def call
+ raise Error, "此用户禁止修改手机号." if @user.id.to_i === 104691
raise Error, errors.full_messages.join(",") unless valid?
raise Error, "密码不正确." unless @user.check_password?(@password)
exist_owner = Owner.find_by(phone: @phone)
diff --git a/app/services/cache/v2/project_date_rank_service.rb b/app/services/cache/v2/project_date_rank_service.rb
index 9d8ffca90..9df69bbb4 100644
--- a/app/services/cache/v2/project_date_rank_service.rb
+++ b/app/services/cache/v2/project_date_rank_service.rb
@@ -28,6 +28,10 @@ class Cache::V2::ProjectDateRankService < ApplicationService
"v2-project-rank-#{@rank_date.to_s}"
end
+ def project_rank_statistic_key
+ "v2-project-statistic:#{@project_id}-#{@rank_date.to_s}"
+ end
+
def project_rank
$redis_cache.zscore(project_rank_key, @project_id)
end
@@ -35,26 +39,37 @@ class Cache::V2::ProjectDateRankService < ApplicationService
def set_project_rank
if @visits.present?
$redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id)
+ $redis_cache.hincrby(project_rank_statistic_key, "visits", @visits.to_i)
end
if @watchers.present?
$redis_cache.zincrby(project_rank_key, @watchers.to_i * 5, @project_id)
+ $redis_cache.hincrby(project_rank_statistic_key, "watchers", @watchers.to_i)
end
if @praises.present?
$redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id)
+ $redis_cache.hincrby(project_rank_statistic_key, "praises", @praises.to_i)
end
if @forks.present?
$redis_cache.zincrby(project_rank_key, @forks.to_i * 10, @project_id)
+ $redis_cache.hincrby(project_rank_statistic_key, "forks", @forks.to_i)
end
if @issues.present?
$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 @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)
end
if @commits.present?
$redis_cache.zincrby(project_rank_key, @commits.to_i * 5, @project_id)
+ $redis_cache.hincrby(project_rank_statistic_key, "commits", @commits.to_i)
end
$redis_cache.zscore(project_rank_key, @project_id)
+
+ # 设置过期时间(一个月)
+ $redis_cache.expireat(project_rank_key, (@rank_date+30.days).to_time.to_i)
+ $redis_cache.expireat(project_rank_statistic_key, (@rank_date+30.days).to_time.to_i)
end
end
\ No newline at end of file
diff --git a/app/services/cache/v2/user_date_rank_service.rb b/app/services/cache/v2/user_date_rank_service.rb
index a3351b724..b669e4d67 100644
--- a/app/services/cache/v2/user_date_rank_service.rb
+++ b/app/services/cache/v2/user_date_rank_service.rb
@@ -115,5 +115,9 @@ class Cache::V2::UserDateRankService < ApplicationService
$redis_cache.zadd(user_rank_key, score-300, @user_id) if score > 300
$redis_cache.zscore(user_rank_key, @user_id)
+
+ # 设置过期时间(一个月)
+ $redis_cache.expireat(user_rank_key, (@rank_date+30.days).to_time.to_i)
+ $redis_cache.expireat(user_date_statistic_key, (@rank_date+30.days).to_time.to_i)
end
end
\ No newline at end of file
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 837775d36..f8b38df47 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -29,7 +29,7 @@ class Projects::ForkService < ApplicationService
ProjectUnit.init_types(clone_project.id)
- @project.update_column('forked_count', @project&.forked_count.to_i + 1)
+ @project.update_attribute('forked_count', @project&.forked_count.to_i + 1)
new_repository.update_column('url', result['clone_url']) if result
ForkUser.create(project_id: @project.id, fork_project_id: clone_project.id, user_id: clone_project.user_id)
diff --git a/app/views/admins/projects_rank/index.html.erb b/app/views/admins/projects_rank/index.html.erb
new file mode 100644
index 000000000..056e0a0da
--- /dev/null
+++ b/app/views/admins/projects_rank/index.html.erb
@@ -0,0 +1,74 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('项目排行榜', admins_path) %>
+<% end %>
+
+
+
+
+
+
+
+
+ 排名 |
+ 项目 |
+ 得分 |
+ 访问数 |
+ 关注数 |
+ 点赞数 |
+ fork数 |
+ 疑修数 |
+ 合并请求数 |
+ 提交数 |
+
+
+
+ <% @date_rank.each_with_index do |item, index| %>
+
+ <%= index + 1%> |
+ <% project_common = $redis_cache.hgetall("v2-project-common:#{item[0]}") %>
+ <% owner_common = $redis_cache.hgetall("v2-owner-common:#{project_common["owner_id"]}")%>
+
+ /<%= project_common["identifier"]%>">
+ <%= project_common["name"] %>
+
+ |
+
+ <%= item[1] %> |
+ <% project_date_statistic_key = "v2-project-statistic:#{item[0]}-#{@rank_date}"%>
+ <% if $redis_cache.exists(project_date_statistic_key)%>
+ <% visits = $redis_cache.hget(project_date_statistic_key, "visits") %>
+ <%= visits || 0 %> |
+ <% watchers = $redis_cache.hget(project_date_statistic_key, "watchers") %>
+ <%= watchers || 0 %> |
+ <% praises = $redis_cache.hget(project_date_statistic_key, "praises") %>
+ <%= praises || 0 %> |
+ <% forks = $redis_cache.hget(project_date_statistic_key, "forks") %>
+ <%= forks || 0 %> |
+ <% issues = $redis_cache.hget(project_date_statistic_key, "issues") %>
+ <%= issues || 0 %> |
+ <% pullrequests = $redis_cache.hget(project_date_statistic_key, "pullrequests") %>
+ <%= pullrequests || 0 %> |
+ <% commits = $redis_cache.hget(project_date_statistic_key, "commits") %>
+ <%= commits || 0 %> |
+ <% else %>
+ 暂无数据 |
+ <% end %>
+
+ <% end %>
+
+
+
+
\ No newline at end of file
diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb
index afd0dad68..fb96f088e 100644
--- a/app/views/admins/shared/_sidebar.html.erb
+++ b/app/views/admins/shared/_sidebar.html.erb
@@ -14,6 +14,12 @@
- <%= sidebar_item(admins_path, '概览', icon: 'dashboard', controller: 'admins-dashboards') %>
+ -
+ <%= sidebar_item_group('#user-submenu', '排行榜', icon: 'user') do %>
+
- <%= sidebar_item(admins_users_rank_index_path, '用户排行榜', icon: 'user', controller: 'admins-users_rank') %>
+ - <%= sidebar_item(admins_projects_rank_index_path, '项目排行榜', icon: 'user', controller: 'admins-projects_rank') %>
+ <% end %>
+
-
<%= sidebar_item_group('#user-submenu', '用户', icon: 'user') do %>
- <%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users') %>
diff --git a/app/views/admins/users_rank/index.html.erb b/app/views/admins/users_rank/index.html.erb
new file mode 100644
index 000000000..9fa5a5aec
--- /dev/null
+++ b/app/views/admins/users_rank/index.html.erb
@@ -0,0 +1,74 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('用户排行榜', admins_path) %>
+<% end %>
+
+
+
+
+
+
+
+
+ 排名 |
+ 用户 |
+ 得分 |
+ 影响力 |
+ 贡献度 |
+ 活跃度 |
+ 项目经验 |
+ 语言能力 |
+
+
+
+ <% @date_rank.each_with_index do |item, index| %>
+
+ <%= index + 1%> |
+ <% owner_common = $redis_cache.hgetall("v2-owner-common:#{item[0]}")%>
+
+ ">
+ <%= owner_common["name"] %>
+
+ |
+ <% user_date_statistic_key = "v2-user-statistic:#{item[0]}-#{@rank_date}"%>
+ <% follow_count = $redis_cache.hget(user_date_statistic_key, "follow-count") || 0 %>
+ <% pullrequest_count = $redis_cache.hget(user_date_statistic_key, "pullrequest-count") || 0 %>
+ <% issues_count = $redis_cache.hget(user_date_statistic_key, "issue-count") || 0 %>
+ <% project_count = $redis_cache.hget(user_date_statistic_key, "project-count") || 0 %>
+ <% fork_count = $redis_cache.hget(user_date_statistic_key, "fork-count") || 0 %>
+ <% project_watchers_count = $redis_cache.hget(user_date_statistic_key, "project-watcher-count") || 0 %>
+ <% project_praises_count = $redis_cache.hget(user_date_statistic_key, "project-praise-count") || 0 %>
+ <% project_language = $redis_cache.hget(user_date_statistic_key, "project-language") %>
+ <% project_languages_count = project_language.nil? || project_language == "{}" ? 0 : JSON.parse(project_language).length %>
+
+ <% influence = (60.0 + follow_count.to_i / (follow_count.to_i + 20.0) * 40.0).to_i %>
+ <% contribution = (60.0 + pullrequest_count.to_i / (pullrequest_count.to_i + 20.0) * 40.0).to_i %>
+ <% activity = (60.0 + issues_count.to_i / (issues_count.to_i + 80.0) * 40.0).to_i %>
+ <% experience = 10 * project_count.to_i + 5 * fork_count.to_i + project_watchers_count.to_i + project_praises_count.to_i %>
+ <% experience = (60.0 + experience / (experience + 100.0) * 40.0).to_i %>
+ <% language = (60.0 + project_languages_count.to_i / (project_languages_count.to_i + 5.0) * 40.0).to_i %>
+ <% score = influence+ contribution + activity + experience + language%>
+ <%= score %> |
+ <%= influence%> |
+ <%= contribution%> |
+ <%= activity%> |
+ <%= experience%> |
+ <%= language%> |
+
+ <% end %>
+
+
+
+
\ No newline at end of file
diff --git a/app/views/api/v1/projects/branches/_simple_gitea_detail.json.jbuilder b/app/views/api/v1/projects/branches/_simple_gitea_detail.json.jbuilder
index 70fac8238..6a35b782e 100644
--- a/app/views/api/v1/projects/branches/_simple_gitea_detail.json.jbuilder
+++ b/app/views/api/v1/projects/branches/_simple_gitea_detail.json.jbuilder
@@ -18,7 +18,7 @@ json.protected branch['protected']
json.user_can_push branch['user_can_push']
json.user_can_merge branch['user_can_merge']
json.commit_id branch['commit_id']
-json.commit_time_from_now time_from_now(branch['commit_time'].to_time)
+json.commit_time_from_now time_from_now(branch['commit']['timestamp'].to_time)
json.commit_time branch['commit_time']
json.default_branch branch['default_branch']
json.http_url render_http_url(@project)
diff --git a/app/views/api/v1/projects/branches/index.json.jbuilder b/app/views/api/v1/projects/branches/index.json.jbuilder
new file mode 100644
index 000000000..cfb9bb647
--- /dev/null
+++ b/app/views/api/v1/projects/branches/index.json.jbuilder
@@ -0,0 +1,4 @@
+json.total_count @result_object[:total_data].to_i
+json.branches @result_object[:data].each do |branch|
+ json.partial! "api/v1/projects/branches/simple_gitea_detail", branch: branch
+end
\ No newline at end of file
diff --git a/app/views/api/v1/projects/tags/_simple_gitea_index_detail.json.jbuilder b/app/views/api/v1/projects/tags/_simple_gitea_index_detail.json.jbuilder
new file mode 100644
index 000000000..b8ba28f85
--- /dev/null
+++ b/app/views/api/v1/projects/tags/_simple_gitea_index_detail.json.jbuilder
@@ -0,0 +1,26 @@
+if tag.present? && tag.is_a?(Hash)
+ json.name tag['name']
+ json.id tag['id']
+ json.zipball_url render_zip_url(@owner, @repository, tag['name'])
+ json.tarball_url render_tar_url(@owner, @repository, tag['name'])
+ json.tagger do
+ json.partial! 'api/v1/users/commit_user', user: render_cache_commit_author(tag['tagger']), name: tag['tagger']['name']
+ end
+ json.time_ago time_from_now(tag['tagger']['date'].to_time)
+ json.created_at_unix tag['tagger']['date'].to_time.to_i
+ json.message tag['message']
+ json.commit do
+ json.sha tag['commit']['sha']
+ json.message tag['commit']['message']
+ json.time_ago time_from_now(tag['commit']['commiter']['date'].to_time)
+ json.created_at_unix tag['commit']['commiter']['date'].to_time.to_i
+ json.committer do
+ json.partial! 'api/v1/users/commit_user', user: render_cache_commit_author(tag['commit']['commiter']), name: tag['commit']['commiter']['name']
+ end
+ json.author do
+ json.partial! 'api/v1/users/commit_user', user: render_cache_commit_author(tag['commit']['author']), name: tag['commit']['author']['name']
+ end
+ end
+else
+ json.name tag
+end
\ No newline at end of file
diff --git a/app/views/api/v1/projects/tags/index.json.jbuilder b/app/views/api/v1/projects/tags/index.json.jbuilder
new file mode 100644
index 000000000..207289041
--- /dev/null
+++ b/app/views/api/v1/projects/tags/index.json.jbuilder
@@ -0,0 +1,5 @@
+json.total_count @result_object[:total_data].to_i
+json.tags @result_object[:data].each do |tag|
+ json.partial! "api/v1/projects/tags/simple_gitea_index_detail", tag: tag
+ json.has_release @release_tags.blank? ? false : @release_tags.include?(tag['name'])
+end
\ No newline at end of file
diff --git a/app/views/installations/index.json.jbuilder b/app/views/installations/index.json.jbuilder
new file mode 100644
index 000000000..b2f674f20
--- /dev/null
+++ b/app/views/installations/index.json.jbuilder
@@ -0,0 +1,7 @@
+json.status 0
+json.message "success"
+json.data do
+ json.array! @install_bots do |install_bot|
+ json.extract! install_bot.bot, :id, :name
+ end
+end
\ No newline at end of file
diff --git a/app/views/repositories/_simple_entry.json.jbuilder b/app/views/repositories/_simple_entry.json.jbuilder
index 8adcaeb83..aae0e613c 100644
--- a/app/views/repositories/_simple_entry.json.jbuilder
+++ b/app/views/repositories/_simple_entry.json.jbuilder
@@ -1,13 +1,14 @@
if @project.forge?
is_dir = @sub_entries.is_a?(Array)
file_name = entry['name']
- file_type = File.extname(file_name.to_s)[1..-1]
+ file_type = file_name.starts_with?('.') ? file_name[1..-1] : File.extname(file_name.to_s)[1..-1]
direct_download = file_name.to_s.downcase != "Makefile".downcase && download_type(file_type)
image_type = image_type?(file_type)
json.name file_name
json.sha entry['sha']
json.path entry['path']
json.type entry['type']
+ json.submodule_git_url entry['submodule_git_url'].nil? ? nil : repo_git_submodule_url(@owner, @repository, entry['submodule_git_url'])
json.size entry['size']
is_readme = is_readme?(entry['type'], entry['name'])
if is_readme
diff --git a/app/views/repositories/entries.json.jbuilder b/app/views/repositories/entries.json.jbuilder
index 6dea93b32..c86219785 100644
--- a/app/views/repositories/entries.json.jbuilder
+++ b/app/views/repositories/entries.json.jbuilder
@@ -51,6 +51,7 @@ if @project.forge?
json.path entry['path']
json.sha entry['sha']
json.type entry['type']
+ json.submodule_git_url entry['submodule_git_url'].nil? ? nil : repo_git_submodule_url(@owner, @repository, entry['submodule_git_url'])
json.size entry['size']
json.is_readme_file is_readme?(entry['type'], entry['name'])
json.content decode64_content(entry, @owner, @repository, @ref, @path)
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 2a2355c6d..0cc9a02a4 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -18,7 +18,7 @@ Doorkeeper.configure do
User.authenticate!(params[:username], params[:password])
end
- access_token_generator '::Doorkeeper::JWT'
+ # access_token_generator '::Doorkeeper::JWT'
admin_authenticator do
user = current_user
diff --git a/config/routes.rb b/config/routes.rb
index 22773794c..3d6cc8f55 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -761,6 +761,8 @@ Rails.application.routes.draw do
get :visits_static
end
end
+ resources :users_rank, only: [:index]
+ resources :projects_rank, only: [:index]
resources :sites
resources :edu_settings
resources :project_languages
@@ -1045,6 +1047,19 @@ Rails.application.routes.draw do
resources :commit_logs, :only => [:create]
+ scope '/app' do
+ post ':id/auth_active', to: 'installations#auth_active'
+ post ':id/update_private_key', to: 'installations#update_private_key'
+ post ':id/update_secret', to: 'installations#update_secret'
+ resources :installations do
+ get :repositories, on: :collection
+ member do
+ post :access_tokens
+ put :suspended
+ end
+ end
+ end
+
root 'main#index'
diff --git a/config/routes/api.rb b/config/routes/api.rb
index 7e9504401..31127c7bf 100644
--- a/config/routes/api.rb
+++ b/config/routes/api.rb
@@ -48,11 +48,17 @@ defaults format: :json do
get :hooktasks
end
end
- resources :branches, only:[:index, :create] do
+ resources :branches, param: :name, only:[:index, :create, :destroy] do
collection do
- get :all
+ get :all
+ patch :update_default_branch
end
end
+ match 'branches/*name', to: "branches#destroy", via: :all
+
+ resources :tags, param: :name, only: [:index, :destroy]
+ match 'tags/*name', to: "tags#destroy", via: :all
+
resources :commits, only: [:index]
resources :code_stats, only: [:index]
get '/commits/:sha/diff', to: 'commits#diff'
diff --git a/db/migrate/20230214000021_add_bot_info.rb b/db/migrate/20230214000021_add_bot_info.rb
new file mode 100644
index 000000000..5e8d11b52
--- /dev/null
+++ b/db/migrate/20230214000021_add_bot_info.rb
@@ -0,0 +1,9 @@
+class AddBotInfo < ActiveRecord::Migration[5.2]
+ def change
+ if table_exists? :bot
+ add_column :bot, :private_key, :text, comment: "私钥"
+ add_column :bot, :owner_id, :integer, comment: "所有者ID"
+ add_column :bot, :uid, :integer, comment: "Bot机器人用户ID"
+ end
+ end
+end
diff --git a/test/jwt_test.rb b/test/jwt_test.rb
new file mode 100644
index 000000000..8d0faaa3f
--- /dev/null
+++ b/test/jwt_test.rb
@@ -0,0 +1,42 @@
+require 'openssl'
+require 'jwt' # https://rubygems.org/gems/jwt
+
+# Private key contents
+private_pem = File.read("/Users/xxq/Documents/gitlink-webhook.2022-06-09.private-key.pem")
+
+private_key22="-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEApOebWmRV/ooNq5Ks04YnDU7pEezGShGvaiF0cIvn9jvmYHu0\nFialojvJV3VpB6xE6QBPXZ0Pi1lokZ9dMx8F5UWNx9WA7wf7xK3hAJLNml+GeewF\nou8vk/Ry7n6diLxETNVd7YzPvztn5qaMp/DXa+65i11H8a/XXqR7kCVnCevVlufh\nNr/Dp6dW31W8TInnDQasJFMZ8GY7f+tCwLXNc0M8p+TeDp9xmXHOrEB+S/mgbUOF\nXgRr6icbMmlT9bsAxYHrrDkcVxJhs0hq5vD3BaoK06gcZEnN7/HVNzgVSOYNsVNh\n9006cMgDSOwc9F8aulP7cr8k74INq1xswoGs9wIDAQABAoIBAHayc2NkF3YJXv+h\nqx7yUEfHBgKuAKiuBCqLfCnKuqPFx/So9h5/oPeeuzVlwL0SJePlIjuK4vZ128v9\n/vLeILtADmbJ6m2jvHh8hBmKkc3Ndplp50C5k/CWoufCYZhbk3oOlvZ3Rc4rb4VZ\nWqNDu3voMMv8z91KqeZo1LwUAA/l9mU++zLkRA6qOuWGBJFsM8YpshzxL5lzRUb3\n7y+YJDyUZztfzKwr6pqm1n9B2e6e+znCw1vMZXp2TbUrpvrrXSxlgdNuK68SkZX6\nTdZUD8y0viwaioRVf3vR+e/Bf7yZannGdvcmVGs0A7dq9QgHkakqNHiRkQgwviSq\nbjBo7dECgYEAzekeP5j/dAPkv9X4qnmZ4du/+ZgrQrJckDD/JuNIBmQT9m286l4P\nmb2TBcWkswVOZaS5Qy2bN/69rwIbcdvbaROGBCabn3ATK4fSzmUk31M2rRKYZqaU\nMi0W2g2YtSRg+bV6S7aFXa98j5+JlqJeDZQoRuvL68ooq5WzFWmfYnkCgYEAzQTi\n4USqz2z66BfU+v2rchzK8URxnv7EW/CG3XFRsG+1UXCyEIct2L7rzvC7r7+jjS4s\ngmV3Civ1sckGMwikLzxFtUZ1LUBakZp/mmipIzxcHOeBsRdHei8BFvMNqveg1JpO\ncY/Fp+wEkSNLhfkb/IXRw0iwFalBRnyo4BJbLu8CgYBrQ7E6OB169jxHotNzGv2K\npssO3rJKgFev1ZZVT7jJe4Dasrfi7zT5RcQ9EYSGrZD1aiYIVM2zEcUGUfayDXHy\n/vSlXOdc2ylhV9P9KLtYiyTEbBdwAf7ZVJu+465VTqol6t/WaTJ4Z15gAx/NlK+i\nKzgAGf2Uyy78k3NDCE67IQKBgFwM0pUUEKEbLDhi4uRiWsTcep4C/gTGHIGvJ85r\nH6NZNI7BS6GyH/qOFjAO1CYfpB4yWhed2Om/PQw61sa5HYZ7yEyQuvG7UC7JsHsy\nfKZuZmkv5IIPkq8gRZv5OuzFS/fI5GmGhNdVV+OWdkVLyK4Do1/L1guTt9QfCm+4\nrioPAoGBALGr8aUAbz/A611M/bLnk04UYfV+M34/hCf6/rKiBHdQoIHOriSC9Nv7\nyhE5axTdmIWMxfbyb3vHJ5MizZkD/Qj0VDuMkyS2+3TepI6tySQE3YQeWnCMJI9i\nuoCZ31GBui4+W5udbx8NOVsJfXUQn/OAoOn6WuMNPdgB45KXcktj\n-----END RSA PRIVATE KEY-----\n"
+private_key33= "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAq/wUH8N+5fzj3hArKY7ChC591R/uKyeNM/BbsR2OGxO5F1CE\nozy6thtPult96Gm9oK3sMpLdYCze2YgozgteFO1Ft0o1GEJ1A4SinOKzeixLpFy0\n5N9t+iz7Xa7jC/1E3uy/s2WvSYCS9NnK2Uj3DQOH8BUWfkvyTtt91a2pplbPCV3T\nw1PykAcDWIFXVJJCMtYd2x+DukSWKHRsYbBCMtVZhEVuKmTE3FBTDVu9sN3b7uLL\n5RzHUg13QZZr9OvMNR3nUZl6yDxw+wD4anDrtpL9C+tFjhMyqsyYpYWwcJm65YiD\ny7Ps24IdcLB4iOxJE91fu+MnicvyBrtEjoBP/wIDAQABAoIBAAcKc9x1CW3q8300\n1j+GS6pTqO0fuIVlwh8dOPPATQAIx6wPrM5t/wrThWkQs8/e/Fdmp2POpWd5jsoD\nDACbcIeUyyTc0d2jYtz5AhtAIK7gv1wEO5efGgaC7ut/7GWiQb6KnLKAeDOfIuUJ\nQYexuAN9YIRQqLIU89+MltM3n9liZTMuPWRFJcitaDytXa10TCe5RUqHGZf49pi7\njCgk0x7jDYqbIzsqOu741P8My/gkAjKPkRnjaj3o6MrwHzIlc4t/6mKbaPnywywk\n6roYMqmytgueA9wxFcj74ekBQAaXsu4xRkbZXxjcBtIvTId5IHHK5Z/r3fgE9K3J\nOuzzJ1kCgYEA3uu/pUjJbKegOsgSdu3cO/NvRV2YsRD4NUgtiMCEakE4VQXRK5pf\nV8xqQeH/rLjZf5aP5xe8n25krh/c+m0ezOMyu5MmhoxaWCPWIezsaKJXOcvsOxIu\n2sJ9GRMXabyuDuSdL7ZGYMpLhRclXYLyPCz7wzN445IluTHuD3lJ2qUCgYEAxYFh\ncVD73yNZn9BN1DSGWpfPtLqOKIdG+xi/ypCSGpJG0QCJRFi7R1qJOxFtJNI8DRiD\nZapPEGLVd/KY5NzBGZBfNQt4DQH9qR4l43c6NNkisWA9rvXvCDqXKmBq7wfpnkYr\n4Ul2hXYmsPJjP8e0BfG54PaSu3BDBMJMtcgDktMCgYBvzyDdnwdgVyc3tHgGbMFk\n1HHAAfT/ArrrxpsIFz+TJ8lAY92JGDGwENhO2TLrCAAXTYY5657w/GbFKzgj5y1m\nqKIekOzm2WjLApZ5h6L/zEUhuRVwf2s+0AP82qWIpFlNIP9yGeNs0qpUQ8q6/13O\nLuXL/3on8nq3S8LSwgv3/QKBgDfM+g7d5ouAnU29uH9/54Wo5pIVMxzYO4Gt2GIO\nvnirYz6hfCbHOwJJ3gPGRKPmkfjROC59E6F5iv48mF3w0M28MGn4N47VRSmGzwWZ\nJeTQhDDBFCxeZ45Xn2Xln9Cw15xUDwmzi7zhSMUtdkUK0x3q0a1xfLtgWE775lhl\njjzpAoGAdUXFW1elfjXpfIYZf7vUV7MPquKL7qAcopd96XBszhOn7g+ibzem+wgt\n1UTSeOBESYANHeJk2MuWPSRXk/FlQETVIcPAEp0kxbwQE+7YEdrMVeDcIe5lPwGD\n+WuS3kg0MPgUrXZXn74gcwWmSIOyHfqXULqOxWE25uU2icdV+2w=\n-----END RSA PRIVATE KEY-----\n"
+private_key = OpenSSL::PKey::RSA.new(private_key33)
+# puts private_key.to_json
+
+# Generate the JWT
+payload = {
+ # issued at time, 60 seconds in the past to allow for clock drift
+ iat: Time.now.to_i - 60,
+ # JWT expiration time (10 minute maximum)
+ exp: Time.now.to_i + (10 * 60),
+ # GitHub App's identifier
+ iss: "782"
+}
+
+jwt = JWT.encode(payload, private_key, "RS256")
+puts jwt
+# puts OpenSSL::PKey::RSA.new(private_key33).public_key.to_s
+#
+rsa_private = OpenSSL::PKey::RSA.new(private_key33)
+rsa_public = rsa_private.public_key
+
+# decoded_token = JWT.decode jwt, nil, false
+begin
+ decoded_token = JWT.decode jwt, rsa_private, true, { algorithm: 'RS256' }
+rescue JWT::DecodeError
+ puts "jwt is not mmmmmm"
+end
+
+#
+puts decoded_token[0]
+puts decoded_token[0]["iss"]
+
+# serialized_private_key = OpenSSL::PKey::RSA::generate(2048).to_s
+
+