Compare commits

...

23 Commits

Author SHA1 Message Date
anph d76d85b8fb change 2023-10-07 15:09:30 +08:00
anph 82907e001f update 2023-09-22 21:10:33 +08:00
anph b8f9deb1ed GLCC 2023-08-15 00:15:10 +08:00
jasder 4fa10a3683 Merge pull request 'fix mege develop' (#248) from develop into master 2021-11-14 20:39:31 +08:00
jasder f13b8009ad Merge pull request 'fix code review' (#246) from jasder/forgeplus:develop into develop 2021-11-11 18:21:51 +08:00
jasder e216d7da70 Merge branch 'develop' of https://git.trustie.net/Gitlink/forgeplus into develop 2021-11-11 18:09:26 +08:00
jasder 0106f2d5dd Merge pull request '存在问题修复' (#244) from yystopf/forgeplus:hh_hotfix into develop 2021-11-11 18:09:08 +08:00
jasder 4f33e1194c Merge branch 'featrue_codereview' into develop 2021-11-11 18:06:08 +08:00
jasder 03beee6cae FIX code review 2021-11-11 18:03:30 +08:00
yystopf 49c7827f87 fix 2021-11-10 16:40:11 +08:00
yystopf 222e5c1050 fix: atme sender info 2021-11-10 11:32:59 +08:00
yystopf 1298fedcbb fix: user rank 2021-11-10 10:47:03 +08:00
yystopf 937603d0f2 fix: change params is blank not sent email 2021-11-10 10:05:35 +08:00
yystopf 685d2b80f2 fix 2021-11-10 09:43:22 +08:00
yystopf 2e35fb92a9 fix: change message template email title 2021-11-09 17:04:45 +08:00
yystopf c4e88ad690 fix 2021-11-09 16:56:49 +08:00
yystopf e316a60433 fix: pullrequest fork_project_user_name 2021-11-09 16:56:49 +08:00
jasder f1f4867b8c Merge pull request 'FIX sync user info' (#243) from jasder/forgeplus:develop into develop 2021-11-08 16:31:01 +08:00
jasder cb11a5c8e9 发布v3.1.1版本
* FIX 修复pulls、issues 搜索数量统计问题
* FIX 解决在线创建文件错误提示信息不准确的问题
* FIX table name bug
* FIX 解决applied_projects相关表操作的问题
* FIX 解决排序参数的判断预防SQL注入
* FIX 项目导航栏数量改为开启中的数量
* FIX 解决项目邀请码的索引查询问题
* FIX FIX get readme file bug
* FIX sql attack
* FIX projects load by invite code slowly
2021-06-18 17:09:57 +08:00
jasder c5d73b7cf8 v3.1.0
* 改版升级个人主页
* 修复bug
* 更改license
2021-06-09 09:52:57 +08:00
jasder 8a10a183e0 Merge branch 'develop' 2021-05-24 10:18:03 +08:00
jasder 6d1bcabd51 Merge branch 'master' of https://git.trustie.net/jasder/forgeplus 2021-05-24 10:10:24 +08:00
jasder 86f03ffafc Merge OK 2021-05-08 17:46:22 +08:00
313 changed files with 816 additions and 6283 deletions

View File

@ -124,6 +124,7 @@ class AccountsController < ApplicationController
password = register_params[:password].strip
# gitea用户注册, email, username, password
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
if interactor.success?
gitea_user = interactor.result
@ -138,6 +139,7 @@ class AccountsController < ApplicationController
else
tip_exception(-1, interactor.error)
end
rescue Register::BaseForm::EmailError => e
render_error(-2, e.message)
rescue Register::BaseForm::LoginError => e

View File

@ -33,12 +33,13 @@ class Admins::ProjectCategoriesController < Admins::BaseController
end
def update
if @project_category.update_attributes({name: @name, pinned_index: params[:project_category][:pinned_index].to_i}) && save_image_file(params[:logo], 'logo')
if @project_category.update_attributes({name: @name, pinned_index: params[:project_category][:pinned_index].to_i})
save_image_file(params[:logo], 'logo')
redirect_to admins_project_categories_path
flash[:success] = '更新成功'
else
redirect_to admins_project_categories_path
flash[:success] = '更新失败'
flash[:danger] = '更新失败'
end
end

View File

@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base
when 1, 2, 4, 9
# 手机类型的发送
sigle_para = {phone: value}
status = Educoder::Sms.send(mobile: value, code: code)
status = Gitlink::Sms.send(mobile: value, code: code)
tip_exception(-2, code_msg(status)) if status != 0
when 8, 3, 5
# 邮箱类型的发送
@ -183,7 +183,7 @@ class ApplicationController < ActionController::Base
# 异常提醒
def tip_exception(status = -1, message)
raise Educoder::TipException.new(status, message)
raise Gitlink::TipException.new(status, message)
end
def missing_template
@ -192,7 +192,7 @@ class ApplicationController < ActionController::Base
# 弹框提醒
def tip_show_exception(status = -2, message)
raise Educoder::TipException.new(status, message)
raise Gitlink::TipException.new(status, message)
end
def normal_status(status = 0, message)
@ -265,25 +265,25 @@ class ApplicationController < ActionController::Base
end
end
# if !User.current.logged? && Rails.env.development?
# User.current = User.find 1
# end
if !User.current.logged? && Rails.env.development?
User.current = User.find 104
end
# 测试版前端需求
logger.info("subdomain:#{request.subdomain}")
if request.subdomain != "www"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
user = User.find 36480
User.current = user
cookies.signed[:user_id] = user.id
end
end
# if request.subdomain != "www"
# if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
# User.current = User.find 81403
# elsif params[:debug] == 'student'
# User.current = User.find 8686
# elsif params[:debug] == 'admin'
# logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
# user = User.find 36480
# User.current = user
# cookies.signed[:user_id] = user.id
# end
# end
# User.current = User.find 81403
end
@ -373,7 +373,7 @@ class ApplicationController < ActionController::Base
JSON.parse(res)
rescue Exception => e
uid_logger_error("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new("实训平台繁忙繁忙等级84")
raise Gitlink::TipException.new("实训平台繁忙繁忙等级84")
end
end
@ -392,7 +392,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new(message)
raise Gitlink::TipException.new(message)
end
end
@ -416,7 +416,7 @@ class ApplicationController < ActionController::Base
end
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new("服务器繁忙")
raise Gitlink::TipException.new("服务器繁忙")
end
end
@ -588,8 +588,8 @@ class ApplicationController < ActionController::Base
# 获取Oauth Client
def get_client(site)
client_id = Rails.configuration.educoder['client_id']
client_secret = Rails.configuration.educoder['client_secret']
client_id = Rails.configuration.Gitlink['client_id']
client_secret = Rails.configuration.Gitlink['client_secret']
OAuth2::Client.new(client_id, client_secret, site: site)
end

View File

@ -196,7 +196,7 @@ class AttachmentsController < ApplicationController
end
def file_save_to_ucloud(path, file, content_type)
ufile = Educoder::Ufile.new(
ufile = Gitlink::Ufile.new(
ucloud_public_key: edu_setting('public_key'),
ucloud_private_key: edu_setting('private_key'),
ucloud_public_read: true,

View File

@ -20,7 +20,7 @@ module ControllerRescueHandler
end
# rescue_from ActionView::MissingTemplate, with: :object_not_found
# rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from Educoder::TipException, with: :tip_show
rescue_from Gitlink::TipException, with: :tip_show
rescue_from ::ActionView::MissingTemplate, with: :missing_template
rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from ActionController::ParameterMissing, with: :render_parameter_missing

View File

@ -36,10 +36,10 @@ module GitCommon
begin
@commits = GitService.commits(repo_path: @repo_path)
logger.info("git first commit is #{@commits.try(:first)}")
raise Educoder::TipException.new("请先创建版本库") if @commits.nil?
raise Gitlink::TipException.new("请先创建版本库") if @commits.nil?
rescue Exception => e
uid_logger_error(e.message)
raise Educoder::TipException.new("提交记录异常")
raise Gitlink::TipException.new("提交记录异常")
end
end

View File

@ -34,7 +34,7 @@ module GitHelper
rescue Exception => e
Rails.logger.error(e.message)
raise Educoder::TipException.new("文档内容获取异常")
raise Gitlink::TipException.new("文档内容获取异常")
end
end
@ -64,7 +64,7 @@ module GitHelper
# 版本库Fork功能
def project_fork(container, original_rep_path, username)
raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?
raise Gitlink::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?
# 将要生成的仓库名字
new_repo_name = "#{username.try(:strip)}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}"
# uid_logger("start fork container: repo_name is #{new_repo_name}")

View File

@ -14,6 +14,22 @@ class Organizations::ProjectsController < Organizations::BaseController
@projects = paginate(@projects)
end
#######################change#################################
def organizationBadge
watchers_count = @organization.watchers_count
@watchered = judge_level(watchers_count, 10, 20, 100)
@badge = organizationBadge.find_or_create_by(organization_id: @organization.id)
if @watchered != @badge.watched
@badge.watched = @watchered
@badge.save
end
render :json => {list: [{watchered: @watchered}], count: 1}
end
#######################change#################################
def search
tip_exception("请输入搜索关键词") if params[:search].nil?
public_projects_sql = @organization.projects.where(is_public: true).to_sql
@ -42,4 +58,17 @@ class Organizations::ProjectsController < Organizations::BaseController
def sort_direction
%w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
end
def judge_level(judged, low, mid, high)
if judged < low
return 0
elsif judged < mid
return 1
elsif judged < high
return 2
else
return 3
end
end
end

View File

@ -6,7 +6,6 @@ class Organizations::TeamProjectsController < Organizations::BaseController
def index
@team_projects = @team.team_projects
@team_projects = paginate(@team_projects)
end

View File

@ -12,12 +12,58 @@ class RepositoriesController < ApplicationController
before_action :get_ref, only: %i[entries sub_entries top_counts file archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts]
before_action :preload_badge, only: [:badges]
def files
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
render json: result
end
def preload_badge
@praised_cache = "praised"
@forked_cache = "forked"
@watchered_cache = "watchered"
@badge = RepositoryBadge.find_or_create_by(user_id: observed_user.id)
$redis_cache.hset(project_statistic_key, @many_projects_cache, @badge.many_projects)
$redis_cache.hset(project_statistic_key, @manyParisesProject_cache, @badge.manyParisesProject)
$redis_cache.hset(project_statistic_key, @parises_project_cache, @badge.parises_project)
end
####################change for repository############################
def badges
preload_badge
@badges_dic = Hash.new(0)
praises_count = @project.praises_count.to_i
forked_count = @project.forked_count.to_i
watchers_count = @project.watchers_count.to_i
@praised = judge_level(praises_count, 10, 20,100)
redis_judge_reload @praised_cache, @praised
@badges_dic["praised_cache"] = $redis_cache.hget(project_statistic_key, @praised_cache).to_i
@forked = judge_level(forked_count, 5, 10,100)
redis_judge_reload @forked_cache, @forked
@badges_dic["forked_cache"] = $redis_cache.hget(project_statistic_key, @forked_cache).to_i
@watchered = judge_level(watchers_count, 10, 20,100)
redis_judge_reload @watchered_cache, @watchered
@badges_dic["forked_cache"] = $redis_cache.hget(project_statistic_key, @forked_cache).to_i
badges_visable = Array.new
@badges_dic.each do |key,value|
if value > 0
badges_visable.append({"#{key}":value})
end
end
render :json => {list: badges_visable, count: badges_visable.size}
end
##########################################################
# 新版项目详情
def detail
@user = current_user
@ -355,4 +401,37 @@ class RepositoriesController < ApplicationController
end
end
def judge_level(judged, low, mid, high)
if judged < low
return 0
elsif judged < mid
return 1
elsif judged < high
return 2
else
return 3
end
end
def redis_judge_reload(judge_cache, new_value)
if $redis_cache.hget(project_statistic_key, judge_cache).to_i != new_value
$redis_cache.del(project_statistic_key)
updateService judge_cache, new_value
load_redis
end
end
def project_statistic_key
"project:#{@project.id}"
end
def updateService(update_name, update_value)
@badge = RepositoryBadge.find_or_create_by(user_id: observed_user.id)
@badge.update_attribute(update_name,update_value)
@badge.save
end
end

View File

@ -1,5 +1,6 @@
class Users::StatisticsController < Users::BaseController
class Users::StatisticsController < Users::BaseController
before_action :preload_develop_data, only: [:develop]
before_action :preload_badge_data, only: [:badges]
# 近期活动统计
def activity
@ -20,6 +21,35 @@ class Users::StatisticsController < Users::BaseController
render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data}
end
###############change###############
# 用户badges 接口 url 路径为/api/users/:user_id/statistic/badges
# 三类
# 第一类 贡献类
# 1. 用户累积获得高星
# 2. 用户关注数超过10人
# 3. 用户的累积获赞人数
# 4. 用户连续一周有commit
# 5. 用户累积pr数
# 第二类 活动类
# 第三类 特殊类
def badges
badges_visable = Array.new
@badges_dic.each do |key,value|
if value > 0
#与describe同理此处应该再增加一个 url字典
describe = @badges_describe_dic[key]
badges_visable.append({"#{key}":value, "describe":describe})
end
end
render :json => {list: badges_visable, count: badges_visable.size}
end
###############change###############
# 开发能力
def develop
if params[:start_time].present? && params[:end_time].present?
@ -216,4 +246,207 @@ class Users::StatisticsController < Users::BaseController
@platform_project_languages_count = JSON.parse(@platform_result["project-language"])
end
end
end
end
def count_filter(collection, count_field, countf)
return collection.where("#{count_field} >= ?", countf)
end
# 判断是否拥有
def judge_have(judged, count)
return judged >= count ? 1 : 0
end
# 判断等级
def judge_level(judged, low, mid, high)
if judged < low
return 0
elsif judged < mid
return 1
elsif judged < high
return 2
else
return 3
end
end
###############change###############
# 用户badges 接口 url 路径为/api/users/:user_id/statistic/badges
# 三类
# 第一类 贡献类
# 2.用户有项目获得高星
# 3.用户有数个高星项目
# 4.用户拥有一个点赞数很高的项目
# 5.用户拥有数个点赞数很高的项目
# 6. 用户关注数超过10人
# 7. 用户的累积获赞人数
# 8. 用户累积pr数
# 第二类 活动类
# 第三类 活跃类
# 1. 用户拥有10个项目以上
# 2. 用户连续一周/月有commit
# 3. 用户涨粉迅速
def preload_badge_data
badge_describe
cache_describe
#加载缓存资源
load_redis
#存放用户获得的徽章字典
@badges_dic = Hash.new(0)
# 有些数据可以考虑直接从缓存中读取,由于题目要求不能破坏原本的函数,暂时缓存写了直接查询,
# 例如 Watcher.where(watchable: observed_user).count 可以用@user_result["follow-count"]来替代
#
@user_result = Cache::V2::UserStatisticService.new(observed_user.id).read
# 用户项目获得的徽章
#用户语言数量 y
# 用户项目数量 y
project_count = @user_result["project-count"].to_i
if project_count > 10
@badges_dic["project_count"] = project_count
end
# 用户点赞数量 y
# 用户项目被follow数量
praises_project_count = count_filter(Project.where(user_id:observed_user.id), 'praises_count' , 10).count
praises_project = Project.where(user_id:observed_user.id).maximum('praises_count')
watchers_project_count = count_filter(Project.where(user_id:observed_user.id), 'watchers_count' , 10).count
watchers_project = Project.where(user_id:observed_user.id).maximum('watchers_count')
# 项目数
@many_projects = judge_have(project_count, 5)
redis_judge_reload @many_projects_cache, @many_projects
@badges_dic["many_projects"] = $redis_cache.hget(user_statistic_key, @many_projects_cache).to_i
# 用户有超过五个以上的高点赞项目
@manyParisesProject = judge_have(praises_project_count, 5)
redis_judge_reload @manyParisesProject_cache, @manyParisesProject
@badges_dic["manyParisesProject"] = $redis_cache.hget(user_statistic_key, @manyParisesProject_cache).to_i
#用户有一个点赞数很高的项目 金/银/铜
@parises_project = judge_level(praises_project, 3, 5, 10)
redis_judge_reload @many_projects_cache, @parises_project
@badges_dic["parises_project"] = $redis_cache.hget(user_statistic_key, @parises_project_cache).to_i
# 用户有超过五个以上的高关注项目
@manyWatchersProject = judge_have(watchers_project_count, 5)
redis_judge_reload @manyWatchersProject_cache, @manyWatchersProject
@badges_dic["manyWatchersProject"] = $redis_cache.hget(user_statistic_key, @manyWatchersProject_cache).to_i
#用户有一个关注数很高的项目 金/银/铜
@watchers_project = judge_level(watchers_project, 3, 5, 10)
redis_judge_reload @watchers_project_cache, @watchers_project
@badges_dic["watchers_project"] = $redis_cache.hget(user_statistic_key, @watchers_project_cache).to_i
# 用户被follow数量 y
fans = Watcher.where(watchable: observed_user).count
# 用户pr数量 y
pr = PullRequest.where(user_id: observed_user.id).count
# 用户issue数量 y
issue = Issue.where(author_id: observed_user.id).count
#用户有关注数很多 金/银/铜
@many_fans = judge_level(fans, 5, 50, 100)
redis_judge_reload @many_fans_cache, @many_fans
@badges_dic["many_fans"] = $redis_cache.hget(user_statistic_key, @many_fans_cache).to_i
#用户pr很多 金/银/铜
@many_pr = judge_level(pr, 5, 50, 100)
redis_judge_reload @many_pr_cache, @many_pr
@badges_dic["many_pr"] = $redis_cache.hget(user_statistic_key, @many_pr_cache).to_i
#用户issue很多 金/银/铜
@many_issue = judge_level(issue, 5, 50, 100)
redis_judge_reload @many_issue_cache, @many_issue
@badges_dic["many_issue"] = $redis_cache.hget(user_statistic_key, @many_issue_cache).to_i
#一周内活跃
commit_request = Gitea::User::HeadmapService.call(observed_user.login, 1.week.ago.to_date.to_time.to_i, Date.today.to_time.to_i)
commit_data = commit_request[2]
active_commit = commit_data.select{|item| item["contributions"] >= 1}.size
@active_in_week = active_commit == 7 ? 1 : 0
@badges_dic["active_in_week"] = $redis_cache.hget(user_statistic_key, @active_in_week_cache).to_i
#TODO fans_raise_quickly
end
def user_statistic_key
"user:#{@user_id}"
end
def redis_judge_reload(judge_cache, new_value)
if $redis_cache.hget(user_statistic_key, judge_cache).to_i != new_value
$redis_cache.del(user_statistic_key)
updateService judge_cache, new_value
load_redis
end
end
def cache_describe
@many_projects_cache = "many_projects"
@manyParisesProject_cache = "manyParisesProject"
@parises_project_cache = "parises_project"
@manyWatchersProject_cache = "manyWatchersProject"
@watchers_project_cache = "watchers_project"
@many_fans_cache = "many_fans"
@many_pr_cache = "many_pr"
@many_issue_cache = "many_issue"
@active_in_week_cache = "active_in_week"
end
def badge_describe
@badges_describe_dic = Hash.new(0)
@badges_describe_dic["many_projects"] = "参与了多个project"
@badges_describe_dic["manyParisesProject"] = "有多个点赞数高的project"
@badges_describe_dic["parises_project"] = "有一个项目获得了很高的点赞数!"
@badges_describe_dic["manyWatchersProject"] = "有多个关注三诉讼诉讼诉讼诉讼诉讼诉讼数高的project"
@badges_describe_dic["watchers_project"] = "有一个项目获得了很高的关注数!"
@badges_describe_dic["watchers_project"] = "有一个项目获得了很高的关注数!"
@badges_describe_dic["many_fans"] = "粉丝数很多!"
@badges_describe_dic["many_fans"] = "贡献了很多pr"
@badges_describe_dic["many_pr"] = "贡献了很多issue"
@badges_describe_dic["many_issue"] = "粉丝数很多!"
@badges_describe_dic["active_in_week"] = "一周活跃打卡成就!"
end
def load_redis
@badge = Badge.find_or_create_by(user_id: observed_user.id)
$redis_cache.hset(user_statistic_key, @many_projects_cache, @badge.many_projects)
$redis_cache.hset(user_statistic_key, @manyParisesProject_cache, @badge.manyParisesProject)
$redis_cache.hset(user_statistic_key, @parises_project_cache, @badge.parises_project)
$redis_cache.hset(user_statistic_key, @manyWatchersProject_cache, @badge.manyWatchersProject)
$redis_cache.hset(user_statistic_key, @watchers_project_cache, @badge.watchers_project)
$redis_cache.hset(user_statistic_key, @many_fans_cache, @badge.many_fans)
$redis_cache.hset(user_statistic_key, @many_pr_cache, @badge.many_pr)
$redis_cache.hset(user_statistic_key, @many_issue_cache, @badge.many_issue)
$redis_cache.hset(user_statistic_key, @active_in_week_cache, @badge.active_in_week)
end
def updateService(update_name, update_value)
#添加事务,如果更新失败则回滚
ActiveRecord::Base.transaction do
@badge = Badge.find_or_create_by!(user_id: observed_user.id)
@badge.update_attributes!(update_name => update_value)
@badge.save!
end
end

View File

@ -1,5 +0,0 @@
module CourseDecorator
def can_visited?
is_public == 1 || User.current.admin_or_business? || User.current.member_of_course?(self)
end
end

View File

@ -1,2 +0,0 @@
module EcCourseTargetDecorator
end

View File

@ -1,16 +0,0 @@
module ExperienceDecorator
def container_type_text
I18n.t("experience.container_type.#{container_type.to_s.underscore}")
end
def content
case container_type.to_s.underscore
when 'game' then
game = Game.find_by(id: container_id)
game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : ''
when 'shixun_publish' then
shixun = Shixun.find_by(id: container_id)
shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : ''
end
end
end

View File

@ -1,39 +0,0 @@
module GradeDecorator
def container_type_text
I18n.t("grade.container_type.#{container_type.to_s.underscore}")
end
def content
case container_type.to_s.underscore
when 'avatar' then '用户首次上传头像获得的奖励'
when 'phone' then '用户首次绑定手机号码获得的奖励'
when 'mail' then '用户首次绑定邮箱获得的奖励'
when 'attendance' then '用户每天签到获得的奖励'
when 'account' then '新用户首次填写基本资料获得的奖励'
when 'memo' then '发布的评论或者帖子获得平台奖励'
when 'discusses' then '发布的评论获得平台奖励'
when 'star' then '用户给实训评分获得的随机奖励'
when 'feedback' then '反馈的问题获得平台奖励'
when 'authentication' then '用户首次完成实名认证获得的奖励'
when 'professional' then '用户首次完成职业认证获得的奖励'
when 'answer' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的参考答案消耗的金币" : ''
when 'game' then
game = Game.find_by(id: container_id)
game.present? ? "通过实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关获得的奖励" : ''
when 'test_set' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”的第#{game.challenge.position}关的隐藏测试集消耗的金币" : ''
when 'shixun_publish' then
shixun = Shixun.find_by(id: container_id)
shixun.present? ? "发布实训“#{shixun.name}”获得的奖励" : ''
when 'check_ta_answer' then
game = Game.find_by(id: container_id)
game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的TA人解答消耗的金币" : ''
when 'hack' then
hack = Hack.find_by(id: container_id)
hack.present? ? "完成了题目解答“#{hack.name}”,获得金币奖励:#{hack.score}" : ''
end
end
end

View File

@ -1,5 +0,0 @@
module LibraryDecorator
extend ApplicationDecorator
display_time_method :published_at, :created_at, :updated_at
end

View File

@ -1,5 +0,0 @@
module ShixunDecorator
def human_status
I18n.t("shixun.status.#{status}")
end
end

View File

@ -1,5 +0,0 @@
module SubjectDecorator
def can_visited?
published? || User.current.admin? || member?(User.current)
end
end

View File

@ -1,5 +0,0 @@
module VideoDecorator
extend ApplicationDecorator
display_time_method :published_at, :created_at, :updated_at
end

View File

@ -1,10 +0,0 @@
class AddSchoolApplyForm
include ActiveModel::Model
attr_accessor :name, :province, :city, :address, :remarks
validates :name, presence: true
# validates :province, presence: true
# validates :city, presence: true
# validates :address, presence: true
end

View File

@ -1,27 +0,0 @@
class ApplyShixunMirrorForm
include ActiveModel::Model
attr_accessor :language, :runtime, :run_method, :attachment_id
validates :language, presence: true
validates :runtime, presence: true
validates :run_method, presence: true
validates :attachment_id, presence: true, numericality: { only_integer: true }
validate :ensure_attachment_presence
def ensure_attachment_presence
return unless attachment_id
if attachment.blank?
errors.add(:attachment_id, :attachment_not_exist)
end
end
def attachment
@attachment ||= Attachment.find_by_id(attachment_id)
end
def to_json
{ language: language, runtime: runtime, run_method: run_method, attachment_id: attachment_id }.to_json
end
end

View File

@ -1,15 +0,0 @@
class ExaminationBanks::SaveExamForm
include ActiveModel::Model
attr_accessor :discipline_id, :sub_discipline_id, :difficulty, :name, :duration, :tag_discipline_id
validates :discipline_id, presence: true
validates :sub_discipline_id, presence: true
validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
validates :name, presence: true, length: { maximum: 60, too_long: "不能超过60个字符" }
validate :validate_duration
def validate_duration
raise '时长应为大于0的整数' if duration.present? && duration.to_i < 1
end
end

View File

@ -1,12 +0,0 @@
class ExaminationIntelligentSettings::SaveExamForm
include ActiveModel::Model
attr_accessor :name, :duration
validates :name, presence: true, length: { maximum: 60 }
validate :validate_duration
def validate_duration
raise '时长应为大于0的整数' if duration.present? && duration.to_i < 1
end
end

View File

@ -1,11 +0,0 @@
class ExaminationIntelligentSettings::SaveExamSettingForm
include ActiveModel::Model
attr_accessor :discipline_id, :sub_discipline_id, :source, :difficulty, :tag_discipline_id, :question_settings
validates :discipline_id, presence: true
validates :sub_discipline_id, presence: true
validates :source, presence: true
validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
validates :question_settings, presence: true
end

View File

@ -41,7 +41,7 @@ module Register
def check_verifi_code(verifi_code, code)
code = strip(code)
# return if code == "123123" # TODO 万能验证码,用于测试
return if code == "123123" # TODO 万能验证码,用于测试
raise VerifiCodeError, "验证码不正确" if verifi_code&.code != code
raise VerifiCodeError, "验证码已失效" if !verifi_code&.effective?

View File

@ -1,20 +0,0 @@
class Weapps::CreateCourseForm
include ActiveModel::Model
attr_accessor :course
attr_accessor :name, :course_list_name, :credit, :course_module_types, :end_date
validates :name, presence: true
validates :course_list_name, presence: true
validate :course_name_prefix
validate :check_course_modules
def course_name_prefix
raise '课堂名称应以课程名称开头' unless name.index(course_list_name) && name.index(course_list_name) == 0
end
def check_course_modules
raise '请至少添加一个课堂模块' if course_module_types.blank?
end
end

View File

@ -1,15 +0,0 @@
class Weapps::UpdateCourseForm
include ActiveModel::Model
attr_accessor :course
attr_accessor :name, :course_list_name, :credit, :end_date
validates :name, presence: true
validates :course_list_name, presence: true
validate :course_name_prefix
def course_name_prefix
raise '课堂名称应以课程名称开头' unless name.index(course_list_name) && name.index(course_list_name) == 0
end
end

View File

@ -4,7 +4,7 @@ module Admins::ProjectsHelper
owner = project.owner
if owner.is_a?(User)
link_to(project.owner&.real_name, "/users/#{project&.owner&.login}", target: '_blank')
link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank')
elsif owner.is_a?(Organization)
link_to(project.owner&.real_name, "/organize/#{project&.owner&.login}", target: '_blank')
else

View File

@ -1,6 +1,6 @@
# 所有的方法请按首字母的顺序依次列出
module ApplicationHelper
include Educoder::I18n
include Gitlink::I18n
include GitHelper
ONE_MINUTE = 60 * 1000

View File

@ -1,2 +0,0 @@
module BoardsHelper
end

View File

@ -1,10 +0,0 @@
module ChallengesHelper
def match_begin_symbol str
str.gsub(/\A\r/, "\r\r")
end
end

View File

@ -1,2 +0,0 @@
module CourseGroupsHelper
end

View File

@ -1,2 +0,0 @@
module CourseModulesHelper
end

View File

@ -1,2 +0,0 @@
module CourseSecondCategoriesHelper
end

View File

@ -1,2 +0,0 @@
module CourseStagesHelper
end

View File

@ -1,298 +0,0 @@
module CoursesHelper
def member_manager group, teachers
str = ""
members = teachers.select{|teacher| teacher.teacher_course_groups.pluck(:course_group_id).include?(group.id) || teacher.teacher_course_groups.size == 0}
str = members.uniq.size == teachers.size ? "全部教师" : members.map{|member| member.user.real_name}.join("")
str
# teachers.each do |member|
# if member.teacher_course_groups.exists?(course_group_id: group.id) || member.teacher_course_groups.size == 0
# str << member.user.real_name
# end
# end
end
def edit_auth group, teachers
User.current.admin_or_business? ||
teachers.select{|teacher| teacher.user_id == User.current.id &&
(teacher.teacher_course_groups.pluck(:course_group_id).include?(group.id) || teacher.teacher_course_groups.size == 0)}.size > 0
end
# 是否有切换为学生的入口
def switch_student_role is_teacher, course, user
is_teacher && course.course_members.where(user_id: user.id, role: %i(STUDENT)).exists?
end
# 是否有切换为教师的入口
def switch_teacher_role is_student, course, user
is_student && course.course_members.where(user_id: user.id, role: %i(CREATOR PROFESSOR)).exists?
end
# 是否有切换为助教的入口
def switch_assistant_role is_student, course, user
is_student && course.course_members.where(user_id: user.id, role: %i(ASSISTANT_PROFESSOR)).exists?
end
# 课堂结束天数
def course_end_date end_date
if end_date.present?
curr = Time.new
date = ((Date.parse(end_date.to_s) - Date.parse(curr.to_s)).to_i)
date > 0 ? "#{date}天后" : ""
end
end
# 课堂模块的url
def module_url mod, course
return nil if mod.blank? or course.blank?
case mod.module_type
when "announcement"
"/courses/#{course.id}/informs"
when "online_learning"
"/courses/#{course.id}/online_learning"
when "shixun_homework"
"/courses/#{course.id}/shixun_homeworks/#{mod.id}"
when "common_homework"
"/courses/#{course.id}/common_homeworks/#{mod.id}"
when "group_homework"
"/courses/#{course.id}/group_homeworks/#{mod.id}"
when "graduation"
"/courses/#{course.id}/graduation_topics/#{mod.id}"
when "exercise"
"/courses/#{course.id}/exercises/#{mod.id}"
when "poll"
"/courses/#{course.id}/polls/#{mod.id}"
when "attachment"
"/courses/#{course.id}/files/#{mod.id}"
when "board"
course_board = course.course_board
"/courses/#{course.id}/boards/#{course_board.id}"
when "course_group"
"/courses/#{course.id}/course_groups"
when "statistics"
"/courses/#{course.id}/statistics"
when "video"
"/courses/#{course.id}/course_videos"
end
end
# 子目录对应的url
def category_url category, course
case category.category_type
when "shixun_homework"
"/courses/#{course.id}/shixun_homework/#{category.id}"
when "graduation"
if category.name == "毕设选题"
"/courses/#{course.id}/graduation_topics/#{category.course_module_id}"
else
"/courses/#{course.id}/graduation_tasks/#{category.course_module_id}"
end
when "attachment"
"/courses/#{course.id}/file/#{category.id}"
end
end
# 子目录下的任务数
def category_task_count course, category, user
case category.category_type
when "shixun_homework"
get_homework_commons_count(course, 4, category.id)
when "graduation"
if category.name == "毕设选题"
course.graduation_topics_count
else
course.graduation_tasks_count
end
when "attachment"
get_attachment_count(course, category.id)
end
end
# 课堂模块的任务数
def course_task_count(course, module_type)
case module_type
when "shixun_homework"
get_homework_commons_count(course, 4, 0)
when "common_homework"
get_homework_commons_count(course, 1, 0)
when "group_homework"
get_homework_commons_count(course, 3, 0)
when "graduation"
0
when "exercise"
course.exercises_count
when "poll"
course.polls_count
when "attachment"
get_attachment_count(course, 0)
when "board"
course_board = course.course_board
course_board.present? ? course_board.messages.size : 0
when "course_group"
course.course_groups_count
when "announcement"
course.informs.count
when "online_learning"
course.shixuns.count
when "video"
course.course_videos.count + course.live_links.count
end
end
# 当前用户可见的课堂作业type指定作业类型 category_id指定二级目录
def visible_homework course, user, type, category_id=0
if user.teacher_of_course?(course)
homeworks = course.homework_commons.where("homework_type = #{type} and course_second_category_id = #{category_id}")
elsif user.member_of_course?(course)
member = course.course_members.find_by(user_id: user.id, role: 4)
if member.try(:course_group_id).to_i == 0
homeworks = course.homework_commons.where("homework_commons.homework_type = #{type} and publish_time <= '#{Time.now}'
and unified_setting = 1 and course_second_category_id = #{category_id}")
else
not_homework_ids = course.homework_group_settings.where("course_group_id = #{member.try(:course_group_id)} and
(publish_time > '#{Time.now}' or publish_time is null)").pluck(:homework_common_id)
# not_homework_ids = not_homework_ids.blank? ? "(-1)" : "(" + not_homework_ids.map(&:homework_common_id).join(",") + ")"
homeworks = course.homework_commons.where.not(id: not_homework_ids).where("homework_commons.homework_type = #{type} and publish_time <= '#{Time.now}'
and course_second_category_id = #{category_id}")
end
else
homeworks = course.homework_commons.where("homework_type = #{type} and publish_time <= '#{Time.now}' and unified_setting = 1
and course_second_category_id = #{category_id}")
end
homeworks
end
# 当前用户可见的课堂试卷
def visible_exercise course, user
if user.teacher_of_course?(course)
exercises = course.exercises
elsif user.member_of_course?(course)
member = course.course_members.find_by(user_id: user.id, role: 4)
if member.try(:course_group_id).to_i == 0
exercises = course.exercises.where("publish_time <= '#{Time.now}' and unified_setting = 1")
else
not_exercise_ids = course.exercise_group_settings.where("course_group_id = #{member.try(:course_group_id)} and
(publish_time > '#{Time.now}' or publish_time is null)").pluck(:exercise_id)
exercises = course.exercises.where.not(id: not_exercise_ids).where("publish_time <= '#{Time.now}'")
end
else
exercises = course.exercises.where("publish_time <= '#{Time.now}' and unified_setting = 1")
end
exercises
end
# 当前用户可见的课堂问卷
def visible_poll course, user
if user.teacher_of_course?(course)
polls = course.polls
elsif user.member_of_course?(course)
member = course.course_members.find_by(user_id: user.id, role: 4)
if member.try(:course_group_id).to_i == 0
polls = course.polls.where("publish_time <= '#{Time.now}' and unified_setting = 1")
else
not_poll_ids = course.poll_group_settings.where("course_group_id = #{member.try(:course_group_id)} and
(publish_time > '#{Time.now}' or publish_time is null)").pluck(:poll_id)
polls = course.polls.where.not(id: not_poll_ids).where("publish_time <= '#{Time.now}'")
end
else
polls = course.polls.where("publish_time <= '#{Time.now}' and unified_setting = 1")
end
polls
end
# 当前用户可见的课堂资源category_id指定资源的目录
def visible_attachment course, user, category_id=0
result = []
course.attachments.where(course_second_category_id: category_id).each do |attachment|
if attachment.unified_setting
if attachment.is_public == 1 && attachment.is_publish == 1 || user == attachment.author || user.teacher_of_course?(course) || (user.member_of_course?(course) && attachment.is_publish == 1)
result << attachment
end
else
if attachment.is_public == 1 && attachment.is_publish == 1 && !user.member_of_course?(course) || user == attachment.author || user.teacher_of_course?(course)
result << attachment
elsif user.member_of_course?(course) && attachment.is_publish == 1
member = course.course_members.find_by(user_id: user.id, role: 4)
if member.try(:course_group_id).to_i == 0 && attachment.unified_setting
result << attachment
elsif attachment.attachment_group_settings.where("course_group_id = #{member.try(:course_group_id)} and publish_time > '#{Time.now}'").count == 0
result << attachment
end
end
end
end
result
end
# 获取课堂的资源数
def get_attachment_count(course, category_id)
category_id.to_i == 0 ? course.attachments.size : course.attachments.where(course_second_category_id: category_id).size
end
# 获取课堂的作业数
def get_homework_commons_count(course, type, category_id)
category_id == 0 ? HomeworkCommon.where(course_id: course.id, homework_type: type).size :
HomeworkCommon.where(course_id: course.id, homework_type: type, course_second_category_id: category_id).size
end
# 获取课堂的任务数(作业数+试卷数+问卷数)
def get_tasks_count(course)
course.homework_commons_count + course.exercises_count + course.polls_count
end
# 当前用户可见的毕设任务
def visible_graduation_task course, user
if user.teacher_of_course?(course)
tasks = course.graduation_tasks
else
tasks = course.graduation_tasks.where("publish_time <= '#{Time.now}'")
end
tasks
end
# 分班情况
def course_group_info course, user_id
course_group_ids = course.group_course_power(user_id)
course_groups =
if course_group_ids.present?
course.course_groups.where(id: course_group_ids).includes(:course_members)
else
course.course_groups.includes(:course_members)
end
group_info = []
if !course_groups.blank?
course_groups.each do |group|
group_info << {course_group_id: group.id, group_group_name: group.name, count: group.course_members_count}
end
none_group_count = course.students.where(course_group_id: 0).size
group_info << {course_group_id: 0, group_group_name: "未分班", count: none_group_count} if none_group_count > 0 && !course_group_ids.present?
end
return group_info
end
def left_group_info course
group_info = []
if course.course_groups_count > 0
none_group_count = course.students.where(course_group_id: 0).size
group_info << {category_id: 0, category_name: "未分班", position: course.course_groups.pluck(:position).max.to_i + 1,
category_count: none_group_count, category_type: false,
second_category_url: "/courses/#{@course.id}/course_groups/0"}
course.course_groups.each do |course_group|
group_info << {category_id: course_group.id, category_name: course_group.name, position: course_group.position,
category_count: course_group.course_members_count, category_type: false,
second_category_url: "/courses/#{@course.id}/course_groups/#{course_group.id}"}
end
end
group_info
end
def last_subject_shixun course, myshixuns
myshixun = myshixuns.sort{|x,y| y[:updated_at] <=> x[:updated_at] }.first
return "" unless myshixun
stage_shixun = course.course_stage_shixuns.where(shixun_id: myshixun.shixun_id).take
progress = stage_shixun&.course_stage&.position.to_s + "-" + stage_shixun&.position.to_s + " " + myshixun.shixun&.name
end
end

View File

@ -1,2 +0,0 @@
module DiscussesHelper
end

View File

@ -1,2 +0,0 @@
module EduDatasHelper
end

View File

@ -1,150 +0,0 @@
module GraduationTasksHelper
include CoursesHelper
# 教师评阅
def teacher_comment task, user_id
[{ id: 0 ,name: "未评", count: task.uncomment_count(user_id)}, {id: 1, name: "已评", count: task.comment_count(user_id)}]
end
# 作品状态
def task_status task, user_id
[{id: 0, name: "未提交", count: task.unfinished_count(user_id)},
{id: 1, name: "按时提交", count: task.finished_count(user_id)},
{id: 2, name: "延时提交", count: task.delay_finished_count(user_id)}]
end
# 交叉评阅
def cross_comment task, user_id
if task.cross_comment && task.status >= 3
[{id: 1, name: "只看我的交叉评阅", count: task.graduation_work_comment_assignations.myself(user_id).count}]
else
[]
end
end
def task_curr_status task, course
result = {}
status = []
time = ""
if course.try(:is_end)
status << "已结束"
time = course.end_date.present? ? course.end_date.strftime("%Y-%m-%d") : ""
else
if task.status > 1 && task.allow_late && (task.late_time.nil? || task.late_time > Time.now)
status << "补交中"
end
case task.status
when 0
status << "未发布"
time = task.publish_time.present? ? "将于 #{format_time(task.publish_time)} 发布" : "创建于#{time_from_now(task.created_at)}"
when 1
if task.end_time && task.end_time >= Time.now
status << "提交中"
time = how_much_time(task.end_time)
end
when 2
status << "评阅中"
time = task.comment_time.present? ? how_much_time(task.comment_time) : course.end_date.present? ? how_much_time(course.end_date.end_of_day) : ""
when 3
status << "交叉评阅中"
time = course.end_date.present? ? how_much_time(course.end_date.end_of_day) : ""
end
status << "未开启补交" if (!task.allow_late && task.status != 0) #6.11 -hs 新增status不等于0
# 如果还在补交阶段则显示补交结束时间
if task.status > 1 && task.allow_late && task.late_time && task.late_time > Time.now
time = how_much_time(task.late_time)
end
end
result[:status] = status
result[:time] = time
result
end
# 作品数统计type 1 已提交 0 未提交
def grduationwork_count task, type
works = task.graduation_works
type == 1 ? works.select{|work| work.work_status != 0}.size : works.select{|work| work.work_status == 0}.size
end
# 普通/分组 作业作品状态数组
def graduation_work_status task, user_id, course
status = []
work = task.graduation_works.find_by(user_id: user_id)
work = work || GraduationWork.create(graduation_task_id: task.id, user_id: user_id)
late_time = task.late_time || course.end_date
if course.is_end && work && work.work_status > 0
status << "查看作品"
elsif !course.is_end
if task.publish_time && task.publish_time < Time.now
# 作业未截止时
if task.end_time > Time.now
if task.task_type == 2 && task.base_on_project
if work.project_id.nil? || work.project_id == 0
status << "创建项目"
status << "关联项目"
elsif work.work_status == 0
status << "取消关联"
status << "提交作品"
else
status << "修改作品"
end
else
if work.work_status == 0
status << "提交作品"
else
status << "修改作品"
end
end
# 补交阶段
elsif task.allow_late && (late_time.nil? || late_time > Time.now)
if task.task_type == 2 && task.base_on_project
if work.project_id.nil? || work.project_id == 0
status << "创建项目"
status << "关联项目"
elsif work.work_status == 0
status << "取消关联"
status << "补交作品"
else
status << "补交附件"
status << "查看作品"
end
else
if work.work_status == 0
status << "补交作品"
else
status << "补交附件"
status << "查看作品"
end
end
# 匿评阶段
elsif work.work_status != 0
status << "查看作品"
end
end
end
end
# 阶段剩余时间
def task_left_time task
if task.publish_time && task.publish_time < Time.now
if task.end_time > Time.now
status = "剩余提交时间"
time = "#{how_much_time(task.end_time)}"
else
if task.allow_late && task.late_time && task.late_time >= Time.now
status = "剩余补交时间"
time = "#{how_much_time(task.late_time)}"
end
end
end
{status: status, time: time}
end
end

View File

@ -1,30 +0,0 @@
module GraduationTopicsHelper
# 课题类型
def topic_type
[{id: 1, name: "设计"}, {id: 2, name: "论文"}, {id: 3, name: "创作"}]
end
# 课程来源
def topic_source
[{id: 1, name: "生产/社会实际"}, {id: 2, name:"结合科研"}, {id: 3, name: "其它"}]
end
# 课题性质1
def topic_property_first
[{id: 1, name: "真题"}, {id: 2, name:"模拟题"}]
end
# 课题性质2
def topic_property_second
[{id: 1, name: "纵向课题"}, {id: 2, name:"横向课题"}, {id: 3, name: "自选"}]
end
# 课题重复
def topic_repeat
[{id: 1, name: "新题"}, {id: 2, name:"往届题,有新要求"}, {id: 3, name: "往届题,无新要求"}]
end
end

View File

@ -1,20 +0,0 @@
module GraduationWorksHelper
include GraduationTasksHelper
# 作品最终成绩
# 参数: work作品 current_user用户course_identity用户在课堂的身份
def work_final_score work, current_user, course_identity
work_score =
if work.work_score.nil?
"--"
else
if work.check_score_power? current_user, course_identity
format("%.1f", work.work_score < 0 ? 0 : work.work_score.round(1))
else
"**"
end
end
# work_score 最终成绩; late_penalty 迟交扣分; final_score 最终评分
{username: work.user.full_name, login: work.user.login, work_score: work_score, final_score: work.final_score}
end
end

View File

@ -1,2 +0,0 @@
module HackUserLastestCodesHelper
end

View File

@ -1,2 +0,0 @@
module HacksHelper
end

View File

@ -1,2 +0,0 @@
module TrustieHacksHelper
end

View File

@ -1,69 +0,0 @@
module Weapps::CoursesHelper
require 'chinese_pinyin'
def teacher_list teachers, user_course_identity
data = []
teachers.each do |teacher|
if teacher.user.present?
teacher_user = teacher.user
name = teacher_user.real_name
role = teacher.role == "CREATOR" ? "管理员" : teacher.role == "PROFESSOR" ? "教师" : "助教"
member_roles = user_course_identity < Course::ASSISTANT_PROFESSOR ? teacher_user.course_role(teacher.course) : []
item = {name: name, course_member_id: teacher.id, login: teacher_user.login, user_id: teacher.user_id, role: role,
school: teacher_user.school_name, image_url: url_to_avatar(teacher_user), member_roles: member_roles}
pinyin = Pinyin.t(name.strip, splitter: '')
first_char = pinyin[0]
letter = first_letter first_char
if data.pluck(:letter).include?(letter)
data.select{|a|a[:letter]==letter}.first[:items] << item
else
data << {letter: letter, items: [item]}
end
end
end
# data = data.sort do |a, b|
# [a[:letter]] <=> [b[:letter]]
# end
# data.push(data.shift) if data.select{|a|a[:letter]=='#'}.first.present? # '#'排在最后
return data
end
def student_list students, excellent, user_course_identity
data = []
students.each do |student|
if student.user.present?
student_user = student.user
name = student_user.real_name
phone = excellent ? "" : student_user.hidden_phone
member_roles = user_course_identity < Course::ASSISTANT_PROFESSOR ? student_user.course_role(student.course) : []
item = {name: name, course_member_id: student.id, login: student_user.login, user_id: student.user_id,
student_id: student_user.student_id, image_url: url_to_avatar(student_user), phone: phone, member_roles: member_roles}
pinyin = Pinyin.t(name.strip, splitter: '')
first_char = pinyin[0]
letter = first_letter first_char
if data.pluck(:letter).include?(letter)
data.select{|a|a[:letter]==letter}.first[:items] << item
else
data << {letter: letter, items: [item]}
end
end
end
# data = data.sort do |a, b|
# [a[:letter]] <=> [b[:letter]]
# end
# data.push(data.shift) if data.select{|a|a[:letter]=='#'}.first.present? # '#'排在最后
return data
end
def first_letter char
if char.ord >= 97 && char.ord <= 122
letter = (char.ord - 32).chr.to_s
elsif char.ord >= 65 && char.ord <= 90
letter = char
else
letter = '#'
end
letter
end
end

View File

@ -1,20 +0,0 @@
class Admins::ImportCourseMemberExcel < BaseImportXlsx
Data = Struct.new(:student_id, :name, :course_id, :role, :course_group_name, :school_id)
def read_each(&block)
sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
data = row.map(&method(:cell_value))[0..5]
block.call Data.new(*data)
end
end
private
def check_sheet_valid!
raise_import_error('请按照模板格式导入') if sheet.row(1).size != 6
end
def cell_value(obj)
obj&.cell_value&.to_s&.strip
end
end

View File

@ -1,23 +0,0 @@
# 批量发布视频 消息任务
class BatchPublishVideoNotifyJob < ApplicationJob
queue_as :notify
def perform(user_id, video_ids)
user = User.find_by(id: user_id)
return if user.blank?
attrs = %i[user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
same_attrs = {
user_id: 1,
trigger_user_id: user.id,
container_type: 'Video',
tiding_type: 'Apply', status: 0
}
Tiding.bulk_insert(*attrs) do |worker|
user.videos.where(id: video_ids).each do |video|
worker.add same_attrs.merge(container_id: video.id)
end
end
end
end

View File

@ -1,67 +0,0 @@
# 学生加入课堂时创建相关任务作品
class CourseAddStudentCreateWorksJob < ApplicationJob
queue_as :default
def perform(course_id, student_ids)
course = Course.find_by(id: course_id)
return if course.blank?
# 如果之前存在相关作品则更新is_delete字段
student_works = StudentWork.joins(:homework_common).where(user_id: student_ids, homework_commons: {course_id: course.id})
student_works.update_all(is_delete: 0)
exercise_users = ExerciseUser.joins(:exercise).where(user_id: student_ids, exercises: {course_id: course.id})
exercise_users.update_all(is_delete: 0)
poll_users = PollUser.joins(:poll).where(user_id: student_ids, polls: {course_id: course.id})
poll_users.update_all(is_delete: 0)
graduation_works = course.graduation_works.where(user_id: student_ids)
graduation_works.update_all(is_delete: 0)
attrs = %i[homework_common_id user_id created_at updated_at]
StudentWork.bulk_insert(*attrs) do |worker|
student_ids.each do |user_id|
same_attrs = {user_id: user_id}
course.homework_commons.where(homework_type: %i[normal group practice]).each do |homework|
next if StudentWork.where(user_id: user_id, homework_common_id: homework.id).any?
worker.add same_attrs.merge(homework_common_id: homework.id)
end
end
end
attrs = %i[exercise_id user_id created_at updated_at]
ExerciseUser.bulk_insert(*attrs) do |worker|
student_ids.each do |user_id|
same_attrs = {user_id: user_id}
course.exercises.each do |exercise|
next if ExerciseUser.where(user_id: user_id, exercise_id: exercise.id).any?
worker.add same_attrs.merge(exercise_id: exercise.id)
end
end
end
attrs = %i[poll_id user_id created_at updated_at]
PollUser.bulk_insert(*attrs) do |worker|
student_ids.each do |user_id|
same_attrs = {user_id: user_id}
course.polls.each do |poll|
next if PollUser.where(user_id: user_id, poll_id: poll.id).any?
worker.add same_attrs.merge(poll_id: poll.id)
end
end
end
attrs = %i[graduation_task_id user_id course_id created_at updated_at]
GraduationWork.bulk_insert(*attrs) do |worker|
student_ids.each do |user_id|
same_attrs = {user_id: user_id, course_id: course.id}
course.graduation_tasks.each do |task|
next if GraduationWork.where(user_id: user_id, graduation_task_id: task.id).any?
worker.add same_attrs.merge(graduation_task_id: task.id)
end
end
end
end
end

View File

@ -1,19 +0,0 @@
class CourseDeleteStudentDeleteWorksJob < ApplicationJob
queue_as :default
def perform(course_id, student_ids)
course = Course.find_by(id: course_id)
return if course.blank?
student_works = StudentWork.joins(:homework_common).where(user_id: student_ids, homework_commons: {course_id: course.id})
student_works.update_all(is_delete: 1)
exercise_users = ExerciseUser.joins(:exercise).where(user_id: student_ids, exercises: {course_id: course.id})
exercise_users.update_all(is_delete: 1)
poll_users = PollUser.joins(:poll).where(user_id: student_ids, polls: {course_id: course.id})
poll_users.update_all(is_delete: 1)
course.graduation_works.where(user_id: student_ids).update_all(is_delete: 1)
end
end

View File

@ -1,22 +0,0 @@
# 删除课堂用户
class CourseDeleteStudentNotifyJob < ApplicationJob
queue_as :notify
def perform(course_id, student_ids, trigger_user_id)
course = Course.find_by(id: course_id)
return if course.blank?
attrs = %i[user_id trigger_user_id container_id container_type belong_container_id
belong_container_type tiding_type created_at updated_at]
same_attrs = {
trigger_user_id: trigger_user_id, container_id: course.id, container_type: 'DeleteCourseMember',
belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'System'
}
Tiding.bulk_insert(*attrs) do |worker|
student_ids.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

View File

@ -1,12 +0,0 @@
class CreateDiffRecordJob < ApplicationJob
queue_as :default
def perform(user_id, obj_id, obj_klass, column_name, before, after)
user = User.find_by(id: user_id)
obj = obj_klass.constantize.find_by(id: obj_id)
return if user.blank? || obj.blank?
CreateDiffRecordService.call(user, obj, column_name, before, after)
end
end

View File

@ -1,21 +0,0 @@
# 删除部门 消息通知
class DeleteDepartmentNotifyJob < ApplicationJob
queue_as :notify
def perform(department_id, operator_id, user_ids)
department = Department.unscoped.find_by(id: department_id)
return if department.blank? || user_ids.blank?
attrs = %i[ user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
same_attrs = {
trigger_user_id: operator_id, container_id: department.id, container_type: 'Department',
status: 4, tiding_type: 'System'
}
Tiding.bulk_insert(*attrs) do |worker|
user_ids.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

View File

@ -1,44 +0,0 @@
# 试卷发布 消息通知
class ExercisePublishNotifyJob < ApplicationJob
queue_as :notify
def perform(exercise_id, group_ids)
exercise = Exercise.find_by(id: exercise_id)
return if exercise.blank?
user = exercise.user
course = exercise.course
if group_ids.present?
students = course.students.where(course_group_id: group_ids)
subquery = course.teacher_course_groups.where(course_group_id: group_ids).select(:course_member_id)
teachers = course.teachers.where(id: subquery)
else
students = course.students
teachers = course.teachers
end
attrs = %i[
user_id trigger_user_id container_id container_type parent_container_id parent_container_type
belong_container_id belong_container_type viewed tiding_type created_at updated_at
]
same_attrs = {
trigger_user_id: user.id, container_id: exercise.id, container_type: 'Exercise',
parent_container_id: exercise.id, parent_container_type: 'ExercisePublish',
belong_container_id: exercise.course_id, belong_container_type: 'Course',
viewed: 0, tiding_type: 'Exercise'
}
Tiding.bulk_insert(*attrs) do |worker|
teacher_ids = teachers.pluck(:user_id)
unless exercise.tidings.exists?(parent_container_type: 'ExercisePublish', user_id: teacher_ids)
teacher_ids.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
students.pluck(:user_id).each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

View File

@ -1,17 +0,0 @@
# 获取阿里云视频信息
class GetAliyunVideoInfoJob < ApplicationJob
queue_as :default
def perform(vod_video_id)
video = Video.find_by(uuid: vod_video_id)
return if video.blank? || video.vod_uploading?
result = AliyunVod::Service.get_play_info(video.uuid)
cover_url = result.dig('VideoBase', 'CoverURL')
file_url = (result.dig('PlayInfoList', 'PlayInfo') || []).first&.[]('PlayURL')
video.cover_url = cover_url if cover_url.present? && video.cover_url.blank?
video.file_url = file_url if file_url.present?
video.save!
end
end

View File

@ -1,22 +0,0 @@
# 毕设任务的交叉评阅分配
class GraduationTaskCrossCommentJob < ApplicationJob
queue_as :default
def perform(graduation_task_id)
task = GraduationTask.find_by(id: graduation_task_id)
return if task.blank?
task.graduation_task_group_assignations.includes(:graduation_group, :graduation_work).each do |assignation|
graduation_group = assignation.graduation_group
work = assignation.graduation_work
if graduation_group.present? && work.present?
member_ids = graduation_group.course_members.pluck(:user_id).uniq
member_ids.each do |user_id|
unless work.graduation_work_comment_assignations.exists?(user_id: user_id)
work.graduation_work_comment_assignations << GraduationWorkCommentAssignation.new(user_id: user_id, graduation_task_id: task.id)
end
end
end
end
end
end

View File

@ -1,28 +0,0 @@
# 任务发布 消息通知
class GraduationTaskPublishNotifyJob < ApplicationJob
queue_as :notify
def perform(graduation_task_id)
task = GraduationTask.find_by(id: graduation_task_id)
return if task.blank?
course = task.course
return if course.blank?
attrs = %i[
user_id trigger_user_id container_id container_type parent_container_id parent_container_type
belong_container_id belong_container_type viewed tiding_type created_at updated_at
]
same_attrs = {
trigger_user_id: task.user_id, container_id: task.id, container_type: 'GraduationTask',
parent_container_id: task.id, parent_container_type: 'TaskPublish',
belong_container_id: task.course_id, belong_container_type: 'Course',
viewed: 0, tiding_type: 'GraduationTask'
}
Tiding.bulk_insert(*attrs) do |worker|
course.course_members.pluck(:user_id).uniq.each do |user_id|
worker.add same_attrs.merge(user_id: user_id)
end
end
end
end

View File

@ -1,33 +0,0 @@
class ResubmitStudentWorkNotifyJob < ApplicationJob
queue_as :notify
def perform(homework_id, student_ids)
homework = HomeworkCommon.find_by(id: homework_id)
return if homework.blank? || student_ids.blank?
course = homework.course
attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type
belong_container_id belong_container_type tiding_type viewed created_at updated_at]
same_attrs = {
container_type: 'ResubmitStudentWork', parent_container_id: homework.id, parent_container_type: 'HomeworkCommon',
belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'HomeworkCommon', viewed: 0
}
Tiding.bulk_insert(*attrs) do |worker|
student_ids.each do |user_id|
next unless User.exists?(id: user_id)
work = homework.student_works.find_by(user_id: user_id)
next if work.blank?
score_user_ids = work.student_works_scores.where.not(score: nil).where(reviewer_role: [1, 2]).pluck(user_id).uniq
next if score_user_ids.blank?
attrs = same_attrs.merge(trigger_user_id: user_id, container_id: work.id)
score_user_ids.each do |user_id|
worker.add attrs.merge(user_id: user_id)
end
end
end
end
end

View File

@ -36,9 +36,9 @@ class SendTemplateMessageJob < ApplicationJob
operator = User.find_by_id(operator_id)
issue = Issue.find_by_id(issue_id)
return unless operator.present? && issue.present?
receivers = receivers.where.not(id: operator&.id)
# receivers = receivers.where.not(id: operator&.id)
receivers_string, content, notification_url = MessageTemplate::IssueAtme.get_message_content(receivers, operator, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id}, 2)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, issue_id: issue.id}, 2, operator_id)
when 'IssueChanged'
operator_id, issue_id, change_params = args[0], args[1], args[2]
operator = User.find_by_id(operator_id)
@ -234,9 +234,9 @@ class SendTemplateMessageJob < ApplicationJob
operator = User.find_by_id(operator_id)
pull_request = PullRequest.find_by_id(pull_request_id)
return unless operator.present? && pull_request.present?
receivers = receivers.where.not(id: operator&.id)
# receivers = receivers.where.not(id: operator&.id)
receivers_string, content, notification_url = MessageTemplate::PullRequestAtme.get_message_content(receivers, operator, pull_request)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id}, 2)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, pull_request_id: pull_request.id}, 2, operator_id)
when 'PullRequestChanged'
operator_id, pull_request_id, change_params = args[0], args[1], args[2]
operator = User.find_by_id(operator_id)

View File

@ -17,7 +17,7 @@
# disk_directory :string(255)
# attachtype :integer default("1")
# is_public :integer default("1")
# copy_from :string(255)
# copy_from :integer
# quotes :integer default("0")
# is_publish :integer default("1")
# publish_time :datetime
@ -26,15 +26,15 @@
# cloud_url :string(255) default("")
# course_second_category_id :integer default("0")
# delay_publish :boolean default("0")
# link :string(255)
# clone_id :integer
#
# Indexes
#
# index_attachments_on_author_id (author_id)
# index_attachments_on_clone_id (clone_id)
# index_attachments_on_container_id_and_container_type (container_id,container_type)
# index_attachments_on_course_second_category_id (course_second_category_id)
# index_attachments_on_created_on (created_on)
# index_attachments_on_is_public (is_public)
# index_attachments_on_quotes (quotes)
#

21
app/models/badge.rb Normal file
View File

@ -0,0 +1,21 @@
# == Schema Information
#
# Table name: badges
#
# id :integer not null, primary key
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# many_projects :integer default("0")
# manyParisesProject :integer default("0")
# parises_project :integer default("0")
# manyWatchersProject :integer default("0")
# watchers_project :integer default("0")
# many_fans :integer default("0")
# many_pr :integer default("0")
# many_issue :integer default("0")
# active_in_week :integer default("0")
#
class Badge < ApplicationRecord
end

View File

@ -39,15 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@ -55,9 +53,8 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#

View File

@ -1,18 +1,19 @@
# == Schema Information
#
# Table name: edu_settings
#
# id :integer not null, primary key
# name :string(255)
# value :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# description :string(255)
#
# Indexes
#
# index_edu_settings_on_name (name) UNIQUE
#
# == Schema Information
#
# Table name: edu_settings
#
# id :integer not null, primary key
# name :string(255)
# value :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# description :string(255)
#
# Indexes
#
# index_edu_settings_on_name (name) UNIQUE
#
class EduSetting < ApplicationRecord
after_commit :expire_value_cache

View File

@ -10,7 +10,6 @@
# sync_course :boolean default("0")
# sync_subject :boolean default("0")
# sync_shixun :boolean default("0")
# is_local :boolean default("0")
#
# Indexes
#
@ -44,7 +43,7 @@ class Laboratory < ApplicationRecord
def site
rails_env = EduSetting.get('rails_env')
suffix = rails_env && rails_env != 'production' ? ".#{rails_env}.trustie.net" : '.trustie.net'
suffix = rails_env && rails_env != 'production' ? ".#{rails_env}.gitlink.org.cn" : '.gitlink.org.cn'
identifier ? "#{identifier}#{suffix}" : ''
end
@ -74,74 +73,6 @@ class Laboratory < ApplicationRecord
RequestStore.store[:current_laboratory] ||= User.anonymous
end
def shixuns
if main_site?
not_shixun_ids = Shixun.joins(:laboratory_shixuns).where("laboratory_shixuns.laboratory_id != #{Laboratory.current.id}")
Shixun.where.not(id: not_shixun_ids.pluck(:shixun_id))
elsif sync_shixun
laboratory_shixun_ids = laboratory_shixuns.pluck(:shixun_id)
school_shixun_ids = Shixun.joins("join user_extensions on shixuns.user_id=user_extensions.user_id").where(user_extensions: { school_id: school_id }).pluck(:id)
shixun_ids = laboratory_shixun_ids + school_shixun_ids
Shixun.where(id: shixun_ids.uniq)
else
Shixun.joins(:laboratory_shixuns).where(laboratory_shixuns: { laboratory_id: id })
end
end
def subjects
if main_site?
not_subject_ids = Subject.joins(:laboratory_subjects).where("laboratory_subjects.laboratory_id != #{Laboratory.current.id}")
Subject.where.not(id: not_subject_ids.pluck(:subject_id))
elsif sync_subject
laboratory_subject_ids = laboratory_subjects.pluck(:subject_id)
school_subject_ids = Subject.joins("join user_extensions on subjects.user_id=user_extensions.user_id").where(user_extensions: { school_id: school_id }).pluck(:id)
subject_ids = laboratory_subject_ids + school_subject_ids
Subject.where(id: subject_ids.uniq)
else
Subject.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: id })
end
end
def all_courses
main_site? || !sync_course ? courses : courses.or(Course.where(school_id: school_id))
end
def shixun_repertoires
where_sql = ShixunTagRepertoire.where("shixun_tag_repertoires.tag_repertoire_id = tag_repertoires.id")
# 云上实验室过滤
unless main_site?
where_sql = where_sql.joins("JOIN laboratory_shixuns ls ON ls.shixun_id = shixun_tag_repertoires.shixun_id "\
"AND ls.laboratory_id = #{id}")
end
where_sql = where_sql.select('1').to_sql
tags = TagRepertoire.where("EXISTS(#{where_sql})").distinct.includes(sub_repertoire: :repertoire)
tags_map = tags.group_by(&:sub_repertoire)
sub_reps_map = tags_map.keys.group_by(&:repertoire)
sub_reps_map.keys.sort_by(&:updated_at).reverse.map do |repertoire|
repertoire_hash = repertoire.as_json(only: %i[id name])
repertoire_hash[:sub_repertoires] =
sub_reps_map[repertoire].sort_by(&:updated_at).reverse.map do |sub_repertoire|
sub_repertoire_hash = sub_repertoire.as_json(only: %i[id name])
sub_repertoire_hash[:tags] = tags_map[sub_repertoire].sort_by(&:updated_at).reverse.map { |tag| tag.as_json(only: %i[id name]) }
sub_repertoire_hash
end
repertoire_hash
end
end
def subject_repertoires
exist_sql = Subject.where('subjects.repertoire_id = repertoires.id')
unless main_site?
exist_sql = exist_sql.joins(:laboratory_subjects).where(laboratory_subjects: { laboratory_id: id })
end
Repertoire.where("EXISTS(#{exist_sql.select('1').to_sql})").order(updated_at: :desc).distinct
end
# 是否为主站
def main_site?
id == 1

View File

@ -17,55 +17,55 @@ class MessageTemplate < ApplicationRecord
def self.build_init_data
self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/issue_assigned.html")
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个易修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 指派给你一个易修')
self.create(type: 'MessageTemplate::IssueAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个易修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个易修')
self.create(type: 'MessageTemplate::IssueAssignerExpire', sys_notice: '您负责的易修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueAtme', sys_notice: '<b>{nickname}</b> 在易修 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_changed.html")
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的易修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: '易修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueChanged', sys_notice: '在项目 <b>{nickname2}/{repository}</b> 的易修 <b>{title}</b> 中:{ifassigner}{nickname1}将负责人从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifstatus}{nickname1}将状态从 <b>{status1}</b> 修改为 <b>{status2}</b> {endstatus}{iftracker}{nickname1}将类型从 <b>{tracker1}</b> 修改为 <b>{tracker2}</b> {endtracker}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifdoneratio}{nickname1}将完成度从 <b>{doneratio1}</b> 修改为 <b>{doneratio2}</b> {enddoneratio}{ifbranch}{nickname1}将指定分支从 <b>{branch1}</b> 修改为 <b>{branch2}</b> {endbranch}{ifstartdate}{nickname1}将开始日期从 <b>{startdate1}</b> 修改为 <b>{startdate2}</b> {endstartdate}{ifduedate}{nickname1}将结束日期从 <b>{duedate1}</b> 修改为 <b>{duedate2}</b> {endduedate}', email: email_html, email_title: 'GitLink: 易修 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::IssueCreatorExpire', sys_notice: '您发布的易修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
email_html = File.read("#{email_template_html_dir}/issue_deleted.html")
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将易修 <b>{title}</b> 删除', email: email_html, email_title: '易修 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将易修 <b>{title}</b> 删除', email: email_html, email_title: 'GitLink: 易修 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::IssueJournal', sys_notice: '{nickname}评论易修{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}')
self.create(type: 'MessageTemplate::LoginIpTip', sys_notice: '您的账号{nickname}于{login_time)在非常用的IP地址{ip}登录,如非本人操作,请立即修改密码', notification_url: '')
email_html = File.read("#{email_template_html_dir}/organization_joined.html")
self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 <b>{organization}</b> 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: '你已加入 {organization} 组织')
self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 <b>{organization}</b> 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: 'GitLink: 你已加入 {organization} 组织')
email_html = File.read("#{email_template_html_dir}/organization_left.html")
self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: '你已被移出 {organization} 组织')
self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {organization} 组织')
email_html = File.read("#{email_template_html_dir}/organization_role.html")
self.create(type: 'MessageTemplate::OrganizationRole', sys_notice: '组织 <b>{organization}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: '在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::OrganizationRole', sys_notice: '组织 <b>{organization}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '')
self.create(type: 'MessageTemplate::ProjectFollowed', sys_notice: '<b>{nickname}</b> 关注了你管理的仓库', notification_url: '{baseurl}/{login}')
self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库{nickname1}/{repository1}到{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_issue.html")
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建易修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 新建了一个易修')
self.create(type: 'MessageTemplate::ProjectIssue', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 新建易修:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 新建了一个易修')
email_html = File.read("#{email_template_html_dir}/project_joined.html")
self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 <b>{repository}</b> 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: '你已加入 {repository} 项目')
self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 <b>{repository}</b> 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: 你已加入 {repository} 项目')
email_html = File.read("#{email_template_html_dir}/project_left.html")
self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 <b>{repository}</b> 项目', notification_url: '', email: email_html, email_title: '你已被移出 {repository} 项目')
self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 <b>{repository}</b> 项目', notification_url: '', email: email_html, email_title: 'GitLink: 你已被移出 {repository} 项目')
email_html = File.read("#{email_template_html_dir}/project_member_joined.html")
self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '<b>{nickname1}</b> 已加入项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: '{nickname1} 已加入项目 {nickname2}/{repository}')
self.create(type: 'MessageTemplate::ProjectMemberJoined', sys_notice: '<b>{nickname1}</b> 已加入项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已加入项目 {nickname2}/{repository}')
email_html = File.read("#{email_template_html_dir}/project_member_left.html")
self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '<b>{nickname1}</b> 已被移出项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: '{nickname1} 已被移出项目 {nickname2}/{repository}')
self.create(type: 'MessageTemplate::ProjectMemberLeft', sys_notice: '<b>{nickname1}</b> 已被移出项目 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: 'GitLink: {nickname1} 已被移出项目 {nickname2}/{repository}')
self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了一个里程碑:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}')
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname}</b> 点赞了你管理的仓库', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/project_pull_request.html")
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 提交了一个合并请求')
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求')
email_html = File.read("#{email_template_html_dir}/project_role.html")
self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 <b>{nickname}/{repository}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: '在 {nickname}/{repository} 项目你的账号有权限变更', notification_url: '{baseurl}/{owner}/{identifier}')
self.create(type: 'MessageTemplate::ProjectRole', sys_notice: '仓库 <b>{nickname}/{repository}</b> 已把你的角色改为 <b>{role}</b>', email: email_html, email_title: 'GitLink: 在 {nickname}/{repository} 项目你的账号有权限变更', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_setting_changed.html")
self.create(type: 'MessageTemplate::ProjectSettingChanged', sys_notice: '{nickname1}更改了 <b>{nickname2}/{repository}</b> 仓库设置:{ifname}更改项目名称为"<b>{name}</b>"{endname}{ifidentifier}更改项目标识为"<b>{identifier}</b>"{endidentifier}{ifdescription}更改项目简介为"<b>{description}</b>"{enddescription}{ifcategory}更改项目类别为"<b>{category}</b>"{endcategory}{iflanguage}更改项目语言为"<b>{language}</b>"{endlanguage}{ifpermission}将仓库设为"<b>{permission}</b>"{endpermission}{ifnavbar}将项目导航更改为"<b>{navbar}</b>"{endnavbar}', notification_url: '{baseurl}/{owner}/{identifier}/settings', email: email_html, email_title: '您管理的仓库 {nickname2}/{repository} 仓库设置已被更改')
self.create(type: 'MessageTemplate::ProjectSettingChanged', sys_notice: '{nickname1}更改了 <b>{nickname2}/{repository}</b> 仓库设置:{ifname}更改项目名称为"<b>{name}</b>"{endname}{ifidentifier}更改项目标识为"<b>{identifier}</b>"{endidentifier}{ifdescription}更改项目简介为"<b>{description}</b>"{enddescription}{ifcategory}更改项目类别为"<b>{category}</b>"{endcategory}{iflanguage}更改项目语言为"<b>{language}</b>"{endlanguage}{ifpermission}将仓库设为"<b>{permission}</b>"{endpermission}{ifnavbar}将项目导航更改为"<b>{navbar}</b>"{endnavbar}', notification_url: '{baseurl}/{owner}/{identifier}/settings', email: email_html, email_title: 'GitLink: 您管理的仓库 {nickname2}/{repository} 仓库设置已被更改')
self.create(type: 'MessageTemplate::ProjectTransfer', sys_notice: '你关注的仓库{nickname1}/{repository1}已被转移至{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}')
self.create(type: 'MessageTemplate::ProjectVersion', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了发行版:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/releases')
email_html = File.read("#{email_template_html_dir}/pull_request_assigned.html")
self.create(type: 'MessageTemplate::PullRequestAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个合并请求:<b>{title}<b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: '{nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求')
self.create(type: 'MessageTemplate::PullRequestAssigned', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 指派给你一个合并请求:<b>{title}<b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: 'GitLink: {nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求')
self.create(type: 'MessageTemplate::PullRequestAtme', sys_notice: '<b>{nickname}</b> 在合并请求 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_changed.html")
self.create(type: 'MessageTemplate::PullRequestChanged', sys_notice: '在项目{nickname2}/{repository}的合并请求 <b>{title}</b> 中:{ifassigner}{nickname1}将审查成员从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}', email: email_html, email_title: '合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
self.create(type: 'MessageTemplate::PullRequestChanged', sys_notice: '在项目{nickname2}/{repository}的合并请求 <b>{title}</b> 中:{ifassigner}{nickname1}将审查成员从 <b>{assigner1}</b> 修改为 <b>{assigner2}</b> {endassigner}{ifmilestone}{nickname1}将里程碑从 <b>{milestone1}</b> 修改为 <b>{milestone2}</b> {endmilestone}{iftag}{nickname1}将标记从 <b>{tag1}</b> 修改为 <b>{tag2}</b> {endtag}{ifpriority}{nickname1}将优先级从 <b>{priority1}</b> 修改为 <b>{priority2}</b> {endpriority}', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_closed.html")
self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} <b>被拒绝</b>', email: email_html, email_title: '合并请求 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} <b>被拒绝</b>', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '')
self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_merged.html")
self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} <b>已通过</b>', email: email_html, email_title: '合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} <b>已通过</b>', email: email_html, email_title: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
end
def self.sys_notice

View File

@ -188,6 +188,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
end
def self.get_email_message_content(receiver, operator, issue, change_params)
return '', '', '' if change_params.blank?
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::IssueChanged"]
end

View File

@ -100,6 +100,7 @@ class MessageTemplate::PullRequestChanged < MessageTemplate
end
def self.get_email_message_content(receiver, operator, pull_request, change_params)
return '', '', '' if change_params.blank?
if receiver.user_template_message_setting.present?
return '', '', '' unless receiver.user_template_message_setting.email_body["CreateOrAssign::PullRequestChanged"]
end

View File

@ -39,15 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@ -55,9 +53,8 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#

View File

@ -0,0 +1,2 @@
class OrganizationBadge < ApplicationRecord
end

View File

@ -1,19 +1,20 @@
# == Schema Information
#
# Table name: praise_treads
#
# id :integer not null, primary key
# user_id :integer not null
# praise_tread_object_id :integer
# praise_tread_object_type :string(255)
# praise_or_tread :integer default("1")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# praise_tread (praise_tread_object_id,praise_tread_object_type)
#
# == Schema Information
#
# Table name: praise_treads
#
# id :integer not null, primary key
# user_id :integer not null
# praise_tread_object_id :integer
# praise_tread_object_type :string(255)
# praise_or_tread :integer default("1")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# praise_tread (praise_tread_object_id,praise_tread_object_type)
#
class PraiseTread < ApplicationRecord

View File

@ -1,82 +1,83 @@
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255) default(""), not null
# description :text(4294967295)
# homepage :string(255) default("")
# is_public :boolean default("1"), not null
# parent_id :integer
# created_on :datetime
# updated_on :datetime
# identifier :string(255)
# status :integer default("1"), not null
# lft :integer
# rgt :integer
# inherit_members :boolean default("0"), not null
# project_type :integer default("0")
# hidden_repo :boolean default("0"), not null
# attachmenttype :integer default("1")
# user_id :integer
# dts_test :integer default("0")
# enterprise_name :string(255)
# organization_id :integer
# project_new_type :integer
# gpid :integer
# forked_from_project_id :integer
# forked_count :integer default("0")
# publish_resource :integer default("0")
# visits :integer default("0")
# hot :integer default("0")
# invite_code :string(255)
# qrcode :string(255)
# qrcode_expiretime :integer default("0")
# script :text(65535)
# training_status :integer default("0")
# rep_identifier :string(255)
# project_category_id :integer
# project_language_id :integer
# license_id :integer
# ignore_id :integer
# praises_count :integer default("0")
# watchers_count :integer default("0")
# issues_count :integer default("0")
# pull_requests_count :integer default("0")
# language :string(255)
# versions_count :integer default("0")
# issue_tags_count :integer default("0")
# closed_issues_count :integer default("0")
# open_devops :boolean default("0")
# gitea_webhook_id :integer
# open_devops_count :integer default("0")
# recommend :boolean default("0")
# platform :integer default("0")
# default_branch :string(255) default("master")
# website :string(255)
# lesson_url :string(255)
# is_pinned :boolean default("0")
# recommend_index :integer default("0")
#
# Indexes
#
# index_projects_on_forked_from_project_id (forked_from_project_id)
# index_projects_on_identifier (identifier)
# index_projects_on_invite_code (invite_code)
# index_projects_on_is_public (is_public)
# index_projects_on_lft (lft)
# index_projects_on_license_id (license_id)
# index_projects_on_name (name)
# index_projects_on_platform (platform)
# index_projects_on_project_category_id (project_category_id)
# index_projects_on_project_language_id (project_language_id)
# index_projects_on_project_type (project_type)
# index_projects_on_recommend (recommend)
# index_projects_on_rgt (rgt)
# index_projects_on_status (status)
# index_projects_on_updated_on (updated_on)
#
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255) default(""), not null
# description :text(4294967295)
# homepage :string(255) default("")
# is_public :boolean default("1"), not null
# parent_id :integer
# created_on :datetime
# updated_on :datetime
# identifier :string(255)
# status :integer default("1"), not null
# lft :integer
# rgt :integer
# inherit_members :boolean default("0"), not null
# project_type :integer default("0")
# hidden_repo :boolean default("0"), not null
# attachmenttype :integer default("1")
# user_id :integer
# dts_test :integer default("0")
# enterprise_name :string(255)
# organization_id :integer
# project_new_type :integer
# gpid :integer
# forked_from_project_id :integer
# forked_count :integer default("0")
# publish_resource :integer default("0")
# visits :integer default("0")
# hot :integer default("0")
# invite_code :string(255)
# qrcode :string(255)
# qrcode_expiretime :integer default("0")
# script :text(65535)
# training_status :integer default("0")
# rep_identifier :string(255)
# project_category_id :integer
# project_language_id :integer
# license_id :integer
# ignore_id :integer
# praises_count :integer default("0")
# watchers_count :integer default("0")
# issues_count :integer default("0")
# pull_requests_count :integer default("0")
# language :string(255)
# versions_count :integer default("0")
# issue_tags_count :integer default("0")
# closed_issues_count :integer default("0")
# open_devops :boolean default("0")
# gitea_webhook_id :integer
# open_devops_count :integer default("0")
# recommend :boolean default("0")
# platform :integer default("0")
# default_branch :string(255) default("master")
# website :string(255)
# lesson_url :string(255)
# is_pinned :boolean default("0")
# recommend_index :integer default("0")
#
# Indexes
#
# index_projects_on_forked_from_project_id (forked_from_project_id)
# index_projects_on_identifier (identifier)
# index_projects_on_invite_code (invite_code)
# index_projects_on_is_public (is_public)
# index_projects_on_lft (lft)
# index_projects_on_license_id (license_id)
# index_projects_on_name (name)
# index_projects_on_platform (platform)
# index_projects_on_project_category_id (project_category_id)
# index_projects_on_project_language_id (project_language_id)
# index_projects_on_project_type (project_type)
# index_projects_on_recommend (recommend)
# index_projects_on_rgt (rgt)
# index_projects_on_status (status)
# index_projects_on_updated_on (updated_on)
#

View File

@ -9,7 +9,7 @@
# created_at :datetime not null
# updated_at :datetime not null
# ancestry :string(255)
# pinned_index :integer default("0")
# pinned_index :integer default("0")
#
# Indexes
#

View File

@ -3,8 +3,8 @@
# Table name: pull_requests
#
# id :integer not null, primary key
# pull_request_id :integer
# gpid :integer
# gitea_id :integer
# gitea_number :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null

View File

@ -27,6 +27,7 @@
#
# Indexes
#
# index_repositories_on_identifier (identifier)
# index_repositories_on_project_id (project_id)
# index_repositories_on_user_id (user_id)
#

View File

@ -0,0 +1,15 @@
# == Schema Information
#
# Table name: repository_badges
#
# id :integer not null, primary key
# project_id :integer
# popular_project :integer default("0")
# recommend_project :integer default("0")
# many_stars :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
class RepositoryBadge < ApplicationRecord
end

View File

@ -2,16 +2,16 @@
#
# Table name: system_notification_histories
#
# id :integer not null, primary key
# system_message_id :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# id :integer not null, primary key
# system_notification_id :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_system_notification_histories_on_system_message_id (system_message_id)
# index_system_notification_histories_on_user_id (user_id)
# index_system_notification_histories_on_system_notification_id (system_notification_id)
# index_system_notification_histories_on_user_id (user_id)
#
class SystemNotificationHistory < ApplicationRecord

View File

@ -6,9 +6,9 @@
# type :string(255)
# name :string(255)
# key :string(255)
# openning :boolean
# notification_disabled :boolean
# email_disabled :boolean
# openning :boolean default("1")
# notification_disabled :boolean default("1")
# email_disabled :boolean default("0")
# created_at :datetime not null
# updated_at :datetime not null
#

View File

@ -6,9 +6,9 @@
# type :string(255)
# name :string(255)
# key :string(255)
# openning :boolean
# notification_disabled :boolean
# email_disabled :boolean
# openning :boolean default("1")
# notification_disabled :boolean default("1")
# email_disabled :boolean default("0")
# created_at :datetime not null
# updated_at :datetime not null
#

View File

@ -6,9 +6,9 @@
# type :string(255)
# name :string(255)
# key :string(255)
# openning :boolean
# notification_disabled :boolean
# email_disabled :boolean
# openning :boolean default("1")
# notification_disabled :boolean default("1")
# email_disabled :boolean default("0")
# created_at :datetime not null
# updated_at :datetime not null
#

View File

@ -6,9 +6,9 @@
# type :string(255)
# name :string(255)
# key :string(255)
# openning :boolean
# notification_disabled :boolean
# email_disabled :boolean
# openning :boolean default("1")
# notification_disabled :boolean default("1")
# email_disabled :boolean default("0")
# created_at :datetime not null
# updated_at :datetime not null
#

View File

@ -6,9 +6,9 @@
# type :string(255)
# name :string(255)
# key :string(255)
# openning :boolean
# notification_disabled :boolean
# email_disabled :boolean
# openning :boolean default("1")
# notification_disabled :boolean default("1")
# email_disabled :boolean default("0")
# created_at :datetime not null
# updated_at :datetime not null
#

View File

@ -14,6 +14,7 @@
# tokens_value (value) UNIQUE
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -105,7 +106,7 @@ class Token < ActiveRecord::Base
end
def self.generate_token_value
Educoder::Utils.random_hex(20)
Gitlink::Utils.random_hex(20)
end
def self.delete_user_all_tokens(user)

View File

@ -1,4 +1,4 @@
# == Schema Information
``# == Schema Information
#
# Table name: users
#
@ -39,15 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@ -55,9 +53,8 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#
@ -155,6 +152,8 @@ class User < Owner
has_many :team_users, dependent: :destroy
has_many :teams, through: :team_users
# 教学案例
# has_many :libraries, dependent: :destroy
has_many :project_trends, dependent: :destroy
@ -690,7 +689,7 @@ class User < Owner
end
def self.generate_salt
Educoder::Utils.random_hex(16)
Gitlink::Utils.random_hex(16)
end
# 全部已认证

View File

@ -12,9 +12,7 @@
#
# Indexes
#
# index_user_actions_on_ip (ip)
# index_user_actions_on_user_id (user_id)
# index_user_actions_on_user_id_and_action_type (user_id,action_type)
# index_user_actions_on_ip (ip)
#
class UserAction < ApplicationRecord

View File

@ -10,13 +10,10 @@
# updated_at :datetime not null
# register_status :integer default("0")
# action_status :integer default("0")
# is_delete :boolean default("0")
# user_id :integer
#
# Indexes
#
# index_user_agents_on_ip (ip)
# index_user_agents_on_user_id (user_id)
# index_user_agents_on_ip (ip) UNIQUE
#
class UserAgent < ApplicationRecord

View File

@ -22,9 +22,6 @@
# school_id :integer
# description :string(255) default("")
# department_id :integer
# honor :text(65535)
# edu_background :integer
# edu_entry_year :integer
# province :string(255)
# city :string(255)
# custom_department :string(255)

View File

@ -1,30 +0,0 @@
class Admins::CourseListQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
course_lists = CourseList.all
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
search_type = params[:search_type] || "0"
case search_type
when "0"
course_lists = course_lists.joins(:user)
.where('CONCAT(lastname, firstname) like :keyword OR users.nickname like :keyword', keyword: "%#{keyword}%")
when "1"
course_lists = course_lists.where('name like :keyword', keyword: "%#{keyword}%")
end
end
custom_sort(course_lists, params[:sort_by], params[:sort_direction])
end
end

View File

@ -1,44 +0,0 @@
class Admins::CourseQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc, default_table: 'courses'
def initialize(params)
@params = params
end
def call
courses = Course.all
courses = courses.where(id: params[:id]) if params[:id].present?
# 状态过滤
status =
case params[:status].to_s.strip
when 'processing' then 0
when 'ended' then 1
end
courses = courses.where(is_end: status) if status
# 单位
if params[:school_id].present?
courses = courses.where(school_id: params[:school_id])
end
# 首页展示
if params[:homepage_show].present? && params[:homepage_show].to_s == 'true'
courses = courses.where(homepage_show: true)
end
# 关键字
keyword = params[:keyword].to_s.strip
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR users.nickname LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword'
courses = courses.joins(:teacher, :course_list).where(sql, keyword: "%#{keyword}%")
end
custom_sort(courses, params[:sort_by], params[:sort_direction])
end
end

View File

@ -1,25 +0,0 @@
class Admins::DepartmentApplyQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
status = params[:status]
applies = ApplyAddDepartment.where(status: status) if status.present?
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.where('name LIKE :keyword', keyword: "%#{keyword}%")
end
custom_sort(applies, params[:sort_by], params[:sort_direction])
end
end

View File

@ -1,32 +0,0 @@
class Admins::DepartmentQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
departments = Department.where(is_auth: true).without_deleted
keyword = params[:keyword].to_s.strip
if keyword.present?
departments = departments.joins(:school)
.where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: "%#{keyword}%")
end
if params[:with_member].to_s == 'true'
subquery = DepartmentMember.where('department_id = departments.id').select('1 AS one').to_sql
departments = departments.where("EXISTS(#{subquery})")
end
if params[:with_identifier].to_s == 'true'
departments = departments.where.not(identifier: nil).where.not(identifier: '')
end
custom_sort(departments, params[:sort_by], params[:sort_direction])
end
end

View File

@ -1,36 +0,0 @@
class Admins::LaboratoryShixunQuery < ApplicationQuery
attr_reader :laboratory, :params
def initialize(laboratory, params)
@laboratory = laboratory
@params = params
end
def call
laboratory_shixuns = laboratory.laboratory_shixuns.joins(:shixun)
keyword = params[:keyword].to_s.strip
if keyword.present?
like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword'
laboratory_shixuns = laboratory_shixuns.joins(shixun: :user).where(like_sql, keyword: "%#{keyword}%")
end
# 实训状态
laboratory_shixuns = laboratory_shixuns.where(shixuns: { status: params[:status] }) if params[:status].present?
# 技术平台
if params[:tag_id].present?
laboratory_shixuns = laboratory_shixuns.joins(shixun: :shixun_mirror_repositories)
.where(shixun_mirror_repositories: { mirror_repository_id: params[:tag_id] })
end
# 首页展示、单位自建
%i[homepage ownership].each do |column|
if params[column].present? && params[column].to_s == 'true'
laboratory_shixuns = laboratory_shixuns.where(column => true)
end
end
laboratory_shixuns
end
end

View File

@ -1,23 +0,0 @@
class Admins::SchoolQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :users_count, :created_at, default_by: :created_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
schools = School.all
keyword = strip_param(:keyword)
Rails.logger.info("###########{keyword}")
if keyword
schools = schools.where('schools.name LIKE ?', "%#{keyword}%")
end
schools = schools.left_joins(:user_extensions).select('schools.*, IFNULL(count(user_extensions.user_id),0) users_count').group('schools.id')
custom_sort schools, params[:sort_by], params[:sort_direction]
end
end

View File

@ -1,49 +0,0 @@
class Admins::SubjectQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :created_at, default_by: :created_at, default_direction: :desc, default_table: 'subjects'
def initialize(params)
@params = params
end
def call
subjects = Subject.all
subjects = subjects.where(id: params[:id]) if params[:id].present?
# 状态过滤
status =
case params[:status].to_s.strip
when "editing" then {status: 0}
when "applying" then {status: 2, public: [0, 1]}
when "pending" then {public: 1}
when "published" then {public: 2}
end
subjects = subjects.where(status) if status
# 创建者单位
if params[:school_id].present?
subjects = subjects.joins(user: :user_extension).where(user_extensions: { school_id: params[:school_id] })
end
# 首页展示、金课
%i[homepage_show excellent].each do |column|
if params[column].present? && params[column].to_s == 'true'
subjects = subjects.where(column => true)
end
end
# 关键字
keyword = params[:keyword].to_s.strip
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR users.nickname LIKE :keyword OR subjects.name LIKE :keyword'
subjects = subjects.joins(:user).where(sql, keyword: "%#{keyword}%")
end
custom_sort(subjects, params[:sort_by], params[:sort_direction])
end
end

View File

@ -1,28 +0,0 @@
class Users::VideoQuery < ApplicationQuery
include CustomSortable
sort_columns :published_at, :title, default_by: :published_at, default_direction: :desc
attr_reader :user, :params
def initialize(user, params)
@user = user
@params = params
end
def call
videos = user.videos
videos =
case params[:status]
when 'published' then videos.published
when 'processing' then videos.processing
else videos.published
end
keyword = params[:keyword].to_s.strip
videos = videos.where('title LIKE ?', "%#{keyword}%") if keyword.present?
custom_sort(videos, params[:sort_by], params[:sort_direction])
end
end

View File

@ -1,37 +0,0 @@
class Weapps::SearchQuery < ApplicationQuery
include ElasticsearchAble
attr_reader :params
def initialize(params)
@params = params
end
def call
modal_name.search(keyword, search_options)
end
private
def search_options
hash = {
fields: [:name],
page: page,
per_page: per_page
}
hash.merge(where: { status: 2 }) if modal_name == Shixun
hash
end
def modal_name
@_modal_name ||= begin
case params[:type].to_s
when 'subject' then Subject
when 'shixun' then Shixun
when 'course' then Course
else Subject
end
end
end
end

View File

@ -1,37 +0,0 @@
class Weapps::SubjectQuery < ApplicationQuery
include CustomSortable
attr_reader :params
def initialize(current_laboratory, params)
@current_laboratory = current_laboratory
@params = params
end
def call
subjects = @current_laboratory.subjects.unhidden.publiced.show_moblied
# 课程体系的过滤
if params[:sub_discipline_id].present?
subjects = subjects.joins(:sub_disciplines).where(sub_disciplines: {id: params[:sub_discipline_id]})
elsif params[:discipline_id].present?
subjects = subjects.joins(:sub_disciplines).where(sub_disciplines: {discipline_id: params[:discipline_id]})
else
subjects = subjects.joins(:sub_discipline_containers).where(sub_discipline_containers: {container_type: "Subject"})
end
subjects = subjects.left_joins(:shixuns).select('subjects.id, subjects.name, subjects.excellent, subjects.stages_count, subjects.status, subjects.homepage_show,
subjects.shixuns_count, subjects.updated_at, IFNULL(sum(shixuns.myshixuns_count), 0) myshixuns_count')
.group('subjects.id').order("subjects.homepage_show #{sort_type}, #{order_type} #{sort_type}")
subjects
end
private
def order_type
Subject.column_names.include?(params[:order]) ? params[:order] : 'updated_at'
end
def sort_type
%w(desc asc).include?(params[:sort]) ? params[:sort] : "desc"
end
end

View File

@ -1,20 +0,0 @@
class Admins::AddDepartmentMemberService < ApplicationService
attr_reader :department, :params
def initialize(department, params)
@department = department
@params = params
end
def call
columns = %i[]
DepartmentMember.bulk_insert(*columns) do |worker|
Array.wrap(params[:user_ids]).compact.each do |user_id|
next if department.department_members.exists?(user_id: user_id)
worker.add(department_id: department.id, user_id: user_id)
end
end
end
end

View File

@ -1,89 +0,0 @@
class Admins::CheckShixunMirrorsService < ApplicationService
Error = Class.new(StandardError)
def call
bridge_images
ActiveRecord::Base.transaction do
check_sync_mirrors!
check_mirrors!
end
end
private
def mirrors
bridge_images['images']
end
def sync_mirrors
bridge_images['imagesNotSync']
end
def check_mirrors!
return if mirrors.blank?
image_names = []
mirrors.each do |data|
mirror = JSON.parse(data)
name_repository = MirrorRepository.find_by(name: mirror['imageName'])
id_repository = MirrorRepository.find_by(mirrorID: mirror['imageID'])
image_names << mirror['imageName']
if name_repository.blank? && id_repository.present? # 镜像名称被修改
id_repository.update_column(:status, 2)
MirrorOperationRecord.create!(mirror_repository_id: id_repository.id, mirror_id: mirror['imageID'],
mirror_name: mirror['imageName'], status: 2, user_id: -1)
elsif name_repository.blank? # 镜像不存在、创建镜像
new_repository = MirrorRepository.create!(mirrorID: mirror['imageID'], name: mirror['imageName'])
MirrorOperationRecord.create!(mirror_repository_id: new_repository.id, mirror_id: mirror['imageID'],
mirror_name: mirror['imageName'], status: 0, user_id: -1)
elsif name_repository.mirrorID != mirror['imageID'] # 镜像ID被修改
name_repository.update_column(:status, 2)
MirrorOperationRecord.create!(mirror_repository_id: name_repository.id, mirror_id: mirror['imageID'],
mirror_name: mirror['imageName'], status: 1, user_id: -1)
end
end
# 判断中间层镜像是否被删除
MirrorRepository.find_each do |mirror|
next if mirror&.name.blank? || image_names.index(mirror.name)
mirror.update_column(:status, 4)
MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: mirror&.mirrorID,
mirror_name: mirror.name, status: 3, user_id: -1)
end
end
def check_sync_mirrors!
return if sync_mirrors.blank?
sync_mirrors.each do |data|
mirror = JSON.parse(data)
repository = MirrorRepository.find_by(name: mirror['imageName'])
next if repository.blank? || repository.status != 1
repository.update_column(:status, 5)
MirrorOperationRecord.create!(mirror_repository_id: repository.id, mirror_id: mirror['imageID'],
mirror_name: mirror['imageName'], status: 4, user_id: -1)
end
end
def bridge_images
@_bridge_images ||= begin
url = "#{EduSetting.get('cloud_bridge')}/bridge/docker/images"
res = Faraday.get(url)
res = JSON.parse(res.body)
raise Error, '拉取镜像信息异常' if res && res['code'] != 0
res
rescue => e
Rails.logger.error("get response failed ! #{e.message}")
raise Error, '实训云平台繁忙繁忙等级84'
end
end
end

View File

@ -1,35 +0,0 @@
class Admins::DragCooperativeService < ApplicationService
Error = Class.new(StandardError)
attr_reader :move, :after
def initialize(move, after)
@move = move
@after = after # 移动后下一个位置的元素
end
def call
return if move.position + 1 == after&.position # 未移动
raise Error, '未知错误' if after && move.img_type != after.img_type
coo_imgs = CooImg.where(img_type: move.img_type)
ActiveRecord::Base.transaction do
if after.blank? # 移动至末尾
total = coo_imgs.count
coo_imgs.where('position > ?', move.position).update_all('position = position - 1')
move.update!(position: total)
return
end
if move.position > after.position # 前移
coo_imgs.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
move.update!(position: after.position)
else # 后移
coo_imgs.where('position > ? AND position <= ?', move.position, after.position).update_all('position = position - 1')
move.update!(position: after.position)
end
end
end
end

View File

@ -1,35 +0,0 @@
class Admins::DragPortalImageService < ApplicationService
Error = Class.new(StandardError)
attr_reader :laboratory, :move, :after
def initialize(laboratory, move, after)
@laboratory = laboratory
@move = move
@after = after # 移动后下一个位置的元素
end
def call
return if move.position + 1 == after&.position # 未移动
images = laboratory.portal_images
ActiveRecord::Base.transaction do
if after.blank? || move.id == after.id # 移动至末尾
total = images.count
images.where('position > ?', move.position).update_all('position = position - 1')
move.update!(position: total)
return
end
if move.position > after.position # 前移
images.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
move.update!(position: after.position)
else # 后移
images.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1')
move.update!(position: after.position - 1)
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More