Compare commits

..

45 Commits

Author SHA1 Message Date
呱呱呱 9cf0a04455 11111 2025-07-30 17:30:33 +08:00
xxq250 41515575f1 add 流水线停止api 2025-07-29 10:33:56 +08:00
yystopf f4248ec14b fixed 2025-07-25 15:06:50 +08:00
yystopf 9544a5b22d fixed 2025-07-25 15:02:42 +08:00
yystopf 9cf4cc290c 更改:请求参数查询 2025-07-25 15:01:36 +08:00
yystopf e37d76d972 更改:请求参数查询 2025-07-25 14:58:08 +08:00
yystopf c18d1d2ce4 新增:组织项目查询路由 2025-07-25 14:53:03 +08:00
yystopf 40576e321f fixed 2025-07-25 14:50:27 +08:00
yystopf f9e7b92386 fixed 2025-07-25 14:48:50 +08:00
yystopf 40955f5a99 新增:组织下查询接口以及组织成员数 2025-07-25 14:46:21 +08:00
yystopf cece63286e 更改:排序正序倒序 2025-07-24 16:09:06 +08:00
yystopf debefe2e7c 新增:排序正序与倒序 2025-07-24 10:15:49 +08:00
yystopf ad2f42bed6 新增:排序正序与倒序 2025-07-24 10:13:43 +08:00
yystopf 473b9e3dfd 新增:负责人筛选 2025-07-24 09:59:45 +08:00
xxq250 655bb7bb4e add 敏感词调整 2025-07-23 13:55:15 +08:00
xxq250 da48040d2c Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-07-22 16:52:49 +08:00
xxq250 732a3a1405 add 敏感词调整 2025-07-22 16:52:42 +08:00
yystopf 31e4d73e2a 新增:周报时间筛选 2025-07-22 10:20:30 +08:00
xxq250 bd3dd5df4a add 敏感词调整 2025-07-21 15:16:13 +08:00
yystopf 85b55619c6 修复:最近提交文件数过多无法加载的问题 2025-07-18 21:08:28 +08:00
xxq250 9d968ac5db add 在线用户记录数单独显示 2025-07-18 14:59:27 +08:00
xxq250 a90bed0b8f add 在线用户记录,统计缓存取消 2025-07-18 14:20:29 +08:00
xxq250 4151b3564f add 在线用户记录,统计开关 2025-07-18 14:15:16 +08:00
xxq250 bff04758b8 add 在线用户记录,统计 2025-07-18 11:55:25 +08:00
xxq250 7f386622a3 add 在线用户记录,统计 2025-07-18 11:54:52 +08:00
xxq250 9d8600eb1c add 在线用户记录 2025-07-18 11:52:24 +08:00
xxq250 981dde45ef fixed 增加代码库文本内容显示敏感词检测3 2025-07-07 15:52:44 +08:00
xxq250 b02cf8fe79 fixed 增加代码库文本内容显示敏感词检测2 2025-07-07 15:47:13 +08:00
xxq250 44c8d0be7c fixed 增加代码库文本内容显示敏感词检测 2025-07-07 15:42:07 +08:00
xxq250 4afce7809d fixed 敏感词不显示,方法改为tip_exception 2025-07-07 15:26:48 +08:00
xxq250 10c05896fc fixed 敏感词不显示 2025-07-07 15:05:47 +08:00
xxq250 d260fcfe35 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-07-02 14:57:50 +08:00
xxq250 d286502224 fixed 用户搜组织增加名称模糊搜索 2025-07-02 14:57:44 +08:00
yystopf cabc9775bc 更改:导入同步项目失败处理 2025-07-02 14:56:27 +08:00
yystopf 8c9f6d6175 新增:同步github组织下项目 2025-07-01 16:19:15 +08:00
yystopf 0ae4f8decd Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2025-06-27 15:26:06 +08:00
yystopf a86372dc16 修复:周报报错 2025-06-27 15:25:59 +08:00
xxq250 3eebf61f03 fixed 项目表头像处理 2025-06-27 14:40:37 +08:00
xxq250 cf6dc3a9b4 fixed projects gpid 增加索引 2025-06-27 14:39:28 +08:00
yystopf 2a0ce2972a fixed: 返回错误跳转地址 2025-06-25 16:44:44 +08:00
yystopf 8cab37587e fixed: 返回错误跳转地址 2025-06-25 16:42:12 +08:00
yystopf 542fe0b60c fixed:同一方向pullrequest不允许存在 2025-06-25 16:12:58 +08:00
yystopf bb720d20c1 fixed:同一方向pullrequest不允许存在 2025-06-25 16:03:31 +08:00
KingChan 6bcdc20500 Merge pull request 'render pm_logo_url' (#402) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-25 10:02:06 +08:00
KingChan 991a421b67 Merge pull request 'laboratory pm logo' (#401) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-25 09:43:58 +08:00
30 changed files with 412 additions and 216 deletions

View File

@ -292,6 +292,7 @@ class AccountsController < ApplicationController
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
user.update_column(:last_login_on, Time.now)
session[:"#{default_yun_session}"] = user.id
UserOnline.login(user.id)
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
# 注册完成后有一天的试用申请(先去掉)
# UserDayCertification.create(user_id: user.id, status: 1)

View File

@ -67,9 +67,9 @@ class Admins::DashboardsController < Admins::BaseController
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]
@subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数", "在线用户数"]
@subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload", "fa-user"]
@subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count, UserOnline.count]
if EduSetting.get("open_baidu_tongji").to_s == "true"
tongji_service = Baidu::TongjiService.new

View File

@ -5,9 +5,11 @@ class Api::Pm::WeeklyIssuesController < Api::Pm::BaseController
return render_error('请输入正确的用户ID.') if params[:user_id].blank?
@all_issues = Issue.joins(:issue_participants).where(issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
@all_issues = @all_issues.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s).distinct
@weekly_begin_date = params[:weekly_begin_date].to_time || Date.today.beginning_of_week rescue Date.today.beginning_of_week
@weekly_end_date = params[:weekly_end_date].to_time || Date.today.end_of_week rescue Date.today.end_of_week
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", @weekly_begin_date.to_s, @weekly_end_date.to_s).distinct
@this_week_all_issues = @this_week_all_issues.order('created_on desc').pm_includes
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (Date.today.beginning_of_week+1.week).to_s, (Date.today.end_of_week+1.week).to_s).distinct
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (@weekly_begin_date+1.week).to_s, (@weekly_end_date+1.week).to_s).distinct
@next_week_all_issues = @next_week_all_issues.order('created_on desc').pm_includes
@this_week_requirement_issues = @this_week_all_issues.where(pm_issue_type: 1)
@this_week_task_issues = @this_week_all_issues.where(pm_issue_type: 2)
@ -27,7 +29,9 @@ class Api::Pm::WeeklyIssuesController < Api::Pm::BaseController
@enterprise_identifier = params[:enterprise_identifier] || ''
@all_issues = Issue.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
@all_issues = @all_issues.where(pm_project_id: params[:pm_project_ids].split(",")) if params[:pm_project_ids].present?
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s)
@weekly_begin_date = params[:weekly_begin_date] || Date.today.beginning_of_week.to_s
@weekly_end_date = params[:weekly_end_date] || Date.today.end_of_week.to_s
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", @weekly_begin_date, @weekly_end_date)
@this_week_all_issues_group_count = @this_week_all_issues.group(:pm_project_id).count
data = {}
@this_week_all_issues_group_count.keys.each do |pm_project_id|

View File

@ -37,6 +37,11 @@ class Api::V1::BaseController < ApplicationController
params.fetch(:page, 1)
end
def load_organization
@organization = Organization.find_by(login: params[:owner]) || Organization.find_by(id: params[:owner])
return render_not_found("组织不存在") if @organization.nil?
end
# 具有对仓库的管理权限
def require_manager_above
@project = load_project

View File

@ -0,0 +1,46 @@
class Api::V1::Organizations::ProjectsController < Api::V1::BaseController
before_action :load_organization
def index
public_projects_sql = @organization.projects.where(is_public: true).to_sql
private_projects_sql = @organization.projects
.where(is_public: false)
.joins(team_projects: {team: :team_users})
.where(team_users: {user_id: current_user.id}).to_sql
@projects = Project.from("( #{ public_projects_sql} UNION #{ private_projects_sql } ) AS projects")
# 表情处理
keywords = params[:search].to_s.each_char.select { |c| c.bytes.first < 240 }.join('')
@projects = @projects.where(is_public: params[:is_public]) if params[:is_public].present?
@projects = @projects.where(id: params[:pm_project_repository_ids].split(',')) if params[:pm_project_repository_ids].present?
@projects = @projects.where.not(id: params[:exclude_ids].to_s.split(",")) if params[:exclude_ids].present?
@projects = @projects.where(project_type: ['mirror', 'common']).where("gpid is not null") if params[:actived].present?
@projects = @projects.ransack(name_or_identifier_cont: keywords).result if params[:search].present?
@projects = @projects.includes(:owner).order("projects.#{sort} #{sort_direction}")
@projects = kaminari_paginate(@projects)
end
private
def load_organization
@organization = Organization.find_by(login: params[:owner]) || Organization.find_by(id: params[:owner])
return render_not_found("组织不存在") if @organization.nil?
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition
end
def org_limited_condition
@organization.organization_extension.limited? && !current_user.logged?
end
def org_privacy_condition
return false if current_user.admin?
@organization.organization_extension.privacy? && @organization.organization_users.where(user_id: current_user.id).blank?
end
def sort
Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'updated_on'
end
def sort_direction
%w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
end
end

View File

@ -0,0 +1,42 @@
class Api::V1::Organizations::SyncRepositoriesController < Api::V1::BaseController
before_action :load_organization, only: [:create]
def create
return render_error("请输入正确的外部组织login") unless params[:external_login].present?
# 拉取外部组织仓库列表
url = URI("https://api.github.com/orgs/#{params[:external_login]}/repos?page=#{params[:page]}&per_page=#{params[:limit]}")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer #{params[:external_token]}"
response = https.request(request)
if response.code == "200"
repos = JSON.parse(response.body)
repos.each do |repo|
# 检查是否已经存在该仓库
@project = @organization.projects.find_by(identifier: repo["name"])
if @project.present?
if @project.repository.mirror.failed?
@project.destroy!
mirror_params = {name: repo["name"], user_id: @organization.id, description: repo["description"], repository_name: repo["name"], auth_token: params[:external_token], clone_addr: repo["clone_url"]}
@project = ::Projects::MigrateService.call(current_user, mirror_params)
end
@project.update_column(:created_on, repo['created_at'].to_time)
@project.update_column(:updated_on, repo['updated_at'].to_time)
next
else
mirror_params = {name: repo["name"], user_id: @organization.id, description: repo["description"], repository_name: repo["name"], auth_token: params[:external_token], clone_addr: repo["clone_url"]}
@project = ::Projects::MigrateService.call(current_user, mirror_params)
@project.update_column(:created_on, repo['created_at'].to_time)
@project.update_column(:updated_on, repo['updated_at'].to_time)
end
end
end
end
private
def sync_repository_params
params.permit(:external_token)
end
end

View File

@ -58,4 +58,15 @@ class Api::V1::Projects::Actions::RunsController < Api::V1::Projects::Actions::B
redirect_to file_path
end
def cancel
return render_error("请输入正确的流水线记录ID") if params[:run_id].blank?
http = Gitea::Api::Hat::Http.new($gitea_hat_client.config)
gitea_result = http.post("/repos/#{@project&.owner&.login}/#{@project&.identifier}/actions/runs/#{params[:run_id]}/cancel") rescue nil
if gitea_result
render_ok
else
render_error("停止流水线任务失败")
end
end
end

View File

@ -14,11 +14,20 @@ class Api::V1::Projects::Pulls::PullsController < Api::V1::BaseController
end
def reopen
@result_object = Api::V1::Projects::Pulls::ReopenService.call(@project, @pull_request, current_user)
if @result_object
render_ok
can_merge = @project&.pull_requests.where(head: @pull_request.head, base: @pull_request.base, status: 0, is_original: @pull_request.is_original, fork_project_id: @pull_request.fork_project_id)
if can_merge.present?
render json: {
status: -1,
redirect_url:"/#{@project.owner.login}/#{@project.identifier}/pulls/#{can_merge.first.gitea_number}",
message: "在这些分支之间的合并请求已存在",
}
else
render_error("合并请求重新打开失败!")
@result_object = Api::V1::Projects::Pulls::ReopenService.call(@project, @pull_request, current_user)
if @result_object
render_ok
else
render_error("合并请求重新打开失败!")
end
end
end

View File

@ -330,20 +330,6 @@ class ApplicationController < ActionController::Base
User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
# # 开放课程通过链接访问的用户
# if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
# content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
#
# if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
# user = open_class_user
# if user
# start_user_session(user)
# set_autologin_cookie(user)
# end
# User.current = user
# end
# end
if !User.current.logged? && Rails.env.development?
user = User.find 1
User.current = user
@ -366,6 +352,7 @@ class ApplicationController < ActionController::Base
end
end
end
UserOnline.login(User.current.id)
# User.current = User.find 81403
end

View File

@ -33,6 +33,7 @@ class AttachmentsController < ApplicationController
Rails.logger.info("request.host===#{request.host},request.referer===#{request.referer}")
tip_exception(403, "你没有权限访问") if request.host.present? && !request.referer.to_s.include?(request.host.to_s.gsub("www.",""))
normal_status(-1, "参数缺失") if params[:download_url].blank?
tip_exception('不可访问') if params[:download_url].to_s.include?("chinese_dictionary.txt")
url = base_url.starts_with?("https:") ? params[:download_url].to_s.gsub("http:", "https:") : params[:download_url].to_s
md5_file = Digest::MD5.hexdigest(params[:download_url])
FileUtils.mkdir_p("#{Rails.root}#{EduSetting.get("attachment_folder")}gitea/") unless Dir.exists?("#{Rails.root}#{EduSetting.get("attachment_folder")}gitea/")

View File

@ -63,6 +63,7 @@ module LoginHelper
user.delete_autologin_token(autologin)
user.delete_session_token(session[:tk])
UserOnline.logout(User.current.id)
self.logged_user = nil
end

View File

@ -0,0 +1,47 @@
class Huawei::CodeArtsChecksController < ApplicationController
before_action :load_repository
before_action :signer
def index
task_id = "xxxxxx" # 创建任务返回的 task_id
url = "https://codearts-check.#{region}.myhuaweicloud.com/v2/#{project_id}/task/#{task_id}"
headers = @signer.sign_request("GET", url)
response = RestClient.get(url, headers)
puts JSON.pretty_generate(JSON.parse(response.body))
end
def create
branch = params[:branch] || "master"
project_id = @project.id
region = "cn-north-4"
url = "https://codearts-check.#{region}.myhuaweicloud.com/v2/#{project_id}/task"
body = {
"name":@project.name,
"project_id":project_id,
"git_url": @project.repository.url,
"branch": branch
}.to_json
headers = @signer.sign_request("POST", url, {}, body)
response = RestClient.post(url, body, headers)
puts JSON.pretty_generate(JSON.parse(response.body))
end
private
def signer
ak = ENV['HUAWEI_CLOUD_AK']
sk = ENV['HUAWEI_CLOUD_SK']
@signer = Huawei::Signer.new(ak, sk)
end
end

View File

@ -5,7 +5,7 @@ class MainController < ApplicationController
skip_before_action :setup_laboratory
def first_stamp
render :json => { status: 0, message: Time.now.to_i }
render :json => { status: 0, message: Time.now.to_i, online: UserOnline.count }
end
def test_404

View File

@ -84,7 +84,7 @@ class RepositoriesController < ApplicationController
def sub_entries
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
tip_exception('不可访问') if params[:filepath].to_s.include?("chinese_dictionary.txt")
if @project.educoder?
if params[:type] === 'file'
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
@ -307,6 +307,7 @@ class RepositoriesController < ApplicationController
def raw
domain = GiteaService.gitea_config[:domain]
api_url = GiteaService.gitea_config[:base_url]
tip_exception('不可访问') if params[:filepath].to_s.include?("chinese_dictionary.txt")
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{CGI.escape(params[:filepath])}?ref=#{CGI.escape(params[:ref])}"
file_path = [domain, api_url, url].join

View File

@ -9,7 +9,7 @@ class Users::OrganizationsController < Users::BaseController
@organizations = observed_user.organizations.with_visibility("common")
end
@organizations = @organizations.ransack(login_cont: params[:search]).result if params[:search].present?
@organizations = @organizations.ransack(login_or_nickname_cont: params[:search]).result if params[:search].present?
@home_top_ids = @organizations.joins(:home_top_settings).where(home_top_settings: {user_id: observed_user.id}).order("home_top_settings.created_at asc").pluck(:id)

View File

@ -244,7 +244,9 @@ module RepositoriesHelper
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = entry['content'].present? ? entry['content'] : Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
text = new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
text
end
def decode64_content(entry, owner, repo, ref, path=nil)
@ -253,9 +255,13 @@ module RepositoriesHelper
content = entry['content'].present? ? entry['content'] : Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
# Rails.logger.info("content===#{content}")
return Base64.decode64(content).force_encoding("GBK").encode("UTF-8") unless Base64.decode64(content).force_encoding('UTF-8').valid_encoding?
return Base64.decode64(content).force_encoding('UTF-8')
text = Base64.decode64(content).force_encoding('UTF-8')
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
text
elsif entry['is_text_file'] == true
return render_decode64_content(entry['content'])
text = render_decode64_content(entry['content'])
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
text
else
file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type)
@ -264,7 +270,9 @@ module RepositoriesHelper
if download_type(file_type)
return entry['content']
end
render_decode64_content(entry['content'])
text = render_decode64_content(entry['content'])
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
text
end
end

89
app/libs/user_online.rb Normal file
View File

@ -0,0 +1,89 @@
module UserOnline
class << self
redis_config = YAML.load_file(Rails.root.join('config', 'redis.yml'))
if redis_config.present?
redis_url = redis_config[Rails.env]['url']
$redis = Redis.new({:url=>redis_url})
else
$redis = Rails.cache.data
end
def login(user_id)
set_bit(user_id, 1)
end
def logout(user_id)
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
now = Time.now()
keys = []
(1..5).each do |i|
key = (now - i.minutes).strftime("%H-%M")
keys << "cache:online_user_#{key}"
set_bit_and_expire(cache_key, user_id, 0) unless $redis.ttl(cache_key) == -2
end
end
set_bit(user_id, 0)
end
def set_bit(user_id, flag)
if $redis.ttl(cache_key) == -2
# 如果key不存在
set_bit_and_expire(cache_key, user_id, flag)
else
if $redis.ttl(cache_key) ==-1
# 可以存在,但过期时间没关联
# 这种情况大概率是并发原因导致对相应key设置过期时跳过了。所以删除并重新设置过期时间
$redis.del(cache_key)
set_bit_and_expire(cache_key, user_id, flag)
end
# 统计当前时间下前5分钟的活跃人数
$redis.setbit(cache_key, user_id, flag)
end
end
def set_bit_and_expire(cache_key, user_id, flag)
$redis.setbit(cache_key, user_id, flag)
# $redis.setbit(last_cache_key, user_id, flag)
# 现在统计5分钟在线人数这里设置6分钟过期目的是统计当前时刻的前5分钟
$redis.expire(cache_key, 6 * 60)
end
def count
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
now = Time.now()
keys = []
(0..4).each do |i|
key = (now - i.minutes).strftime("%H-%M")
keys << "cache:online_user_#{key}"
end
# 防止每个分钟数据有重复,所以去重去除
$redis.bitop("OR", "daiao", keys)
$redis.bitcount("daiao")
else
0
end
end
def cache_key
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
"cache:online_user_#{Time.now().strftime("%H-%M")}"
else
raise '请配置config.cache_store = redis_store'
end
end
def last_cache_key
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
# 如设置5分钟内即300秒有请求的用户视为在线, 则最大会统计到10分钟内有活动用户
# TODO 更精确时长
begin_hour = Time.now.beginning_of_hour
minutes_piece = (Time.now - begin_hour) / (60 * 5)
time = begin_hour.since((minutes_piece.to_i - 1) * (60 * 5)).strftime("%H-%M")
"cache:online_user_#{time}"
else
raise '请配置config.cache_store = redis_store'
end
end
end
end

View File

@ -105,6 +105,23 @@ class Issue < ApplicationRecord
scope :pm_includes, -> {includes(:project, :show_issue_tags, :issue_status, :priority, :version, :user, :show_assigners, :comment_journals, :operate_journals)}
scope :closed, ->{where(status_id: 5)}
scope :opened, ->{where.not(status_id: 5)}
scope :with_assigner_info, -> {
joins("LEFT JOIN (
SELECT ia.issue_id, ia.assigner_id
FROM issue_assigners ia
JOIN (
SELECT issue_id, MIN(id) AS min_assigner_id
FROM issue_assigners
GROUP BY issue_id
) tmp ON ia.issue_id = tmp.issue_id AND ia.id = tmp.min_assigner_id
) assigner ON issues.id = assigner.issue_id
LEFT JOIN users u ON assigner.assigner_id = u.id")
}
scope :ordered_by_assigner, -> (sort_direction) {
order("CASE WHEN u.id IS NULL THEN 1 ELSE 0 END ASC")
.order("COALESCE(u.nickname, u.login) #{sort_direction}")
}
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
before_save :check_pm_and_update_due_date
after_save :incre_or_decre_closed_issues_count, :change_versions_count, :send_update_message_to_notice_system, :associate_attachment_container, :generate_uuid

View File

@ -9,7 +9,7 @@ class Api::V1::Issues::ListService < ApplicationService
validates :category, inclusion: { in: %w[all opened closed], message: '请输入正确的Category'}
validates :participant_category, inclusion: { in: %w[all aboutme authoredme assignedme atme], message: '请输入正确的ParticipantCategory'}
validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date issues.status_id] , message: '请输入正确的SortBy'}, allow_blank: true
validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date issues.status_id, assigners] , message: '请输入正确的SortBy'}, allow_blank: true
validates :sort_direction, inclusion: { in: %w[asc desc], message: '请输入正确的SortDirection'}, allow_blank: true
validates :current_user, presence: true
@ -175,6 +175,8 @@ class Api::V1::Issues::ListService < ApplicationService
scope = issues.includes(:priority, :issue_status, :user, :show_assigners, :show_issue_tags, :version, :comment_journals)
scope = if sort_by == 'issue_priorities.position'
scope.reorder("issue_priorities.position #{sort_direction}, issues.updated_on DESC").distinct
elsif sort_by == 'assigners'
scope.with_assigner_info.ordered_by_assigner(sort_direction)
else
scope.reorder("#{sort_by} #{sort_direction}").distinct
end

View File

@ -25,7 +25,9 @@ class Api::V1::Projects::Commits::RecentService < ApplicationService
param = {
access_token: token,
page: page,
limit: limit
limit: limit,
stats: false,
files: false
}
param.merge!(keyword: keyword) if keyword.present?

View File

@ -0,0 +1,53 @@
require 'openssl'
require 'base64'
require 'json'
require 'uri'
require 'time'
class Huawei::Signer
def initialize(ak, sk)
@ak = ak
@sk = sk
end
def sign_request(method, url, headers = {}, body = "")
uri = URI.parse(url)
host = uri.host
path = uri.path.empty? ? "/" : uri.path
query = uri.query ? "?" + uri.query : ""
# 时间戳
x_sdk_date = Time.now.utc.strftime("%Y%m%dT%H%M%SZ")
# Step 1: CanonicalRequest
canonical_headers = "host:#{host}\n" \
"x-sdk-date:#{x_sdk_date}\n"
signed_headers = "host;x-sdk-date"
hashed_payload = Digest::SHA256.hexdigest(body)
canonical_request = "#{method}\n#{path}\n#{query}\n#{canonical_headers}\n#{signed_headers}\n#{hashed_payload}"
# Step 2: StringToSign
hashed_canonical = Digest::SHA256.hexdigest(canonical_request)
string_to_sign = "SDK-HMAC-SHA256\n#{x_sdk_date}\n#{hashed_canonical}"
# Step 3: 计算签名
signature = OpenSSL::HMAC.hexdigest("SHA256", @sk, string_to_sign)
# Step 4: 生成 Authorization
authorization = "SDK-HMAC-SHA256 Access=#{@ak}, SignedHeaders=#{signed_headers}, Signature=#{signature}"
# 合并 headers
signed_headers_hash = {
"Authorization" => authorization,
"X-Sdk-Date" => x_sdk_date,
"Host" => host,
"Content-Type" => "application/json"
}
headers.merge!(signed_headers_hash)
headers
end
end

View File

@ -2,7 +2,7 @@
<% add_admin_breadcrumb('概览', admins_path) %>
<% end %>
<% cache "/admin/dashboards/#{Time.now.strftime('%Y-%m-%d')}", :expires_in => 1.days do %>
<%# cache_if EduSetting.get("open_baidu_tongji").to_s == "true", "/admin/dashboards/#{Time.now.strftime('%Y-%m-%d')}", :expires_in => 1.days do %>
<div class="header bg-gradient-primary pb-8 pt-md-8">
<div class="container-fluid">
<div class="header-body">
@ -32,7 +32,7 @@
</div>
</div>
</div>
<%end %>
<%#end %>
<div class="box admin-list-container project-language-list-container">
<table class="table table-hover text-center subject-list-table">

View File

@ -3,6 +3,6 @@ json.this_week_all_issues @this_week_all_issues.each do |issue|
end
json.this_week_total_count @this_week_all_issues.total_count
json.next_week_all_issues @next_week_all_issues.each do |issue|
json.partial! "api/pm/weekly_issues/simple_detail", locals: {issue: issue, weekly_begin_date: @weekly_begin_date+1.week, weekly_end_date: @weekly_end_date+1.week}
json.partial! "api/pm/weekly_issues/simple_detail", locals: {issue: issue, weekly_begin_date: @weekly_begin_date.to_date+1.week, weekly_end_date: @weekly_end_date.to_date+1.week}
end
json.next_week_total_count @next_week_all_issues.total_count

View File

@ -0,0 +1,34 @@
json.total_count @projects.total_count
json.projects @projects.each do |project|
json.(project, :id, :name, :identifier, :description, :forked_count, :praises_count, :forked_from_project_id, :is_public)
json.mirror_url project.repository&.mirror_url
json.type project.numerical_for_project_type
json.praised project.praised_by?(current_user)
json.last_update_time render_unix_time(project.updated_on)
json.full_last_update_time project.updated_on
json.time_ago time_from_now(project.updated_on)
json.language do
if project.project_language.blank?
json.nil!
else
json.id project.project_language.id
json.name project.project_language.name
end
end
json.category do
if project.project_category.blank?
json.nil!
else
json.id project.project_category.id
json.name project.project_category.name
end
end
json.topics project.project_topics.each do |topic|
json.(topic, :id, :name)
end
json.url project.full_url
json.owner do
json.partial! "api/v1/users/simple_user", locals: {user: @organization.team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user}
end
json.team_users_count @organization.team_users.size
end

View File

@ -31,7 +31,7 @@ json.author do
json.name user.try(:show_real_name)
json.type user&.type
json.login user.login
json.image_url url_to_avatar(user)
json.image_url url_to_avatar(user).present? ? url_to_avatar(user) : User::Avatar.get_letter_avatar_url(user.login)
end
end

View File

@ -1,32 +1,4 @@
习近平
习仲勋
贺国强
贺子珍
周永康
李德生
王岐山
姚依林
回良玉
李源潮
李干成
戴秉国
刘延东
刘瑞龙
俞正声
薄熙来
薄一波
周小川
周建南
温云松
江绵康
李小鹏
李小琳
朱云来
让国人愤怒的第二代身份证
文化大革命
胡海峰
陈良宇
老丁
莱仕德事件
fuck
地下的先烈们纷纷打来电话询问
@ -44,8 +16,6 @@ fuck
麻醉乙醚
短信群发器
帝国之梦
毛一鲜
黎阳平
对日强硬
出售枪支
摇头丸
@ -61,7 +31,6 @@ PK黑社会
侦探设备
麻醉钢枪
反华
官商勾结
升达毕业证
戴海静
自杀指南
@ -72,13 +41,8 @@ PK黑社会
强效失意药
迷奸药
透视眼镜
远程偷拍
自制手枪
激情小电影
黄色小电影
天鹅之旅
盘古乐队
高校暴乱
高校群体事件
大学骚乱
高校骚乱
@ -98,8 +62,6 @@ PK黑社会
反政府
禁书
特码
国民党
贪污
骚妇
法论功
江湖淫娘
@ -152,24 +114,15 @@ AV
玉蒲团
隐形喷剂
反雷达测速
假币
代开发票
假钞
窃听
电话拦截系统
探测狗
手机卡复制器
手机跟踪定位器
监听器
针孔摄像
监听宝
迷幻药
手拍肩
迷魂香
麻古
政治风波
政府软弱
政府无能
九评
十七大代表
暴力拆迁
@ -178,8 +131,6 @@ AV
高干子弟名单
性免费电影
全裸
偷拍
中共十七大
徐和柴学友
修炼之歌
警察殴打
@ -187,7 +138,6 @@ AV
李沛瑶遇害
美国凯德
肥东交警
中央军委
针对台湾
梁保华
MC军团
@ -195,7 +145,6 @@ MC军团
伪民运
采花堂
中国劳工通讯
评中国共产党
建立生活性补贴
中共走狗
中共小丑
@ -236,7 +185,6 @@ A集中营
江独裁
李屠夫
江恶人
中共特务
乙醚
党内分裂
圆明网
@ -282,7 +230,6 @@ A集中营
特务民运
中共警察
中共监狱
中共政权
中共迫害
自由联邦
中共独枭
@ -307,9 +254,6 @@ H漫画
买春堂
苏东解体
反右题材
隐私图片
卫星接收器
卫星电视
信号拦截器
新闻通气会
山西洪洞
@ -427,35 +371,27 @@ H漫画
毛爷爷复活
智能H3
智能H3
赣江学院
江西田园置业集团
海乐神
酣乐欣
高莺莺
完全自杀手册
无界
广东王
口头检查
三句硬话
红海湾
升达
沈阳公安
拦截器
阻无通畅
民为法执
尾行
电车之狼
绕过封锁
本拉登
汕尾事件
公务员工资
公务员调资
鸡吧
公务员的工资
反中游行
支持台湾
双鞋的故事
中国军用运输机
科技精英遇难
湘阴杨林
杨林寨
@ -467,11 +403,8 @@ H漫画
鬼村
重题工
先烈的电电
身份证生成
短信猫
车牌反光
次下跪
求救遭拒
邪恶的党
出售迷药
针孔摄像机
@ -589,21 +522,8 @@ a级情片
保钓
鲍戈
鲍彤
暴乱
暴政
北韩
藏独
曹长青
曹刚川
陈炳基
陈破空
陈希同
陈小同
陈宣良
陈一谘
陈总统
程铁军
迟浩田
持不同政见
赤匪
赤化
@ -618,16 +538,11 @@ a级情片
地下教会
地下刊物
电视流氓
钓鱼岛
丁关根
丁子霖
东北独立
东社
东土耳其斯坦
东西南北论坛
动乱
独裁
独裁政治
独夫
独立台湾会
屙民
@ -638,16 +553,11 @@ a级情片
法仑
法伦
法轮
法论
反封锁技术
反腐败论坛
反共
李洪志
法轮功
江泽民
毛泽东
邓小平
胡锦涛
推翻
打倒
台独
@ -836,7 +746,6 @@ A片
避孕套
你妈逼
大鸡巴
政治
卖春
买春
朱容基
@ -869,7 +778,6 @@ A片
吸储
张五常
张丕林
空难
吴邦国
曾庆红
黄菊
@ -890,33 +798,19 @@ A片
吳邦國
曾慶紅
賈慶林
反人类
反社会
方励之
方舟子
斐得勒
费良勇
分家在
分裂
粉饰太平
风雨神州
风雨神州论坛
封从德
冯东海
冯素英
佛展千手法
付申奇
傅申奇
傅志寰
高文谦
高薪养廉
高瞻
高自联
鸽派
个人崇拜
工自联
共产
共党
共匪
共狗
共军
@ -925,8 +819,6 @@ A片
郭伯雄
郭罗基
郭岩华
国家安全
国家机密
国军
国贼
韩东方
@ -985,49 +877,6 @@ A片
抗议
邝锦文
劳动教养所
劳改
劳教
老江
老毛
黎安友
李洪宽
李继耐
李兰菊
李少民
李淑娴
李旺阳
李文斌
李月月鸟
李志绥
连胜德
廉政大论坛
梁光烈
梁擎墩
两岸关系
两岸三地论坛
两个中国
廖锡龙
林保华
林长盛
林樵清
林慎立
刘宾深
刘宾雁
刘国凯
刘华清
刘俊国
刘凯中
刘千石
刘山青
刘士贤
刘文胜
刘晓波
刘晓竹
刘永川
龙虎豹
陆委会
吕京花
吕秀莲
抡功
轮大
罗礼诗
@ -1040,12 +889,8 @@ A片
毛贼东
美国参考
美国之音
蒙独
蒙古独立
密穴
绵恒
民国
民进党
民联
民意
民意论坛
@ -1073,7 +918,6 @@ A片
人民内情真相
人民真实
人民之声论坛
人权
善恶有报
上海帮
邵家健
@ -1087,14 +931,6 @@ A片
双十节
水扁
税力
司马晋
司马璐
司徒华
斯诺
四川独立
宋书元
苏绍智
苏晓康
台盟
台湾狗
台湾建国运动组织
@ -1129,17 +965,7 @@ A片
王秀丽
王冶坪
网特
魏新生
温元凯
文革
无界浏览器
吴百益
吴方城
吴弘达
吴宏达
吴仁华
吴学灿
吴学璨
吾尔开希
五不
洗脑
@ -1207,12 +1033,10 @@ A片
正义党论坛
换妻
真木加美
超爽
毛片
打手枪
欲望
脚交
伦理
艳星
三陪
绝色
@ -1239,7 +1063,6 @@ A片
天安门一代
自民党
自由民主论坛
走私
淫穴
幼女
舆论
@ -1252,7 +1075,6 @@ fa轮
指点江山论坛
中俄边界
中功
中共
中国威胁论
中国问题论坛
中国之春
@ -1357,7 +1179,6 @@ B样
淫图
交媾
护士
自拍
大片
夫妻
流血

View File

@ -42,6 +42,11 @@ Rails.application.routes.draw do
scope '/api' do
resources :topics, only: [:index]
namespace :huawei do
resources :code_arts_checks,only: [:index, :create]
end
namespace :ci do
resources :languages, only: [:index, :show] do
collection do

View File

@ -83,6 +83,10 @@ defaults format: :json do
patch :update_phone
end
end
scope module: :organizations do
resources :sync_repositories, only: [:create]
resources :projects, only: [:index]
end
scope module: :users do
resources :projects, only: [:index]
resources :feedbacks, only: [:create]
@ -189,6 +193,7 @@ defaults format: :json do
post '/jobs/:job', to: 'runs#job_show'
post '/rerun', to: 'runs#rerun'
post '/jobs/:job/rerun', to: 'runs#job_rerun'
post '/jobs/:job/cancel', to: 'runs#cancel'
get '/jobs/:job/logs', to: 'runs#job_logs'
end
end

View File

@ -0,0 +1,5 @@
class AddProjectIndexGpid < ActiveRecord::Migration[5.2]
def change
add_index :projects, :gpid
end
end