# Conflicts: # app/helpers/repositories_helper.rbpull/342/head
| @@ -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 | |||
| # 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 | |||
| # 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 | |||