Merge branch 'pre_trustie_server' into trustie_server
# Conflicts: # app/helpers/repositories_helper.rb
This commit is contained in:
commit
391059602e
|
@ -0,0 +1,2 @@
|
|||
// Place all the behaviors and hooks related to the matching controller here.
|
||||
// All this logic will automatically be available in application.js.
|
|
@ -0,0 +1,3 @@
|
|||
// Place all the styles related to the admins/glcc_pr_check controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -0,0 +1,32 @@
|
|||
class Admins::GlccPrCheckController < Admins::BaseController
|
||||
def index
|
||||
params[:sort_by] = params[:sort_by].presence || 'created_on'
|
||||
params[:sort_direction] = params[:sort_direction].presence || 'desc'
|
||||
examine_materials = Admins::GlccExamineMaterial.call(params)
|
||||
@examine_materials = paginate examine_materials.includes(:glcc_student)
|
||||
end
|
||||
|
||||
def send_mail
|
||||
year = if params[:date].present?
|
||||
params[:date][:year]
|
||||
end
|
||||
if year.nil?
|
||||
return redirect_to admins_glcc_pr_check_index_path
|
||||
flash[:error] = "时间不能为空"
|
||||
end
|
||||
if params[:term].blank?
|
||||
return redirect_to admins_glcc_pr_check_index_path
|
||||
flash[:error] = "考核选项不能为空"
|
||||
end
|
||||
|
||||
examine_materials = GlccMediumTermExamineMaterial.where(\
|
||||
term: params[:term],
|
||||
created_on: [Time.now.change(year:year).beginning_of_year .. Time.now.change(year:year).end_of_year]
|
||||
)
|
||||
examine_materials.map{ |e|
|
||||
e.send_mail
|
||||
}
|
||||
flash[:danger] = "#{year} 年 #{params[:term].to_i == 1 ? "中期考核": "结项考核"} PR 检测邮件已全部发送完毕,一共#{examine_materials.count}封邮件"
|
||||
redirect_to admins_glcc_pr_check_index_path
|
||||
end
|
||||
end
|
|
@ -2,44 +2,18 @@ class ForksController < ApplicationController
|
|||
before_action :require_login
|
||||
before_action :require_profile_completed, only: [:create]
|
||||
before_action :load_project
|
||||
before_action :authenticate_user!
|
||||
before_action :authenticate_project!, only: [:create]
|
||||
|
||||
def fork_list
|
||||
@user = current_user
|
||||
@organizations = current_user.organizations
|
||||
|
||||
end
|
||||
before_action :authenticate_project!, :authenticate_user!
|
||||
|
||||
def create
|
||||
target_owner = if params[:organization].present? && @organization
|
||||
@organization
|
||||
else
|
||||
current_user
|
||||
end
|
||||
@new_project = Projects::ForkService.new(target_owner, @project, params[:organization], params[:new_name], params[:new_identifier]).call
|
||||
if @new_project == false
|
||||
render_result(-1, "已fork过一次该项目,无法再次进行fork")
|
||||
end
|
||||
@new_project = Projects::ForkServiceProjects::ForkService.new(current_user, @project, params[:organization]).call
|
||||
end
|
||||
|
||||
private
|
||||
def authenticate_project!
|
||||
if params[:organization].present?
|
||||
return render_forbidden('参数错误,当organization存在时不允许fork重命名') if params[:new_identifier].present? || params[:new_name].present?
|
||||
@organization = Organization.find_by(login:params[:organization])
|
||||
return render_forbidden('仓库不存在') unless @organization.present?
|
||||
return render_forbidden('你没有权限操作') unless @organization.is_admin?(current_user.id)
|
||||
end
|
||||
|
||||
if params[:organization].blank? && Project.exists?(user_id: current_user.id, identifier: (params[:new_identifier] || @project.identifier))
|
||||
render_result(-1, "fork失败,您已拥有了这个项目")
|
||||
elsif @organization && Project.exists?(user_id: [@organization.id], identifier: (params[:new_identifier] || @project.identifier))
|
||||
render_result(-1, "fork失败,组织已拥有了这个项目")
|
||||
elsif gitea_check_exit(current_user)
|
||||
render_result(-1, "fork失败,请联系系统管理员")
|
||||
elsif @organization && gitea_check_exit(@organization)
|
||||
render_result(-1, "fork失败,请联系系统管理员")
|
||||
if current_user&.id == @project.user_id
|
||||
render_result(-1, "自己不能fork自己的项目")
|
||||
elsif Project.exists?(user_id: current_user.id, identifier: @project.identifier)
|
||||
render_result(0, "fork失败,你已拥有了这个项目")
|
||||
end
|
||||
# return if current_user != @project.owner
|
||||
# render_result(-1, "自己不能fork自己的项目")
|
||||
|
@ -50,9 +24,4 @@ class ForksController < ApplicationController
|
|||
return if @project.member?(current_user) || current_user.admin?
|
||||
render_forbidden('你没有权限操作')
|
||||
end
|
||||
|
||||
def gitea_check_exit(user)
|
||||
data = Gitea::Repository::GetService.new(user, params[:new_identifier]|| @project.identifier).call
|
||||
data.present?
|
||||
end
|
||||
end
|
||||
end
|
|
@ -11,6 +11,20 @@ class SettingsController < ApplicationController
|
|||
get_top_system_notification
|
||||
end
|
||||
|
||||
def check_url
|
||||
url = params[:url]
|
||||
task_id = params[:task]
|
||||
term = params[:term]
|
||||
return normal_status(-1, "缺少url参数") unless url.present?
|
||||
return normal_status(-1, "缺少term参数") unless term.present?
|
||||
return normal_status(-1, "缺少task参数") unless task_id.present?
|
||||
glcc_mate = GlccMediumTermExamineMaterial.new(code_or_pr_url: url, task_id: task_id, term: term, created_on:Time.now)
|
||||
state = glcc_mate.check_pr_url
|
||||
errors = glcc_mate.gennerate_content(state)
|
||||
render_ok({ state:state, state_html: errors})
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def get_navbar
|
||||
@navbar = default_laboratory.navbar
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
module Admins::GlccPrCheckHelper
|
||||
end
|
|
@ -120,25 +120,14 @@ module RepositoriesHelper
|
|||
s_regex_c = /`{1,2}[^`](.*?)`{1,2}/
|
||||
s_regex = /```([\s\S]*?)```[\s]?/
|
||||
s_regex_1 = /\[.*?\]\((.*?)\)/
|
||||
# 变量图片相对路径
|
||||
s_regex_2 = /\[.*?\]:(.*?)\n/
|
||||
src_regex = /src=\"(.*?)\"/
|
||||
src_regex_1 = /src=\'(.*?)\'/
|
||||
src_regex_2 = /src = (.*?) /
|
||||
src_regex_3 = /src= (.*?) /
|
||||
src_regex_4 = /src =(.*?) /
|
||||
src_regex_5 = /src =(.*?) /
|
||||
ss_c = content.to_s.scan(s_regex_c)
|
||||
ss = content.to_s.scan(s_regex)
|
||||
ss_1 = content.to_s.scan(s_regex_1)
|
||||
ss_2 = content.to_s.scan(s_regex_2)
|
||||
ss_src = content.to_s.scan(src_regex)
|
||||
ss_src_1 = content.to_s.scan(src_regex_1)
|
||||
ss_src_2 = content.to_s.scan(src_regex_2)
|
||||
ss_src_3 = content.to_s.scan(src_regex_3)
|
||||
ss_src_4 = content.to_s.scan(src_regex_4)
|
||||
ss_src_5 = content.to_s.scan(src_regex_5)
|
||||
total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_2: ss_2, ss_src: ss_src, ss_src_1: ss_src_1, ss_src_2: ss_src_2, ss_src_3: ss_src_3, ss_src_4: ss_src_4, ss_src_5: ss_src_5}
|
||||
total_sources = {ss_c: ss_c,ss: ss, ss_1: ss_1, ss_src: ss_src, ss_src_1: ss_src_1}
|
||||
# total_sources.uniq!
|
||||
total_sources.except(:ss, :ss_c).each do |k, sources|
|
||||
sources.each do |s|
|
||||
|
@ -159,17 +148,7 @@ module RepositoriesHelper
|
|||
content = content.gsub("src=\"#{s[0]}\"", "src=\"#{s_content}\"")
|
||||
when 'ss_src_1'
|
||||
content = content.gsub("src=\'#{s[0]}\'", "src=\'#{s_content}\'")
|
||||
when 'ss_src_2'
|
||||
content = content.gsub("src = #{s[0]}", "src=\'#{s_content}\'")
|
||||
when 'ss_src_3'
|
||||
content = content.gsub("src= #{s[0]}", "src=\'#{s_content}\'")
|
||||
when 'ss_src_4'
|
||||
content = content.gsub("src =#{s[0]}", "src=\'#{s_content}\'")
|
||||
when 'ss_src_5'
|
||||
content = content.gsub("src=#{s[0]}", "src=\'#{s_content}\'")
|
||||
when 'ss_2'
|
||||
content = content.gsub(/]:#{s[0]}/, "]: #{s_content.to_s.gsub(" ","").gsub("\r", "")}")
|
||||
else
|
||||
else
|
||||
content = content.gsub("(#{s[0]})", "(#{s_content})")
|
||||
end
|
||||
else
|
||||
|
@ -181,9 +160,7 @@ module RepositoriesHelper
|
|||
content = content.gsub("src=\"#{s[0]}\"", "src=\"/#{s_content}\"")
|
||||
when 'ss_src_1'
|
||||
content = content.gsub("src=\'#{s[0]}\'", "src=\'/#{s_content}\'")
|
||||
when 'ss_2'
|
||||
content = content.gsub(/]:#{s[0]}/, "]: /#{s_content.to_s.gsub(" ","").gsub("\r", "")}")
|
||||
else
|
||||
else
|
||||
content = content.gsub("(#{s[0]})", "(/#{s_content})")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,4 +30,11 @@ class UserMailer < ApplicationMailer
|
|||
def feedback_email(mail, title, content)
|
||||
mail(to: mail, subject: title, content_type: "text/html", body: content)
|
||||
end
|
||||
|
||||
def glcc_pr_check_email(mail, title, name, content)
|
||||
@content = content
|
||||
@name = name
|
||||
mail(to: mail, subject: title)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: ignores
|
||||
#
|
||||
# student_reg_id
|
||||
# task_id
|
||||
# defence_video_url
|
||||
# code_or_pr_url
|
||||
# PPT_attachment_id
|
||||
# term
|
||||
# created_on
|
||||
# updated_on
|
||||
# is_delete
|
||||
# round
|
||||
|
||||
class GlccMediumTermExamineMaterial < ActiveRecord::Base
|
||||
self.table_name = "glcc_medium_term_examine_material"
|
||||
belongs_to :glcc_student, :class_name => :GlccRegistrationStudent, :foreign_key => "student_reg_id"
|
||||
belongs_to :task, :class_name => :GlccRegistrationTask, :foreign_key => "task_id"
|
||||
|
||||
def check_pr_url
|
||||
state = []
|
||||
# code_or_pr_url = "https://www.gitlink.org.cn/Gitlink/forgeplus/pulls/337"
|
||||
url_array = code_or_pr_url.split("/")
|
||||
gitlink_index = url_array.index("www.gitlink.org.cn") || url_array.index("gitlink.org.cn")
|
||||
pull_index = url_array.index("pulls")
|
||||
|
||||
#发送没有在gitlink上提交PR的邮件
|
||||
unless gitlink_index.present?
|
||||
state << 1
|
||||
end
|
||||
|
||||
# 输入的地址有问题邮件内容
|
||||
unless pull_index == 5
|
||||
state << 2
|
||||
end
|
||||
|
||||
project = Project.find_by(identifier: url_array[4])
|
||||
pr = PullRequest.where(project:project, gitea_number:url_array[6])
|
||||
|
||||
unless pr.present?
|
||||
state << 3
|
||||
end
|
||||
if white_list && term == 1 #特殊处理 白名单的中期考核不处理 中期考核后去掉
|
||||
state = []
|
||||
end
|
||||
state
|
||||
end
|
||||
|
||||
|
||||
def white_list
|
||||
# 全局设置白名单 key
|
||||
key = "glcc_white_task_#{self.created_on.year}"
|
||||
white_task = EduSetting.find_by_name(key)
|
||||
if white_task
|
||||
task_ids = white_task.value.split(",")
|
||||
task_ids.map(&:to_i).include?(self.task_id)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def send_mail
|
||||
gcs = glcc_student
|
||||
mail = gcs.mail
|
||||
return if mail.nil? || code_or_pr_url.nil?
|
||||
|
||||
state = check_pr_url
|
||||
return unless state.present?
|
||||
title = "#{self.created_on.year}年GitLink确实开源GLCC开源夏令营#{term == 1 ? "中期考核" : "结项考核"}提醒"
|
||||
content = gennerate_content(state)
|
||||
UserMailer.glcc_pr_check_email(mail,title, gcs.student_name, content).deliver_now
|
||||
end
|
||||
|
||||
def state_to_html
|
||||
gcs = glcc_student
|
||||
mail = gcs.mail
|
||||
return "数据异常,PR链接为空" if mail.nil? || code_or_pr_url.nil?
|
||||
state = check_pr_url
|
||||
gennerate_content(state)
|
||||
end
|
||||
|
||||
def gennerate_content(state)
|
||||
content = ""
|
||||
state.map{|e|
|
||||
content = content + number_to_content(e)
|
||||
}
|
||||
content
|
||||
end
|
||||
|
||||
def number_to_content(num)
|
||||
case num
|
||||
when 1
|
||||
"<p> PR链接为非GitLink平台链接 </p>"
|
||||
when 2
|
||||
"<p> PR链接为GitLink平台链接, 但非PR链接 </p>"
|
||||
when 3
|
||||
"<p> PR链接中的PR不存在 </p>"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: ignores
|
||||
# user_id
|
||||
# student_name
|
||||
# school
|
||||
# profession
|
||||
# location
|
||||
# grade
|
||||
# phone
|
||||
# mail
|
||||
# created_on
|
||||
# is_delete
|
||||
# prove_attachment_id
|
||||
# cancel_count
|
||||
# round
|
||||
#
|
||||
|
||||
class GlccRegistrationStudent < ActiveRecord::Base
|
||||
self.table_name = "glcc_registration_student"
|
||||
has_many :examines, :class_name => :GlccMediumTermExamineMaterial, :foreign_key => "student_reg_id"
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: ignores
|
||||
# user_id
|
||||
# student_name
|
||||
# school
|
||||
# profession
|
||||
# location
|
||||
# grade
|
||||
# phone
|
||||
# mail
|
||||
# created_on
|
||||
# is_delete
|
||||
# prove_attachment_id
|
||||
# cancel_count
|
||||
# round
|
||||
#
|
||||
|
||||
class GlccRegistrationTask < ActiveRecord::Base
|
||||
self.table_name = "glcc_registration_task"
|
||||
has_many :examines, :class_name => :GlccMediumTermExamineMaterial, :foreign_key => "task_id"
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
class Admins::GlccExamineMaterial < ApplicationQuery
|
||||
include CustomSortable
|
||||
|
||||
attr_reader :params
|
||||
|
||||
sort_columns :created_on, default_direction: :desc
|
||||
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
|
||||
def call
|
||||
materials = GlccMediumTermExamineMaterial.all
|
||||
|
||||
# term
|
||||
term = params[:term] || [1,2]
|
||||
if term.present?
|
||||
materials = materials.where(term: term)
|
||||
end
|
||||
#year
|
||||
year = if params[:date]
|
||||
params[:date][:year]
|
||||
end
|
||||
year = year || Time.now.year
|
||||
date = Time.now.change(year:year)
|
||||
materials = materials.where(created_on: [date.beginning_of_year..date.end_of_year])
|
||||
custom_sort(materials, params[:sort_by], params[:sort_direction])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,137 @@
|
|||
class ApiLimitService < ApplicationService
|
||||
Error = Class.new(StandardError)
|
||||
|
||||
def initialize() end
|
||||
|
||||
def call
|
||||
|
||||
end
|
||||
|
||||
# 时间窗口法
|
||||
def is_action_allowed?(user_id, action_key, period, max_count)
|
||||
key = "#{user_id}:#{action_key}"
|
||||
count = $redis_cache.multi do |multi|
|
||||
multi.incr(key)
|
||||
multi.expire(key, period)
|
||||
end
|
||||
count[0] <= max_count
|
||||
end
|
||||
|
||||
# 漏桶法
|
||||
def is_action_allowed_bucket?(user_id, action_key, capacity, rate)
|
||||
key = "#{user_id}:#{action_key}"
|
||||
# now = (("%10.3f" % Time.now.to_f).to_f * 1000).to_i
|
||||
now = Time.now.to_i
|
||||
count = $redis_cache.multi do |multi|
|
||||
multi.zadd(key, now, SecureRandom.uuid.gsub("-", ""))
|
||||
multi.zremrangebyscore(key, 0, now - capacity)
|
||||
multi.zcard(key)
|
||||
multi.expire(key, (capacity / rate + 1).to_i)
|
||||
end
|
||||
# puts "count1==#{count}"
|
||||
# puts "count2==#{count[2]}"
|
||||
count[2] <= capacity
|
||||
end
|
||||
|
||||
def is_action_allowed_aaa?(user_id, action_key, period, maxCount)
|
||||
key = "#{user_id}:#{action_key}"
|
||||
now = (("%10.3f" % Time.now.to_f).to_f * 1000).to_i
|
||||
count = $redis_cache.multi do |multi|
|
||||
# 添加命令
|
||||
multi.zadd(key, now, SecureRandom.uuid.gsub("-", ""))
|
||||
# 清楚无用数据
|
||||
multi.zremrangebyscore(key, 0, now - period * 1000)
|
||||
# 判断规定时间内请求数量
|
||||
multi.zcard(key)
|
||||
# 重新设置过期时间
|
||||
multi.expire(key, period + 1)
|
||||
end
|
||||
# puts "count1==#{count}"
|
||||
# puts "count2==#{count[2]}"
|
||||
count[2] <= maxCount
|
||||
end
|
||||
|
||||
def sdfsf
|
||||
|
||||
# 每秒钟漏斗的容量
|
||||
|
||||
capacity = 10
|
||||
|
||||
|
||||
# 漏斗填充速度
|
||||
|
||||
leak_rate = 0.3
|
||||
|
||||
# 当前漏斗中的水量
|
||||
|
||||
current_volume = 0
|
||||
|
||||
# 上一次漏水的时间
|
||||
|
||||
last_leak_time = Time.now.to_i
|
||||
|
||||
funnel_name = "tests"
|
||||
|
||||
# $redis_cache.hset(funnel_name, "volume", capacity)
|
||||
$redis_cache.hset(funnel_name, "last_leak_time", Time.now.to_i)
|
||||
|
||||
# 构造事务命令
|
||||
|
||||
# result = $redis_cache.multi do |pipe|
|
||||
# # 把当前时间与上一次漏水时间的差值,作为漏斗流出水量
|
||||
#
|
||||
# pipe.hget(funnel_name, "last_leak_time")
|
||||
#
|
||||
# pipe.hset(funnel_name, "last_leak_time", Time.now.to_i)
|
||||
#
|
||||
# pipe.hget(funnel_name, "volume")
|
||||
#
|
||||
# pipe.hget(funnel_name, "capacity")
|
||||
#
|
||||
# pipe.hget(funnel_name, "leak_rate")
|
||||
# end
|
||||
|
||||
current_volume = $redis_cache.hget(funnel_name, "volume")
|
||||
last_leak_time = $redis_cache.hget(funnel_name, "last_leak_time")
|
||||
# 先漏水
|
||||
leaked_volume = (Time.now.to_i - last_leak_time.to_i) * leak_rate.to_f
|
||||
|
||||
current_volume = [current_volume.to_f + leaked_volume, capacity.to_f].sort.first
|
||||
puts "current_volume====#{current_volume}"
|
||||
# 判断是否可以通过请求
|
||||
if current_volume >= 1
|
||||
$redis_cache.hset(funnel_name, "volume", current_volume.to_i - 1)
|
||||
# $redis_cache.hset(funnel_name, "last_leak_time", Time.now.to_i)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def done_test3
|
||||
100.times.each do |t|
|
||||
if t % 2== 0
|
||||
sleep(1)
|
||||
end
|
||||
puts "#{t}:res====#{sdfsf}"
|
||||
end
|
||||
end
|
||||
|
||||
def done_test
|
||||
100.times.each do |t|
|
||||
if t % 10== 0
|
||||
sleep(5)
|
||||
end
|
||||
puts "#{t}:res====#{is_action_allowed_bucket?("123", "test2", 10, 0.2)}"
|
||||
end
|
||||
end
|
||||
|
||||
def done_test2
|
||||
100.times.each do |t|
|
||||
sleep(1)
|
||||
puts "#{t}:res====#{is_action_allowed_aaa?("123", "test3", 10, 5)}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
class LeakyBucketRateLimiter
|
||||
def initialize(user_id, rate, capacity)
|
||||
@rate = rate # 令牌发放速率(每秒发放的令牌数)
|
||||
@capacity = capacity # 桶的容量(最大令牌数)
|
||||
@redis = $redis_cache
|
||||
@key = "#{user_id}:LeakyBucket"
|
||||
@current_time = Time.now.to_f
|
||||
end
|
||||
|
||||
def allow_request
|
||||
current_time = Time.now.to_f
|
||||
last_drip_time = @redis.getset(@key + ':last_drip_time', current_time).to_f
|
||||
tokens = @redis.getset(@key + ':tokens', @capacity).to_i
|
||||
|
||||
# 计算已经漏掉的令牌数量
|
||||
leaked_tokens = (current_time - last_drip_time) * @rate
|
||||
puts leaked_tokens
|
||||
# 如果桶中的令牌多于漏掉的令牌数量,则漏水
|
||||
tokens = [@capacity, tokens + leaked_tokens].min
|
||||
puts tokens
|
||||
if tokens >= 1
|
||||
@redis.set(@key + ':last_drip_time', current_time)
|
||||
@redis.decr(@key + ':tokens')
|
||||
return true
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
=begin
|
||||
失败
|
||||
limiter = LeakyBucketRateLimiter.new(110,10, 40) # 设置令牌发放速率为10,桶的容量为40
|
||||
30.times do
|
||||
if limiter.allow_request
|
||||
puts "Allow"
|
||||
else
|
||||
puts "Reject"
|
||||
end
|
||||
end
|
||||
|
||||
=end
|
|
@ -18,7 +18,6 @@ class Projects::ForkService < ApplicationService
|
|||
:license_id, :ignore_id, {repository: [:identifier, :hidden]}]
|
||||
|
||||
result = Gitea::Repository::ForkService.new(@project.owner, @target_owner, @project.identifier, @organization, @new_identifier).call
|
||||
return false if result['clone_url'].nil?
|
||||
clone_project.owner = @target_owner
|
||||
clone_project.forked_from_project_id = @project.id
|
||||
clone_project.gpid = result['id']
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
class SlidingWindowRateLimiter
|
||||
def initialize(user_id, rate, window_size)
|
||||
@rate = rate # 请求速率限制(每秒的请求数)
|
||||
@window_size = window_size # 时间窗口大小(秒)
|
||||
@redis = $redis_cache
|
||||
@key = "#{user_id}:SlidingWindow"
|
||||
@current_timestamp = Time.now.to_f
|
||||
end
|
||||
|
||||
def allow_request
|
||||
current_timestamp = Time.now.to_f
|
||||
score = current_timestamp.to_i
|
||||
start_time = current_timestamp - @window_size
|
||||
|
||||
@redis.zremrangebyscore(@key, '-inf', start_time)
|
||||
count = @redis.zcount(@key, '-inf', '+inf').to_i
|
||||
|
||||
return false if count >= @rate
|
||||
|
||||
@redis.zadd(@key, score, current_timestamp)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
=begin
|
||||
#测试通过
|
||||
|
||||
limiter = SlidingWindowRateLimiter.new(user_id,10, 1) # 设置请求速率限制为10次/秒,时间窗口大小为1秒
|
||||
40.times do
|
||||
if limiter.allow_request
|
||||
puts "Allow"
|
||||
else
|
||||
puts "Reject"
|
||||
end
|
||||
end
|
||||
|
||||
=end
|
|
@ -0,0 +1,48 @@
|
|||
class TokenBucketRateLimiter
|
||||
def initialize(user_id,rate, capacity)
|
||||
@rate = rate # 令牌发放速率(每秒发放的令牌数)
|
||||
@capacity = capacity # 令牌桶容量
|
||||
@redis = $redis_cache
|
||||
@key = "#{user_id}:TokenBucket"
|
||||
end
|
||||
|
||||
def refill
|
||||
now = Time.now.to_f * 1000
|
||||
tokens = $redis_cache.hget(@key, 'tokens')
|
||||
timestamp = $redis_cache.hget(@key, 'timestamp')
|
||||
|
||||
if tokens.nil?
|
||||
tokens = @capacity
|
||||
timestamp = now
|
||||
else
|
||||
tokens = [@capacity, tokens.to_i + (now - timestamp.to_f) * @rate / 1000].min
|
||||
timestamp = now
|
||||
end
|
||||
|
||||
$redis_cache.hset(@key, 'tokens', tokens)
|
||||
$redis_cache.hset(@key, 'timestamp', timestamp)
|
||||
end
|
||||
|
||||
def allow_request
|
||||
refill
|
||||
tokens = @redis.hget(@key, 'tokens')
|
||||
if !tokens.nil? && tokens.to_i >= 1
|
||||
@redis.hset(@key, 'tokens', tokens.to_i - 1)
|
||||
return true
|
||||
end
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
=begin
|
||||
#测试通过
|
||||
limiter = TokenBucketRateLimiter.new(user_id,10, 40) # 设置令牌发放速率为10,令牌桶容量为40
|
||||
30.times do
|
||||
if limiter.allow_request
|
||||
puts "Allow"
|
||||
else
|
||||
puts "Reject"
|
||||
end
|
||||
end
|
||||
|
||||
=end
|
|
@ -0,0 +1,58 @@
|
|||
<table class="table table-hover glcc_pr_check-list-table">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th width="3%">序号</th>
|
||||
<th width="4%" class="text-left">学生姓名</th>
|
||||
<th width="3%" class="text-left">课题ID</th>
|
||||
<th width="10%" class="text-left">课题名称</th>
|
||||
<th width="10%">邮件地址</th>
|
||||
<th width="15%">视频地址</th>
|
||||
<th width="15%">PR地址</th>
|
||||
60
|
||||
<th width="5%">考核阶段</th>
|
||||
<th width="4%">白名单</th>
|
||||
<th width="15%">检测状态</th>
|
||||
<th width="6%">提交时间</th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if examine_materials.present? %>
|
||||
<% examine_materials.each_with_index do |material, index| %>
|
||||
<tr class="user-item-<%= material.id %>">
|
||||
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
|
||||
<td><%= material.glcc_student.student_name %></td>
|
||||
<td><%= material.task_id %></td>
|
||||
<td><%= material.task.task_name %></td>
|
||||
<td>
|
||||
<span class="d-inline-block" tabindex="0" data-toggle="tooltip" data-placement="left" title="<%= material.glcc_student.mail%>">
|
||||
<%=material.glcc_student.mail.truncate(20) %>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="d-inline-block" tabindex="0" data-toggle="tooltip" data-placement="left" title="<%= material.defence_video_url%>">
|
||||
<a href="javascript:">
|
||||
<%= material.defence_video_url.nil? ? "" : material.defence_video_url.truncate(30) %>
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="d-inline-block" tabindex="0" data-toggle="tooltip" data-placement="left" title="<%= material.code_or_pr_url%>">
|
||||
<a href="javascript:">
|
||||
<%= material.code_or_pr_url.nil? ? "" : material.code_or_pr_url.truncate(30) %>
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
<td><%= material.term == 1 ? "中期考核" : "结项考核"%></td>
|
||||
<td><%= material.white_list ? "是":"否" %></td>
|
||||
<td><%= material.state_to_html.blank?&&!material.white_list ? "通过" : material.state_to_html.html_safe %></td>
|
||||
<td><%= material.created_on.strftime("%Y-%m-%d %H:%M")%></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= render 'admins/shared/no_data_for_table' %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= render partial: 'admins/shared/paginate', locals: { objects: examine_materials } %>
|
|
@ -0,0 +1,44 @@
|
|||
<div class="box search-form-container glcc_pr_check-list-form">
|
||||
<%= form_tag(admins_glcc_pr_check_index_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
|
||||
<div class="form-group mr-2">
|
||||
<label for="status">考核选项:</label>
|
||||
<% status_options = [['中期考核',1], ['结项考核', 2]] %>
|
||||
<%= select_tag(:term, options_for_select(status_options), class: 'form-control') %>
|
||||
</div>
|
||||
|
||||
<div class="form-group mr-2">
|
||||
<label for="status">第 </label>
|
||||
<%= select_year(Date.today, {field_name:"year"}, {class:"form-control"})%>
|
||||
<label for="status"> 期</label>
|
||||
</div>
|
||||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
|
||||
<% end %>
|
||||
<button onclick="$('.send-email-list-form').show();$('.glcc_pr_check-list-form').hide();$('.glcc-examine-list-container').hide()" > 前去发送邮件</button>
|
||||
</div>
|
||||
|
||||
<div class="box search-form-container send-email-list-form" style ="display:none">
|
||||
<h5> 请重新选择参数,谨慎操作</h5>
|
||||
|
||||
<%= form_tag(send_mail_admins_glcc_pr_check_index_path, method: :post, class: 'form-inline search-form flex-1', remote: true) do %>
|
||||
<div class="form-group mr-2">
|
||||
<label for="status"> 请选择考核选项:</label>
|
||||
<% status_options = [['中期考核',1], ['结项考核', 2]] %>
|
||||
<%= select_tag(:term, options_for_select(status_options), class: 'form-control') %>
|
||||
</div>
|
||||
|
||||
<div class="form-group mr-2">
|
||||
<label for="status">第 </label>
|
||||
<%= select_year((Date.today + 1.years), {field_name:"year"}, {class:"form-control"})%>
|
||||
<label for="status"> 期(注:此处为一年中的数据)</label>
|
||||
</div>
|
||||
|
||||
<%= submit_tag('发送邮件', class: 'btn btn-primary ml-3',data: { confirm: '您是否真的需要进行邮件发送操作?请确认 考核选项 和 期数' }) %>
|
||||
<% end %>
|
||||
<button onclick="$('.glcc_pr_check-list-form').show();$('.send-email-list-form').hide();$('.glcc-examine-list-container').show()" > 取消发送邮件</button>
|
||||
</div>
|
||||
|
||||
<div class="box admin-list-container glcc-examine-list-container">
|
||||
<%= render partial: 'examine_material', locals: { examine_materials: @examine_materials } %>
|
||||
</div>
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
$('.glcc-examine-list-container').html("<%= j( render partial: 'examine_material', locals: { examine_materials: @examine_materials } ) %>");
|
|
@ -57,6 +57,7 @@
|
|||
<%= sidebar_item(EduSetting.get("glcc_apply_informations_admin_url"), '报名列表', icon: 'user', controller: 'root') %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li><%= sidebar_item(admins_glcc_pr_check_index_path, '考核PR检测', icon: 'edit', controller: 'admins-glcc_pr_check') %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
json.user do
|
||||
json.id @user.id
|
||||
json.type @user.type
|
||||
json.name @user.real_name
|
||||
json.login @user.login
|
||||
json.image_url url_to_avatar(@user)
|
||||
json.forked Project.exists?(user_id: @user.id, forked_from_project_id: @project.id)
|
||||
end
|
||||
json.organizations @organizations do |organization|
|
||||
json.forked Project.exists?(user_id: organization.id, forked_from_project_id: @project.id)
|
||||
json.id organization.id
|
||||
json.name organization.login
|
||||
json.nickname organization.nickname.blank? ? organization.name : organization.nickname
|
||||
json.avatar_url url_to_avatar(organization)
|
||||
json.created_at organization.created_on.strftime("%Y-%m-%d")
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>验证码发送</title>
|
||||
<style type="text/css">
|
||||
/* 验证链接页面 */
|
||||
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
|
||||
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
|
||||
div,img,tr,td,table{ border:0;}
|
||||
table,tr,td{border:0;}
|
||||
ol,ul,li{ list-style-type:none}
|
||||
.new_content{ background:#fff; width: 100%;}
|
||||
.email-page-link{ }
|
||||
.email-link-top{ }
|
||||
.c_white{ color:#fff;}
|
||||
.email-link-con{ }
|
||||
.email-link-line{ }
|
||||
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
|
||||
.c_grey02{ color: #888;}
|
||||
.fb{ font-weight: normal;}
|
||||
.f14{ }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="background:#fff;">
|
||||
<div class="new_content">
|
||||
<div style="width: 598px; background:#fff; margin:20px auto; font-size:14px; ">
|
||||
<div style="height:50px; width: 578px; background:#46484c; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
|
||||
<a href="https://www.gitlink.org.cn">
|
||||
<img src="https:///www.gitlink.org.cn/images/email_logo.png" width="100" style="float:left; margin-top: 8px;" >
|
||||
</a>
|
||||
<div style="clear:both; overflow:hidden;"></div>
|
||||
</div>
|
||||
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:30px 20px; color:#333; line-height: 1.9;">
|
||||
|
||||
<p style="color:#333; font-size:16px; margin: 15px 0; font-weight: bold">
|
||||
<b>尊敬的<%=@name%>同学:</b>
|
||||
</p>
|
||||
|
||||
<p style="font-size: 15px; font-family: 微软雅黑, 宋体; color: rgb(51, 51, 51); text-decoration: none; background-color: rgba(0, 0, 0, 0); font-weight: 400; font-style: normal;">
|
||||
您好!经过一个多月的开发,GLCC开源编程夏令营终于迎来中期考核。为了确保您能够顺利通过考核,现对您提交的PR链接进行检测,发现存在以下问题:
|
||||
</p>
|
||||
|
||||
<div style="text-align: center; margin: 15px 0; font-size: 15px; font-family: 微软雅黑, 宋体; color: rgb(51, 51, 51); text-decoration: none; background-color: rgba(0, 0, 0, 0); font-weight: 400; font-style: normal;text-align: center;">
|
||||
<%=@content.html_safe%>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 15px; margin: 15px 0; font-family: 微软雅黑, 宋体; color: rgb(51, 51, 51); text-decoration: none; background-color: rgba(0, 0, 0, 0); font-weight: 400; font-style: normal;">
|
||||
您提交的PR链接的真实有效性对于后期的开发和奖金的发放至关重要,请您务必予以重视。请您尽快核查链接的有效性,并按照组委会要求提交中期考核材料。若确认链接无误,请忽略本邮件。
|
||||
</p>
|
||||
|
||||
<p style="margin: 15px 0;font-size: 15px; font-family: 微软雅黑, 宋体; color: rgb(51, 51, 51); text-decoration: none; background-color: rgba(0, 0, 0, 0); font-weight: 400; font-style: normal;">
|
||||
如有其他问题,请联系:glcc@ccf.org.cn
|
||||
</p>
|
||||
|
||||
<p style="font-size: 15px; font-family: 微软雅黑, 宋体; color: rgb(51, 51, 51); text-decoration: none; background-color: rgba(0, 0, 0, 0); font-weight: 400; font-style: normal; text-align: right;">
|
||||
GLCC组委会
|
||||
</p>
|
||||
<p style="font-size: 15px; font-family: 微软雅黑, 宋体; color: rgb(51, 51, 51); text-decoration: none; background-color: rgba(0, 0, 0, 0); font-weight: 400; font-style: normal; text-align: right;">
|
||||
<%=Time.now.strftime('%Y年%m月%d日')%>
|
||||
</p>
|
||||
</div>
|
||||
<div style="padding:20px; color:#333; line-height: 1.9;background:#46484c;border:1px solid #ddd; border-top:none; width: 558px;">
|
||||
<a href="https:///www.gitlink.org.cn/" style="font-weight: normal; color:#fff;">www.gitlink.org.cn</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -19,6 +19,7 @@ Rails.application.routes.draw do
|
|||
get 'attachments/entries/get_file', to: 'attachments#get_file'
|
||||
get 'attachments/download/:id', to: 'attachments#show'
|
||||
get 'attachments/download/:id/:filename', to: 'attachments#show'
|
||||
get 'check_pr_url',to: "settings#check_url"
|
||||
|
||||
# get 'auth/qq/callback', to: 'oauth/qq#create'
|
||||
get 'auth/failure', to: 'oauth/base#auth_failure'
|
||||
|
@ -625,11 +626,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
|
||||
resources :hooks
|
||||
resources :forks, only: [:create] do
|
||||
collection do
|
||||
get :fork_list
|
||||
end
|
||||
end
|
||||
resources :forks, only: [:create]
|
||||
resources :project_trends, :path => :activity, only: [:index, :create]
|
||||
resources :issue_tags, :path => :labels, only: [:create, :edit, :update, :destroy, :index]
|
||||
resources :version_releases, :path => :releases, only: [:index,:new, :show, :create, :edit, :update, :destroy]
|
||||
|
@ -793,6 +790,12 @@ Rails.application.routes.draw do
|
|||
resources :glcc_news
|
||||
resources :pinned_forums
|
||||
end
|
||||
resources :glcc_pr_check do
|
||||
collection do
|
||||
post :send_mail
|
||||
end
|
||||
end
|
||||
|
||||
resources :project_statistics, only: [:index] do
|
||||
collection do
|
||||
get :visits_static
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admins::GlccPrCheckController, type: :controller do
|
||||
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
require 'rails_helper'
|
||||
|
||||
# Specs in this file have access to a helper object that includes
|
||||
# the Admins::GlccPrCheckHelper. For example:
|
||||
#
|
||||
# describe Admins::GlccPrCheckHelper do
|
||||
# describe "string concat" do
|
||||
# it "concats two strings with spaces" do
|
||||
# expect(helper.concat_strings("this","that")).to eq("this that")
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
RSpec.describe Admins::GlccPrCheckHelper, type: :helper do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
Reference in New Issue