diff --git a/app/assets/javascripts/admins/glcc_pr_check.js b/app/assets/javascripts/admins/glcc_pr_check.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/admins/glcc_pr_check.js @@ -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. diff --git a/app/assets/stylesheets/admins/glcc_pr_check.scss b/app/assets/stylesheets/admins/glcc_pr_check.scss new file mode 100644 index 000000000..7dfa6e7cf --- /dev/null +++ b/app/assets/stylesheets/admins/glcc_pr_check.scss @@ -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/ diff --git a/app/controllers/admins/glcc_pr_check_controller.rb b/app/controllers/admins/glcc_pr_check_controller.rb new file mode 100644 index 000000000..1d79ba802 --- /dev/null +++ b/app/controllers/admins/glcc_pr_check_controller.rb @@ -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 diff --git a/app/controllers/forks_controller.rb b/app/controllers/forks_controller.rb index 967c1d4d2..0842d2e67 100644 --- a/app/controllers/forks_controller.rb +++ b/app/controllers/forks_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index ecabeca21..90ed5bc37 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -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 diff --git a/app/helpers/admins/glcc_pr_check_helper.rb b/app/helpers/admins/glcc_pr_check_helper.rb new file mode 100644 index 000000000..9934b83bf --- /dev/null +++ b/app/helpers/admins/glcc_pr_check_helper.rb @@ -0,0 +1,2 @@ +module Admins::GlccPrCheckHelper +end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index ee783da87..a10ad34ca 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -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 diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 28bbccf63..a99948879 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -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 diff --git a/app/models/glcc_medium_term_examine_material.rb b/app/models/glcc_medium_term_examine_material.rb new file mode 100644 index 000000000..ca4cf2e7a --- /dev/null +++ b/app/models/glcc_medium_term_examine_material.rb @@ -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 + "

PR链接为非GitLink平台链接

" + when 2 + "

PR链接为GitLink平台链接, 但非PR链接

" + when 3 + "

PR链接中的PR不存在

" + end + end +end diff --git a/app/models/glcc_registration_student.rb b/app/models/glcc_registration_student.rb new file mode 100644 index 000000000..3ea0c3134 --- /dev/null +++ b/app/models/glcc_registration_student.rb @@ -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 diff --git a/app/models/glcc_registration_task.rb b/app/models/glcc_registration_task.rb new file mode 100644 index 000000000..7c8671e6f --- /dev/null +++ b/app/models/glcc_registration_task.rb @@ -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 diff --git a/app/queries/admins/glcc_examine_material.rb b/app/queries/admins/glcc_examine_material.rb new file mode 100644 index 000000000..4e8f2bea7 --- /dev/null +++ b/app/queries/admins/glcc_examine_material.rb @@ -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 \ No newline at end of file diff --git a/app/services/api_limit_service.rb b/app/services/api_limit_service.rb new file mode 100644 index 000000000..d22684962 --- /dev/null +++ b/app/services/api_limit_service.rb @@ -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 diff --git a/app/services/leaky_bucket_rate_limiter.rb b/app/services/leaky_bucket_rate_limiter.rb new file mode 100644 index 000000000..2508e99e0 --- /dev/null +++ b/app/services/leaky_bucket_rate_limiter.rb @@ -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 \ No newline at end of file diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb index a46b8d86a..37edf56ee 100644 --- a/app/services/projects/fork_service.rb +++ b/app/services/projects/fork_service.rb @@ -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'] diff --git a/app/services/sliding_window_rate_limiter.rb b/app/services/sliding_window_rate_limiter.rb new file mode 100644 index 000000000..a999345ef --- /dev/null +++ b/app/services/sliding_window_rate_limiter.rb @@ -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 \ No newline at end of file diff --git a/app/services/token_bucket_rate_limiter.rb b/app/services/token_bucket_rate_limiter.rb new file mode 100644 index 000000000..c0d726b37 --- /dev/null +++ b/app/services/token_bucket_rate_limiter.rb @@ -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 \ No newline at end of file diff --git a/app/views/admins/glcc_pr_check/_examine_material.html.erb b/app/views/admins/glcc_pr_check/_examine_material.html.erb new file mode 100644 index 000000000..ac8e550ac --- /dev/null +++ b/app/views/admins/glcc_pr_check/_examine_material.html.erb @@ -0,0 +1,58 @@ + + + + + + + + + + + 60 + + + + + + + + <% if examine_materials.present? %> + <% examine_materials.each_with_index do |material, index| %> + + + + + + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号学生姓名课题ID课题名称邮件地址视频地址PR地址考核阶段白名单检测状态提交时间
<%= list_index_no((params[:page] || 1).to_i, index) %><%= material.glcc_student.student_name %><%= material.task_id %><%= material.task.task_name %> + + <%=material.glcc_student.mail.truncate(20) %> + + + + + <%= material.defence_video_url.nil? ? "" : material.defence_video_url.truncate(30) %> + + + + + + <%= material.code_or_pr_url.nil? ? "" : material.code_or_pr_url.truncate(30) %> + + + <%= material.term == 1 ? "中期考核" : "结项考核"%><%= material.white_list ? "是":"否" %><%= material.state_to_html.blank?&&!material.white_list ? "通过" : material.state_to_html.html_safe %><%= material.created_on.strftime("%Y-%m-%d %H:%M")%>
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: examine_materials } %> diff --git a/app/views/admins/glcc_pr_check/index.html.erb b/app/views/admins/glcc_pr_check/index.html.erb new file mode 100644 index 000000000..a70a09f6e --- /dev/null +++ b/app/views/admins/glcc_pr_check/index.html.erb @@ -0,0 +1,44 @@ +
+ <%= form_tag(admins_glcc_pr_check_index_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> +
+ + <% status_options = [['中期考核',1], ['结项考核', 2]] %> + <%= select_tag(:term, options_for_select(status_options), class: 'form-control') %> +
+ +
+ + <%= select_year(Date.today, {field_name:"year"}, {class:"form-control"})%> + +
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> + <% end %> + +
+ + + +
+ <%= render partial: 'examine_material', locals: { examine_materials: @examine_materials } %> +
+ + diff --git a/app/views/admins/glcc_pr_check/index.js.erb b/app/views/admins/glcc_pr_check/index.js.erb new file mode 100644 index 000000000..8bc043f70 --- /dev/null +++ b/app/views/admins/glcc_pr_check/index.js.erb @@ -0,0 +1 @@ +$('.glcc-examine-list-container').html("<%= j( render partial: 'examine_material', locals: { examine_materials: @examine_materials } ) %>"); \ No newline at end of file diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index fc2fe6068..481676b8f 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -57,6 +57,7 @@ <%= sidebar_item(EduSetting.get("glcc_apply_informations_admin_url"), '报名列表', icon: 'user', controller: 'root') %> <% end %> +
  • <%= sidebar_item(admins_glcc_pr_check_index_path, '考核PR检测', icon: 'edit', controller: 'admins-glcc_pr_check') %>
  • <% end %>
  • diff --git a/app/views/forks/fork_list.json.jbuilder b/app/views/forks/fork_list.json.jbuilder deleted file mode 100644 index 185b8e4fc..000000000 --- a/app/views/forks/fork_list.json.jbuilder +++ /dev/null @@ -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 diff --git a/app/views/user_mailer/glcc_pr_check_email.html.erb b/app/views/user_mailer/glcc_pr_check_email.html.erb new file mode 100644 index 000000000..aa01d45bf --- /dev/null +++ b/app/views/user_mailer/glcc_pr_check_email.html.erb @@ -0,0 +1,71 @@ + + + + + 验证码发送 + + + + + +
    +
    +
    + + + +
    +
    +
    + +

    + 尊敬的<%=@name%>同学: +

    + +

    +   您好!经过一个多月的开发,GLCC开源编程夏令营终于迎来中期考核。为了确保您能够顺利通过考核,现对您提交的PR链接进行检测,发现存在以下问题: +

    + +
    + <%=@content.html_safe%> +
    + +

    +   您提交的PR链接的真实有效性对于后期的开发和奖金的发放至关重要,请您务必予以重视。请您尽快核查链接的有效性,并按照组委会要求提交中期考核材料。若确认链接无误,请忽略本邮件。​ +

    + +

    +   如有其他问题,请联系:glcc@ccf.org.cn +

    + +

    + GLCC组委会 +

    +

    + <%=Time.now.strftime('%Y年%m月%d日')%> +

    +
    +
    + www.gitlink.org.cn +
    +
    +
    + + diff --git a/config/routes.rb b/config/routes.rb index 8750508ea..6d9fda2e9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/spec/controllers/admins/glcc_pr_check_controller_spec.rb b/spec/controllers/admins/glcc_pr_check_controller_spec.rb new file mode 100644 index 000000000..1dfcff7d4 --- /dev/null +++ b/spec/controllers/admins/glcc_pr_check_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Admins::GlccPrCheckController, type: :controller do + +end diff --git a/spec/helpers/admins/glcc_pr_check_helper_spec.rb b/spec/helpers/admins/glcc_pr_check_helper_spec.rb new file mode 100644 index 000000000..d47be7eda --- /dev/null +++ b/spec/helpers/admins/glcc_pr_check_helper_spec.rb @@ -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