Compare commits

...

118 Commits

Author SHA1 Message Date
yystopf eadc517a25 Merge pull request '同步develop最新代码' (#11) from yystopf/forgeplus:dev_educoder_sync into dev_educoder_sync 2022-05-25 17:27:42 +08:00
yystopf 1652e615be 同步develop最新代码 2022-05-25 17:25:21 +08:00
yystopf 2ea78b4f20 增加: 已登录用户对用户名、邮箱、电话进行校验 2022-05-25 11:47:35 +08:00
yystopf e36c7a4b6a 修复: 邮箱搜索不需要return 404 2022-05-24 18:09:36 +08:00
yystopf 8e8ec821f2 新增: 根据邮箱来获取用户 2022-05-24 17:26:10 +08:00
yystopf 5cf257c3cc Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-05-24 11:45:53 +08:00
yystopf aa18fe0ad4 修复: 转移项目时新接受者需要移除原来的权限角色 2022-05-24 11:44:05 +08:00
yystopf 1358c23ca6 fix: trasfer project member must remove old permission 2022-05-24 11:43:47 +08:00
yystopf c27cc063e6 add: new update user info simple and sync gitea 2022-05-24 10:59:52 +08:00
yystopf b0092487e6 fix: is readme use regex 2022-05-23 18:10:41 +08:00
yystopf fbebd0a623 fix 2022-05-23 09:27:09 +08:00
yystopf fe23c2afbf fix: replace content next if blank 2022-05-21 16:45:42 +08:00
yystopf 779c86108a fix: readme relative delay and replace_content 2022-05-20 17:00:02 +08:00
yystopf 83e43f0c97 add: new readme delay function 2022-05-20 11:43:22 +08:00
yystopf e545424b7d fix: project count use count 2022-05-19 15:54:38 +08:00
yystopf e237fd46f7 fix: not found user return 404 2022-05-18 11:37:23 +08:00
yystopf ca3c564529 fix: not found user return 404 2022-05-18 11:03:39 +08:00
yystopf 9cd18397f7 fix: import user login length required 2022-05-18 10:11:09 +08:00
xiaoxiaoqiong 7574071445 fix educoder to Gitlink::utils 2022-05-17 15:41:39 +08:00
yystopf 77620f7735 add: download and import user template xlsx 2022-05-16 16:59:25 +08:00
yystopf 50dc5cce5d fix 2022-05-07 14:06:48 +08:00
yystopf a6cee63d17 fix: change owner must fix foreign_key 2022-05-07 11:57:58 +08:00
yystopf 000197b0d1 fix: issues and pull_request length calculate 2022-05-06 17:25:34 +08:00
yystopf 6aa3321d17 fix: pr title description validate 2022-05-06 14:29:05 +08:00
yystopf d44308fc82 Merge branch 'develop' of https://gitlink.org.cn/Trustie/forgeplus into develop 2022-05-06 09:56:38 +08:00
yystopf ae7d0d1329 add: issues description and journals notes validate 2022-05-06 09:56:22 +08:00
xiaoxiaoqiong 55c74de8e4 fork_users加入组织 2022-05-05 10:41:02 +08:00
yystopf 7c88ea3d67 add: quit repo 2022-05-05 10:00:02 +08:00
yystopf f15cd44dff add: compare add paginate 2022-04-28 18:53:33 +08:00
yystopf 3abd6037d9 fix: show super description aways desplay 2022-04-28 11:12:16 +08:00
yystopf ec3a556a6f fix: default value for show super description 2022-04-28 11:03:42 +08:00
yystopf 793cbb372a Merge pull request '用户新增个人简介markdown编辑字段' (#8) from yystopf/forgeplus:hh_develop into develop 2022-04-28 10:53:06 +08:00
yystopf 396ac55429 add: user super description 2022-04-28 10:42:55 +08:00
yystopf 088c617cc1 add: name query for branches 2022-04-26 17:15:59 +08:00
xiaoxiaoqiong 17314b9164 take error utf8 2022-04-24 14:54:27 +08:00
xiaoxiaoqiong e6521ffdd2 utf8 2022-04-24 14:46:59 +08:00
yystopf fc3cf01d3f add: get user image action 2022-04-18 13:49:08 +08:00
yystopf 8f5bb0e2d9 fix: organization gitea_token read by associations 2022-04-18 10:52:48 +08:00
yystopf ef559b11a0 add: settings banner 2022-04-14 14:21:16 +08:00
yystopf 7f59f6739f fix 2022-04-12 11:20:19 +08:00
yystopf d6937f195c sync from develop 2022-04-12 11:01:09 +08:00
yystopf 2dfd69ae21 fix: response data result 2022-04-11 16:08:50 +08:00
yystopf 720c073f32 fix 2022-04-11 15:48:47 +08:00
yystopf 0076468a15 fix: trace client request data 2022-04-11 15:30:28 +08:00
yystopf 910ae48556 fix: exception to ex 2022-04-11 10:50:18 +08:00
yystopf eac7331070 fix: settings need prefix 2022-04-08 15:03:40 +08:00
yystopf 551f333261 fix 2022-04-08 14:52:56 +08:00
yystopf dec264d169 fix: sync user pwd 2022-04-07 16:28:40 +08:00
yystopf 7055974443 fix 2022-04-06 17:04:31 +08:00
yystopf 3536918938 fix 2022-03-31 16:18:16 +08:00
yystopf 56278b84f2 Merge pull request '导航增加动态用户数据获取' (#3) from hh_develop_navbar into develop 2022-03-31 16:08:36 +08:00
yystopf 882a50cf56 add: setting navbar varible 2022-03-31 16:04:48 +08:00
yystopf db4031b8bf fix 2022-03-31 14:24:47 +08:00
yystopf ecfc39565c fix 2022-03-31 13:18:38 +08:00
yystopf 9ced678f91 fix: user trace token 2022-03-31 13:03:54 +08:00
yystopf 7951ca28d5 Merge pull request '代码溯源service封装' (#2) from hh_develop into develop 2022-03-31 12:59:34 +08:00
yystopf 4bbb843edf add: trace users and get trace token 2022-03-31 12:54:39 +08:00
yystopf 747646cd9d add: trace client and api completed 2022-03-30 16:19:32 +08:00
yystopf d0d906d04c fix: readme image regex error rescued 2022-03-28 11:05:21 +08:00
yystopf bc639488aa fix: issues filter error 2022-03-22 10:45:14 +08:00
xiaoxiaoqiong 99fbecc834 gitea 请求延长到20分钟 2022-03-11 14:06:12 +08:00
yystopf 8d0a6d267a fix: download escape 2022-03-10 10:47:06 +08:00
yystopf b1c03ed5e8 fix: activity issues must only issue 2022-03-10 09:51:46 +08:00
yystopf ef12f85687 fix: create pull request valid merge_user_login 2022-03-07 11:17:10 +08:00
yystopf e120c4dac2 add: origin repository need open pr menu 2022-03-07 10:53:07 +08:00
yystopf e1cf2fcdeb fix: owner project not allow repeat name 2022-03-07 10:25:05 +08:00
yystopf c4f380873e fix: is public project attachment allow is not member read 2022-03-07 10:20:51 +08:00
yystopf 5cb2e55f74 add: organization users insist team nickname search 2022-03-07 09:58:05 +08:00
xiaoxiaoqiong 1dd3fbc69a fixed fork列表中存在组织时显示错误 2022-03-03 14:16:57 +08:00
yystopf b97c42d0ae fix: email logo 2022-03-02 10:33:35 +08:00
yystopf a2612d8009 fix 2022-02-24 18:09:11 +08:00
yystopf 2f2655525f fix: user rank user_id must exist 2022-02-24 18:07:18 +08:00
yystopf 1a93477635 fix: forked templete delay 2022-02-24 14:26:04 +08:00
yystopf 7c664addbd fix 2022-02-22 11:03:28 +08:00
yystopf c6b79f82bc fix: change password new version 2022-02-22 10:03:51 +08:00
xiaoxiaoqiong 4e3f9cc019 竞赛通知任务调度 2022-02-21 16:48:59 +08:00
xiaoxiaoqiong 5ed7b3e4ad 竞赛通知任务调度 2022-02-21 16:46:40 +08:00
xiaoxiaoqiong 4e2c46260c Merge remote-tracking branch 'origin/develop' into develop 2022-02-17 18:28:40 +08:00
xiaoxiaoqiong 9ba00b21c9 竞赛通知api 2022-02-17 18:28:32 +08:00
yystopf b11f5fd228 fix: cache rollback 2022-02-17 11:12:50 +08:00
yystopf 90dbe0730a fix: job not affect 2022-02-17 10:59:18 +08:00
yystopf d6633cb73a fix 2022-02-17 09:43:44 +08:00
yystopf a7a6abd22a fix: add rule for issue expire 2022-02-17 09:40:44 +08:00
yystopf c956667ce0 fix 2022-02-17 09:36:49 +08:00
yystopf 5701c818ed fix 2022-02-16 15:10:10 +08:00
yystopf 1ac2ddfaa5 fix: default setting for new template message 2022-02-16 11:46:34 +08:00
yystopf 4aac05d4e1 fix: build user template message data must fronted 2022-02-16 11:17:03 +08:00
yystopf 84b56bfcb8 fix: project milestone create notice template 2022-02-16 09:34:31 +08:00
yystopf 7485564bb9 add: template message platform varible 2022-02-15 18:30:13 +08:00
yystopf b5acf2308a Merge pull request '新增站内信以及里程碑完成度修复' (#299) from yystopf/forgeplus:develop into develop 2022-02-15 17:33:30 +08:00
yystopf e3f4313c80 fix 2022-02-15 17:29:13 +08:00
yystopf b223abe229 fix: init data 2022-02-15 17:26:46 +08:00
yystopf b3bede308c add: some new message rules 2022-02-15 17:13:06 +08:00
xiaoxiaoqiong 2f170a54c6 fixed setting编辑类型下拉选中 2022-02-15 17:10:57 +08:00
yystopf 22293572ac fix: issue changed about version callback 2022-02-14 17:02:59 +08:00
xiaoxiaoqiong 8720cab1e9 通过配置确定github克隆方式 2022-02-14 16:53:29 +08:00
yystopf 959c1e8d95 add: user profile setting message 2022-02-14 13:55:34 +08:00
yystopf 29dc3fff39 fix: migrate use old rule 2022-02-11 16:27:22 +08:00
yystopf 298abdd1b1 fix: devops organization bug 2022-02-10 14:08:14 +08:00
yystopf 26f87fba16 fix: edit transfer need change fork info 2022-01-25 14:26:11 +08:00
yystopf 1e9a32a93e fix: issues select count paginator 2022-01-25 11:39:06 +08:00
yystopf 2dc79052c2 fix: create project trend when status is closed 2022-01-25 10:34:20 +08:00
yystopf 380ca3a066 fix: projects query rule 2022-01-24 14:26:24 +08:00
yystopf 237b0afb08 fix: team user build use find or create by 2022-01-24 10:44:46 +08:00
yystopf e14936e820 fix: issues select count 2022-01-24 10:00:44 +08:00
yystopf 655c85851f Merge branch 'develop' of https://git.trustie.net/Gitlink/forgeplus into develop 2022-01-21 18:20:40 +08:00
yystopf 1c7e414aa4 fix: owner allow nil 2022-01-21 18:19:43 +08:00
yystopf 099fc52e00 fix: contributor error rescue 2022-01-21 18:19:34 +08:00
yystopf 490957ec3b fix: contributor error rescue 2022-01-21 18:19:27 +08:00
yystopf b1884d30d5 fix: detail result delay 2022-01-21 18:19:06 +08:00
xiaoxiaoqiong 98d8ee1fb6 Merge remote-tracking branch 'origin/develop' into develop 2022-01-21 15:50:41 +08:00
xiaoxiaoqiong 2ca77732c8 fixed 注册登录类型 2022-01-21 15:50:37 +08:00
yystopf 70d22f7c4f fix: create team overflow tip 2022-01-14 16:09:38 +08:00
yystopf 25d0e784bb fix: pr assignee info use array 2022-01-14 16:00:59 +08:00
yystopf 5d45b24299 fix: devops return result changed 2022-01-14 10:55:53 +08:00
yystopf b6b8befde7 fix: pr update must edit assignee login 2022-01-14 10:55:01 +08:00
yystopf f33b9559cd fix: download delay 2022-01-13 11:24:27 +08:00
yystopf f9bc2258ec fix: migrate repo github use another addr 2022-01-11 10:48:29 +08:00
205 changed files with 3564 additions and 2013 deletions

View File

@ -1,376 +1,416 @@
class AccountsController < ApplicationController class AccountsController < ApplicationController
include ApplicationHelper before_action :require_login, only: [:login_check, :simple_update]
include ApplicationHelper
#skip_before_action :check_account, :only => [:logout]
#skip_before_action :check_account, :only => [:logout]
def index
render json: session def simple_update
end simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
# 其他平台同步注册的用户 simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
def remote_register Register::RemoteForm.new(simple_update_params).validate!
Register::RemoteForm.new(remote_register_params).validate!
username = params[:username]&.gsub(/\s+/, "") ActiveRecord::Base.transaction do
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) result = auto_update(current_user, simple_update_params)
email = params[:email]&.gsub(/\s+/, "") if result[:message].blank?
password = params[:password] render_ok
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") else
render_error(result[:message])
ActiveRecord::Base.transaction do end
result = autologin_register(username, email, password, platform) end
if result[:message].blank? end
render_ok({user: result[:user]})
else def index
render_error(result[:message]) render json: session
end end
end
rescue Exception => e # 为了同步平台上未注册gitea的用户
uid_logger_error(e.message) def gitea_register
tip_exception(-1, e.message) user = User.find_by(login: sync_gitea_params[:login])
end Users::SyncGiteaForm.new(sync_gitea_params.merge(user: user)).validate!
return render_error("该用户已同步协作平台") if user.gitea_token.present? && user.gitea_uid.present?
# 其他平台修改用户的信息,这边同步修改
def remote_update result = create_gitea_user!(user, sync_gitea_params[:login], sync_gitea_params[:email], sync_gitea_params[:password])
ActiveRecord::Base.transaction do result[:user] ? render_ok : render_error(result[:message])
user_params = params[:user_params] rescue Exception => e
user_extension_params = params[:user_extension_params] uid_logger_error(e.message)
tip_exception(-1, e.message)
u = User.find_by(login: params[:old_user_login]) end
user_mail = u.try(:mail)
# 其他平台同步注册的用户
if u.present? def remote_register
ue = u.user_extension Register::RemoteForm.new(remote_register_params).validate!
u.login = user_params["login"] if user_params["login"] username = params[:username]&.gsub(/\s+/, "")
u.mail = user_params["mail"] if user_params["mail"] tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
u.lastname = user_params["lastname"] if user_params["lastname"] email = params[:email]&.gsub(/\s+/, "")
password = params[:password]
ue.gender = user_extension_params["gender"] platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
ue.school_id = user_extension_params["school_id"]
ue.location = user_extension_params["location"] ActiveRecord::Base.transaction do
ue.location_city = user_extension_params["location_city"] result = autologin_register(username, email, password, platform)
ue.identity = user_extension_params["identity"] if result[:message].blank?
ue.technical_title = user_extension_params["technical_title"] render_ok({user: result[:user]})
ue.student_id = user_extension_params["student_id"] else
ue.description = user_extension_params["description"] render_error(result[:message])
ue.save! end
u.save! end
rescue Exception => e
sync_params = {} uid_logger_error(e.message)
tip_exception(-1, e.message)
if (user_params["mail"] && user_params["mail"] != user_mail) end
sync_params = sync_params.merge(email: user_params["mail"])
end # 其他平台修改用户的信息,这边同步修改
def remote_update
if sync_params.present? ActiveRecord::Base.transaction do
interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) user_params = params[:user_params]
if interactor.success? user_extension_params = params[:user_extension_params]
render_ok
else u = User.find_by(login: params[:old_user_login])
render_error(interactor.error) user_mail = u.try(:mail)
end
end if u.present?
end ue = u.user_extension
end u.login = user_params["login"] if user_params["login"]
rescue Exception => e u.mail = user_params["mail"] if user_params["mail"]
uid_logger_error(e.message) u.lastname = user_params["lastname"] if user_params["lastname"]
tip_exception(-1, e.message)
end ue.gender = user_extension_params["gender"]
ue.school_id = user_extension_params["school_id"]
# 其他平台同步登录 ue.location = user_extension_params["location"]
def remote_login ue.location_city = user_extension_params["location_city"]
@user = User.try_to_login(params[:login], params[:password]) ue.identity = user_extension_params["identity"]
if @user ue.technical_title = user_extension_params["technical_title"]
successful_authentication(@user) ue.student_id = user_extension_params["student_id"]
render_ok({user: {id: @user.id, token: @user.gitea_token}}) ue.description = user_extension_params["description"]
else ue.save!
render_error("用户不存在") u.save!
end
end sync_params = {}
#修改密码 if (user_params["mail"] && user_params["mail"] != user_mail)
def remote_password sync_params = sync_params.merge(email: user_params["mail"])
@user = User.find_by(login: params[:login]) end
return render_error("未找到相关用户!") if @user.blank?
if sync_params.present?
sync_params = { interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params)
password: params[:password].to_s, if interactor.success?
email: @user.mail render_ok
} else
render_error(interactor.error)
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) end
if interactor.success? end
@user.update_attribute(:password, params[:password]) end
render_ok end
else rescue Exception => e
render_error(interactor.error) uid_logger_error(e.message)
end tip_exception(-1, e.message)
end end
# 其他平台同步登录
def remote_login
# 用户注册 @user = User.try_to_login(params[:login], params[:password])
# 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 if @user
# params[:login] 邮箱或者手机号 successful_authentication(@user)
# params[:namespace] 登录名 render_ok({user: {id: @user.id, token: @user.gitea_token}})
# params[:code] 验证码 else
# code_type 1注册手机验证码 8邮箱注册验证码 render_error("用户不存在")
# 本地forge注册入口需要重新更改逻辑 end
def register end
# type只可能是1或者8
user = nil #修改密码
begin def remote_password
Register::Form.new(register_params).validate! @user = User.find_by(login: params[:login])
return render_error("未找到相关用户!") if @user.blank?
user = Users::RegisterService.call(register_params)
password = register_params[:password].strip sync_params = {
password: params[:password].to_s,
# gitea用户注册, email, username, password email: @user.mail
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) }
if interactor.success?
gitea_user = interactor.result interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
result = Gitea::User::GenerateTokenService.call(user.login, password) if interactor.success?
user.gitea_token = result['sha1'] @user.update_attribute(:password, params[:password])
user.gitea_uid = gitea_user[:body]['id'] render_ok
if user.save! else
UserExtension.create!(user_id: user.id) render_error(interactor.error)
successful_authentication(user) end
render_ok end
end
else
tip_exception(-1, interactor.error)
end # 用户注册
rescue Register::BaseForm::EmailError => e # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用
render_error(-2, e.message) # params[:login] 邮箱或者手机号
rescue Register::BaseForm::LoginError => e # params[:namespace] 登录名
render_error(-3, e.message) # params[:code] 验证码
rescue Register::BaseForm::PhoneError => e # code_type 1注册手机验证码 8邮箱注册验证码
render_error(-4, e.message) # 本地forge注册入口需要重新更改逻辑
rescue Register::BaseForm::PasswordFormatError => e def register
render_error(-5, e.message) # type只可能是1或者8
rescue Register::BaseForm::VerifiCodeError => e user = nil
render_error(-6, e.message) begin
rescue Exception => e Register::Form.new(register_params).validate!
Gitea::User::DeleteService.call(user.login) unless user.nil?
uid_logger_error(e.message) user = Users::RegisterService.call(register_params)
tip_exception(-1, e.message) password = register_params[:password].strip
end
end # gitea用户注册, email, username, password
interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password})
# 用户登录 if interactor.success?
def login gitea_user = interactor.result
Users::LoginForm.new(account_params).validate! result = Gitea::User::GenerateTokenService.call(user.login, password)
@user = User.try_to_login(params[:login], params[:password]) user.gitea_token = result['sha1']
user.gitea_uid = gitea_user[:body]['id']
return normal_status(-2, "错误的账号或密码") if @user.blank? if user.save!
# user is already in local database UserExtension.create!(user_id: user.id)
return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? successful_authentication(user)
render_ok
login_control = LimitForbidControl::UserLogin.new(@user) end
return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? else
tip_exception(-1, interactor.error)
password_ok = @user.check_password?(params[:password].to_s) end
unless password_ok rescue Register::BaseForm::EmailError => e
if login_control.remain_times-1 == 0 render_error(-2, e.message)
normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") rescue Register::BaseForm::LoginError => e
else render_error(-3, e.message)
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") rescue Register::BaseForm::PhoneError => e
end render_error(-4, e.message)
login_control.increment! rescue Register::BaseForm::PasswordFormatError => e
return render_error(-5, e.message)
end rescue Register::BaseForm::VerifiCodeError => e
render_error(-6, e.message)
successful_authentication(@user) rescue Exception => e
sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 Gitea::User::DeleteService.call(user.login) unless user.nil?
uid_logger_error(e.message)
# session[:user_id] = @user.id tip_exception(-1, e.message)
end end
end
def change_password
@user = User.find_by(login: params[:login]) # 用户登录
return render_error("未找到相关用户!") if @user.blank? def login
return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) Users::LoginForm.new(account_params).validate!
@user = User.try_to_login(params[:login], params[:password])
sync_params = {
password: params[:password].to_s, return normal_status(-2, "错误的账号或密码") if @user.blank?
email: @user.mail # user is already in local database
} return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked?
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) login_control = LimitForbidControl::UserLogin.new(@user)
if interactor.success? return normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid?
@user.update_attribute(:password, params[:password])
render_ok password_ok = @user.check_password?(params[:password].to_s)
else unless password_ok
render_error(interactor.error) if login_control.remain_times-1 == 0
end normal_status(-2, "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码")
end else
normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会")
# 忘记密码 end
def reset_password login_control.increment!
begin return
code = params[:code] end
login_type = phone_mail_type(params[:login].strip)
# 获取验证码 successful_authentication(@user)
if login_type == 1 sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步
phone = params[:login]
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last # session[:user_id] = @user.id
user = User.find_by_phone(phone) end
else
email = params[:login] def change_password
verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last @user = User.find_by(login: params[:login])
user = User.find_by_mail(email) #这里有问题应该是为email,而不是mail 6.13-hs return render_error("未找到相关用户!") if @user.blank?
end return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
return normal_status(-2, "验证码已失效") if !verifi_code&.effective? sync_params = {
return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD password: params[:password].to_s,
email: @user.mail,
user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] login_name: @user.login,
ActiveRecord::Base.transaction do source_id: 0
user.save! }
LimitForbidControl::UserLogin.new(user).clear
end interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
sucess_status if interactor.success?
rescue Exception => e @user.update_attribute(:password, params[:password])
uid_logger_error(e.message) render_ok
tip_exception(e.message) else
end render_error(interactor.error)
end end
end
def successful_authentication(user)
uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") # 忘记密码
# Valid user def reset_password
self.logged_user = user begin
# generate a key and set cookie if autologin code = params[:code]
login_type = phone_mail_type(params[:login].strip)
set_autologin_cookie(user) # 获取验证码
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) if login_type == 1
user.update_column(:last_login_on, Time.now) phone = params[:login]
session[:"#{default_yun_session}"] = user.id verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") user = User.find_by_phone(phone)
# 注册完成后有一天的试用申请(先去掉) else
# UserDayCertification.create(user_id: user.id, status: 1) email = params[:login]
end verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last
user = User.find_by_mail(email) #这里有问题应该是为email,而不是mail 6.13-hs
def set_autologin_cookie(user) end
token = Token.get_or_create_permanent_login_token(user, "autologin") return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
sync_user_token_to_trustie(user.login, token.value) return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD
cookie_options = {
:value => token.value, user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation]
:expires => 1.month.from_now, ActiveRecord::Base.transaction do
:path => '/', user.save!
:secure => false, LimitForbidControl::UserLogin.new(user).clear
:httponly => true end
} sucess_status
if edu_setting('cookie_domain').present? rescue Exception => e
cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) uid_logger_error(e.message)
end tip_exception(e.message)
cookies[autologin_cookie_name] = cookie_options end
cookies.signed[:user_id] ||= user.id end
logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") def successful_authentication(user)
end uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}")
# Valid user
def logout self.logged_user = user
Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") # generate a key and set cookie if autologin
UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip)
logout_user set_autologin_cookie(user)
render :json => {status: 1, message: "退出成功!"} UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
end user.update_column(:last_login_on, Time.now)
session[:"#{default_yun_session}"] = user.id
# 检验邮箱是否已被注册及邮箱或者手机号是否合法 Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
# 参数type为事件类型 1注册2忘记密码3绑定 # 注册完成后有一天的试用申请(先去掉)
def valid_email_and_phone # UserDayCertification.create(user_id: user.id, status: 1)
check_mail_and_phone_valid(params[:login], params[:type]) end
end
def set_autologin_cookie(user)
# 发送验证码 token = Token.get_or_create_permanent_login_token(user, "autologin")
# params[:login] 手机号或者邮箱号 sync_user_token_to_trustie(user.login, token.value)
# params[:type]为事件通知类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
# 发送验证码send_type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱 cookie_options = {
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9: 验收手机号有效 :value => token.value,
def get_verification_code :expires => 1.month.from_now,
code = %W(0 1 2 3 4 5 6 7 8 9) :path => '/',
value = params[:login] :secure => false,
type = params[:type].strip.to_i :httponly => true
login_type = phone_mail_type(value) }
send_type = verify_type(login_type, type) if edu_setting('cookie_domain').present?
verification_code = code.sample(6).join cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain'))
end
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") cookies[autologin_cookie_name] = cookie_options
tip_exception(501, "请求不合理") if sign != params[:smscode] cookies.signed[:user_id] ||= user.id
logger.info "########### 验证码:#{verification_code}" logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}")
logger.info("########get_verification_code: login_type #{login_type} send_type#{send_type}, ") end
# 记录验证码 def logout
check_verification_code(verification_code, send_type, value) Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}")
render_ok UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip)
end logout_user
render :json => {status: 1, message: "退出成功!"}
# check user's login or email or phone is used end
# params[:value] 手机号或者邮箱号或者登录名
# params[:type] 为事件类型 1登录名(login) 2email(邮箱) 3phone(手机号) # 检验邮箱是否已被注册及邮箱或者手机号是否合法
def check # 参数type为事件类型 1注册2忘记密码3绑定
Register::CheckColumnsForm.new(check_params).validate! def valid_email_and_phone
render_ok check_mail_and_phone_valid(params[:login], params[:type])
end end
private # 发送验证码
# params[:login] 手机号或者邮箱号
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 # params[:type]为事件通知类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
# login_type 1手机类型 2邮箱类型 # 发送验证码send_type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱
def verify_type login_type, type # 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9: 验收手机号有效
case type def get_verification_code
when 1 code = %W(0 1 2 3 4 5 6 7 8 9)
login_type == 1 ? 1 : 8 value = params[:login]
when 2 type = params[:type].strip.to_i
login_type == 1 ? 2 : 3 login_type = phone_mail_type(value)
when 3 send_type = verify_type(login_type, type)
login_type == 1 ? 4 : tip_exception('请填写正确的手机号') verification_code = code.sample(6).join
when 4
login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
when 5 tip_exception(501, "请求不合理") if sign != params[:smscode]
login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
end logger.info "########### 验证码:#{verification_code}"
end logger.info("########get_verification_code: login_type #{login_type} send_type#{send_type}, ")
def generate_login(login) # 记录验证码
type = phone_mail_type(login.strip) check_verification_code(verification_code, send_type, value)
render_ok
if type == 1 end
uid_logger("start register by phone: type is #{type}")
pre = 'p' # check user's login or email or phone is used
email = nil # params[:value] 手机号或者邮箱号或者登录名
phone = login # params[:type] 为事件类型 1登录名(login) 2email(邮箱) 3phone(手机号)
else def check
uid_logger("start register by email: type is #{type}") Register::CheckColumnsForm.new(check_params).validate!
pre = 'm' render_ok
email = login end
phone = nil
end def login_check
code = generate_identifier User, 8, pre Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate!
render_ok
{ login: pre + code, email: email, phone: phone } end
end
private
def user_params
params.require(:user).permit(:login, :email, :phone) # type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
end # login_type 1手机类型 2邮箱类型
def verify_type login_type, type
def account_params case type
params.require(:account).permit(:login, :password) when 1
end login_type == 1 ? 1 : 8
when 2
def check_params login_type == 1 ? 2 : 3
params.permit(:type, :value) when 3
end login_type == 1 ? 4 : tip_exception('请填写正确的手机号')
when 4
def register_params login_type == 1 ? tip_exception('请填写正确的邮箱') : 5
params.permit(:login, :namespace, :password, :code) when 5
end login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
end
def remote_register_params end
params.permit(:username, :email, :password, :platform)
end def generate_login(login)
type = phone_mail_type(login.strip)
end
if type == 1
uid_logger("start register by phone: type is #{type}")
pre = 'p'
email = nil
phone = login
else
uid_logger("start register by email: type is #{type}")
pre = 'm'
email = login
phone = nil
end
code = generate_identifier User, 8, pre
{ login: pre + code, email: email, phone: phone }
end
def user_params
params.require(:user).permit(:login, :email, :phone)
end
def account_params
params.require(:account).permit(:login, :password)
end
def check_params
params.permit(:type, :value)
end
def register_params
params.permit(:login, :namespace, :password, :code)
end
def remote_register_params
params.permit(:username, :email, :password, :platform)
end
def simple_update_params
params.permit(:username, :email, :password, :platform)
end
end

View File

@ -2,7 +2,7 @@ class Admins::ImportUsersController < Admins::BaseController
def create def create
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
result = Admins::ImportUserService.call(params[:file].to_io) result = Admins::ImportUserFromExcelService.call(params[:file].to_io)
render_ok(result) render_ok(result)
rescue Admins::ImportUserService::Error => ex rescue Admins::ImportUserService::Error => ex
render_error(ex) render_error(ex)

View File

@ -174,11 +174,11 @@ class ApplicationController < ActionController::Base
end end
def require_profile_completed def require_profile_completed
tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed? # tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
end end
def require_user_profile_completed(user) def require_user_profile_completed(user)
tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed? # tip_exception(412, "请用户完善资料后再操作") unless user.profile_is_completed?
end end
# 异常提醒 # 异常提醒

View File

@ -217,7 +217,7 @@ class AttachmentsController < ApplicationController
if @file.container && current_user.logged? if @file.container && current_user.logged?
if @file.container.is_a?(Issue) if @file.container.is_a?(Issue)
course = @file.container.project course = @file.container.project
candown = course.member?(current_user) candown = course.member?(current_user) || course.is_public
elsif @file.container.is_a?(Journal) elsif @file.container.is_a?(Journal)
course = @file.container.issue.project course = @file.container.issue.project
candown = course.member?(current_user) candown = course.member?(current_user)

View File

@ -8,7 +8,7 @@ class Ci::BaseController < ApplicationController
namespace = params[:owner] namespace = params[:owner]
id = params[:repo] || params[:id] id = params[:repo] || params[:id]
@ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id) @ci_user, @repo = Ci::Repo.find_with_namespace(namespace, id, current_user.login)
end end
def load_all_repo def load_all_repo

View File

@ -46,7 +46,7 @@ class Ci::SecretsController < Ci::BaseController
end end
def ci_drone_url def ci_drone_url
user = User.find_by(login: params[:owner]) user = User.find_by(login: params[:owner]) || User.find_by(login: current_user.login)
user&.ci_cloud_account.drone_url user&.ci_cloud_account.drone_url
end end

View File

@ -9,23 +9,29 @@ class CompareController < ApplicationController
load_compare_params load_compare_params
compare compare
@merge_status, @merge_message = get_merge_message @merge_status, @merge_message = get_merge_message
@page_size = page_size <= 0 ? 1 : page_size
@page_limit = page_limit <=0 ? 15 : page_limit
@page_offset = (@page_size -1) * @page_limit
Rails.logger.info("+========#{@page_size}-#{@page_limit}-#{@page_offset}")
end end
private private
def get_merge_message
def get_merge_message
if @base.blank? || @head.blank? if @base.blank? || @head.blank?
return -2, "请选择分支" return -2, "请选择分支"
else else
return -2, "目标仓库未开启合并请求PR功能" unless @project.has_menu_permission("pulls")
if @head.include?(":") if @head.include?(":")
fork_project = @project.forked_projects.joins(:owner).where(users: {login: @head.to_s.split("/")[0]}).take fork_project = @project.forked_projects.joins(:owner).where(users: { login: @head.to_s.split("/")[0] }).take
return -2, "请选择正确的仓库" unless fork_project.present? return -2, "请选择正确的仓库" unless fork_project.present?
@exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take @exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take
else else
@exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).take @exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).last
end end
if @exist_pullrequest.present? if @exist_pullrequest.present?
return -2, "在这些分支之间的合并请求已存在:<a href='/#{@owner.login}/#{@project.identifier}/pulls/#{@exist_pullrequest.id}'>#{@exist_pullrequest.try(:title)}</a>" return -2, "在这些分支之间的合并请求已存在:<a href='/#{@owner.login}/#{@project.identifier}/pulls/#{@exist_pullrequest.id}'>#{@exist_pullrequest.try(:title)}</a>"
else else
if @compare_result["Commits"].blank? && @compare_result["Diff"].blank? if @compare_result["Commits"].blank? && @compare_result["Diff"].blank?
return -2, "分支内容相同,无需创建合并请求" return -2, "分支内容相同,无需创建合并请求"
end end
@ -50,6 +56,14 @@ class CompareController < ApplicationController
end end
def gitea_compare(base, head) def gitea_compare(base, head)
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, CGI.escape(base), CGI.escape(head), current_user.gitea_token) Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token)
end
def page_size
params.fetch(:page, 1).to_i
end
def page_limit
params.fetch(:limit, 15).to_i
end end
end end

View File

@ -179,7 +179,7 @@ module Ci::CloudAccountManageable
def drone_oauth_user!(url, state) def drone_oauth_user!(url, state)
logger.info "[drone] drone_oauth_user url: #{url}" logger.info "[drone] drone_oauth_user url: #{url}"
conn = Faraday.new(url: url) do |req| conn = Faraday.new(url: "#{Gitea.gitea_config[:domain]}#{url}") do |req|
req.request :url_encoded req.request :url_encoded
req.adapter Faraday.default_adapter req.adapter Faraday.default_adapter
req.headers["cookie"] = "_session_=#{SecureRandom.hex(28)}; _oauth_state_=#{state}" req.headers["cookie"] = "_session_=#{SecureRandom.hex(28)}; _oauth_state_=#{state}"
@ -188,7 +188,8 @@ module Ci::CloudAccountManageable
response = conn.get response = conn.get
logger.info "[drone] response headers: #{response.headers}" logger.info "[drone] response headers: #{response.headers}"
response.headers['location'].include?('error') ? false : true true
# response.headers['location'].include?('error') ? false : true
end end
private private

View File

@ -35,15 +35,15 @@ module LaboratoryHelper
# my_projects: "/users/#{current_user.try(:login)}/projects", # my_projects: "/users/#{current_user.try(:login)}/projects",
# my_projects: "https://www.trustie.net/users/#{current_user.try(:login)}/user_projectlist", # my_projects: "https://www.trustie.net/users/#{current_user.try(:login)}/user_projectlist",
{ {
new_syllabuses: "https://www.trustie.net/syllabuses/new", new_syllabuses: "https://forge.educoder.net/syllabuses/new",
new_course: "https://www.trustie.net/courses/new", new_course: "https://forge.educoder.net/courses/new",
edit_account: "https://www.trustie.net/my/account", edit_account: "https://forge.educoder.net/my/account",
my_courses: "https://www.trustie.net/users/#{current_user.try(:login)}/user_courselist", my_courses: "https://forge.educoder.net/users/#{current_user.try(:login)}/user_courselist",
my_projects: "/users/#{current_user.try(:login)}/projects", my_projects: "/users/#{current_user.try(:login)}/projects",
my_organ: "https://www.trustie.net/users/#{current_user.try(:login)}/user_organizations", my_organ: "https://forge.educoder.net/users/#{current_user.try(:login)}/user_organizations",
default_url: Rails.application.config_for(:configuration)['platform_url'], default_url: "https://www.educoder.net/",
tiding_url: "https://www.trustie.net/users/#{current_user.try(:login)}/user_messages", tiding_url: "https://www.educoder.net/users/#{current_user.try(:login)}/user_tidings",
register_url: "https://www.trustie.net/login?login=false" register_url: "https://www.educoder.net/user/register"
} }
end end
end end

View File

@ -108,7 +108,11 @@ module LoginHelper
def sync_pwd_to_gitea!(user, hash={}) def sync_pwd_to_gitea!(user, hash={})
return true if user.is_sync_pwd? return true if user.is_sync_pwd?
sync_params = { email: user.mail } sync_params = {
login_name: user.name,
source_id: 0,
email: user.mail
}
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash)) interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
if interactor.success? if interactor.success?
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########" Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"

View File

@ -2,7 +2,6 @@ module RegisterHelper
extend ActiveSupport::Concern extend ActiveSupport::Concern
def autologin_register(username, email, password, platform= 'forge') def autologin_register(username, email, password, platform= 'forge')
result = {message: nil, user: nil}
user = User.new(admin: false, login: username, mail: email, type: "User") user = User.new(admin: false, login: username, mail: email, type: "User")
user.password = password user.password = password
@ -11,20 +10,64 @@ module RegisterHelper
return unless user.valid? return unless user.valid?
create_gitea_user!(user, username, email, password)
end
def create_gitea_user!(forge_user, username, email, password=random_password)
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
if interactor.success? if interactor.success? || interactor.error.to_s.include?("已被注册")
gitea_user = interactor.result gitea_user = interactor.error.to_s.include?("已被注册") ? Gitea::User::GetService.call(username, password) : interactor.result
result = Gitea::User::GenerateTokenService.call(username, password) Rails.logger.info "##### [gitea] create_gitea_user result: #{gitea_user}"
user.gitea_token = result['sha1'] if gitea_user[:body].present?
user.gitea_uid = gitea_user[:body]['id'] result = Gitea::User::GenerateTokenService.call(username, password)
if user.save! forge_user.gitea_token = result['sha1']
UserExtension.create!(user_id: user.id) forge_user.gitea_uid = gitea_user[:body]['id'] if gitea_user[:body].present? && gitea_user[:body]['id'] !=0
result[:user] = {id: user.id, token: user.gitea_token} forge_user.mail = email
if forge_user.save
UserExtension.create!(user_id: forge_user.id) if forge_user.user_extension.blank?
result[:user] = {id: forge_user.id, token: forge_user.gitea_token}
end
else
result[:message] = interactor.error
end end
else else
Rails.logger.info "##### [gitea] create_gitea_user result: #{interactor.error}"
result[:message] = interactor.error result[:message] = interactor.error
end end
result result
end end
def random_password
"#{Random.rand(11111111)}"
end
def auto_update(user, params={})
return if params.blank?
result = {message: nil, user: nil}
before_login = user.login
user.login = params[:username]
user.password = params[:password]
user.mail = params[:email]
if user.save!
sync_params = {
password: params[:password].to_s,
email: params[:email],
login_name: params[:username],
new_name: params[:username],
source_id: 0
}
interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params)
if interactor.success?
result[:user] = user
else
result[:message] = '用户同步Gitea失败!'
end
else
result[:message] = user.errors.full_messages.join(",")
return
end
end
end end

View File

@ -3,7 +3,7 @@ module RenderHelper
render json: { status: 0, message: 'success' }.merge(data) render json: { status: 0, message: 'success' }.merge(data)
end end
def render_error(status = -1, message = '') def render_error(message = '', status=-1)
render json: { status: status, message: message } render json: { status: status, message: message }
end end

View File

@ -6,6 +6,13 @@ class ForksController < ApplicationController
def create def create
@new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call @new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call
# TODO: fix Educoder shixun
if @new_project.persisted?
ProjectScore.create(:project_id => @new_project.id, :score => 0) if @new_project.project_score.nil?
project_info = ProjectInfo.new(:user_id => current_user.id, :project_id => @new_project.id)
@project.project_infos << project_info
end
end end
private private

View File

@ -24,13 +24,13 @@ class IssuesController < ApplicationController
@filter_issues = @all_issues @filter_issues = @all_issues
@filter_issues = @filter_issues.where.not(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::ADD @filter_issues = @filter_issues.where.not(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::ADD
@filter_issues = @filter_issues.where(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::SOLVING @filter_issues = @filter_issues.where(status_id: IssueStatus::CLOSED) if params[:status_type].to_i == IssueStatus::SOLVING
@filter_issues = @filter_issues.where("subject LIKE ? OR description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present? @filter_issues = @filter_issues.where("issues.subject LIKE ? OR issues.description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present?
@open_issues = @all_issues.where.not(status_id: IssueStatus::CLOSED) @open_issues = @all_issues.where.not(status_id: IssueStatus::CLOSED)
@close_issues = @all_issues.where(status_id: IssueStatus::CLOSED) @close_issues = @all_issues.where(status_id: IssueStatus::CLOSED)
@assign_to_me = @filter_issues.where(assigned_to_id: current_user&.id)
@my_published = @filter_issues.where(author_id: current_user&.id)
scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "Issue") scopes = Issues::ListQueryService.call(issues,params.delete_if{|k,v| v.blank?}, "Issue")
@issues_size = scopes.size @issues_size = scopes.size
@assign_to_me = scopes.where(assigned_to_id: current_user&.id)
@my_published = scopes.where(author_id: current_user&.id)
@issues = paginate(scopes) @issues = paginate(scopes)
respond_to do |format| respond_to do |format|
@ -109,7 +109,7 @@ class IssuesController < ApplicationController
def create def create
issue_params = issue_send_params(params) issue_params = issue_send_params(params)
Issues::CreateForm.new({subject:issue_params[:subject]}).validate! Issues::CreateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
@issue = Issue.new(issue_params) @issue = Issue.new(issue_params)
if @issue.save! if @issue.save!
SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('IssueAssigned', current_user.id, @issue&.id) if Site.has_notice_menu?
@ -149,6 +149,8 @@ class IssuesController < ApplicationController
end end
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
@issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: ProjectTrend::CLOSE) if params[:status_id].to_i == 5
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}" Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0 AtmeService.call(current_user, @atme_receivers, @issue) if @atme_receivers.size > 0
@ -178,6 +180,7 @@ class IssuesController < ApplicationController
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1 elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
@issue&.issue_tags_relates&.destroy_all @issue&.issue_tags_relates&.destroy_all
params[:issue_tag_ids].each do |tag| params[:issue_tag_ids].each do |tag|
next if tag == [""]
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag) IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
end end
else else
@ -220,7 +223,7 @@ class IssuesController < ApplicationController
normal_status(-1, "不允许修改为关闭状态") normal_status(-1, "不允许修改为关闭状态")
else else
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
Issues::UpdateForm.new({subject:issue_params[:subject]}).validate! Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
if @issue.update_attributes(issue_params) if @issue.update_attributes(issue_params)
if @issue&.pull_request.present? if @issue&.pull_request.present?
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
@ -244,7 +247,7 @@ class IssuesController < ApplicationController
end end
if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时
@issue.issue_times.update_all(end_time: Time.now) @issue.issue_times.update_all(end_time: Time.now)
@issue.update_closed_issues_count_in_project! # @issue.update_closed_issues_count_in_project!
if @issue.issue_type.to_s == "2" && last_status_id != 5 if @issue.issue_type.to_s == "2" && last_status_id != 5
if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token if @issue.assigned_to_id.present? && last_status_id == 3 #只有当用户完成100%时才给token
post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login)) post_to_chain("add", @issue.token, @issue.get_assign_user.try(:login))

View File

@ -23,6 +23,7 @@ class JournalsController < ApplicationController
normal_status(-1, "评论内容不能为空") normal_status(-1, "评论内容不能为空")
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Journals::CreateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
journal_params = { journal_params = {
journalized_id: @issue.id , journalized_id: @issue.id ,
journalized_type: "Issue", journalized_type: "Issue",
@ -53,6 +54,9 @@ class JournalsController < ApplicationController
end end
end end
end end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end end
def destroy def destroy
@ -70,7 +74,8 @@ class JournalsController < ApplicationController
def update def update
content = params[:content] content = params[:content]
if content.present? if content.present?
Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
if @journal.update_attribute(:notes, content) if @journal.update_attribute(:notes, content)
normal_status(0, "更新成功") normal_status(0, "更新成功")
else else
@ -79,7 +84,9 @@ class JournalsController < ApplicationController
else else
normal_status(-1, "评论的内容不能为空") normal_status(-1, "评论的内容不能为空")
end end
rescue Exception => exception
puts exception.message
normal_status(-1, exception.message)
end end
def get_children_journals def get_children_journals

View File

@ -21,6 +21,14 @@ class MainController < ApplicationController
uid_logger("main start is #{cookies[:_educoder_session]}") uid_logger("main start is #{cookies[:_educoder_session]}")
end end
if params[:path] && params[:path].start_with?('projects/')
project_id = params[:path].split("/")[1]
project = Project.find_by_id(project_id)
if project.present?
return redirect_to("/projects/#{project.owner.login}/#{project.identifier}", status: 301)
end
end
# TODO: 这块之后需要整合者架构重新变化统一跳转到index后再路由分发 # TODO: 这块之后需要整合者架构重新变化统一跳转到index后再路由分发
if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild" if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild"
render file: 'public/h5educoderbuild/index.html', :layout => false, :content_type=> 'text/html' render file: 'public/h5educoderbuild/index.html', :layout => false, :content_type=> 'text/html'

View File

@ -8,6 +8,14 @@ class MembersController < ApplicationController
before_action :check_member_not_exists!, only: %i[remove change_role] before_action :check_member_not_exists!, only: %i[remove change_role]
def create def create
if @user.gitea_token.blank?
result = Gitea::User::GetService.call(@user.login)
if result[:status] == :error
# gitea不存在用户@user,直接注册
user_result = create_gitea_user!(@user, @user.login, @user.mail)
return render_error(user_result[:message]) if user_result[:message]
end
end
interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user) interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user)
SendTemplateMessageJob.perform_later('ProjectJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('ProjectJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('ProjectMemberJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('ProjectMemberJoined', current_user.id, @user.id, @project.id) if Site.has_notice_menu?

View File

@ -0,0 +1,21 @@
class NoticesController < ApplicationController
def create
tip_exception("参数有误") if params["source"].blank?
user_id = params[:user_id]
if params["source"] == "CompetitionBegin"
competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionBegin', user_id, competition_id)
elsif params["source"] == "CompetitionResult"
competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionResult', user_id, competition_id)
elsif params["source"] == "CompetitionReview"
competition_id = params[:competition_id]
SendTemplateMessageJob.perform_later('CompetitionReview', user_id, competition_id)
else
tip_exception("#{params["source"]}未配置")
end
render_ok
end
end

View File

@ -5,7 +5,11 @@ class Organizations::OrganizationUsersController < Organizations::BaseController
def index def index
@organization_users = @organization.organization_users.includes(:user) @organization_users = @organization.organization_users.includes(:user)
search = params[:search].to_s.downcase search = params[:search].to_s.downcase
@organization_users = @organization_users.joins(:user).merge(User.like(search)) user_condition_users = User.like(search).to_sql
team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql
users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users")
@organization_users = @organization_users.where(user_id: users).distinct
@organization_users = kaminari_paginate(@organization_users) @organization_users = kaminari_paginate(@organization_users)
end end

View File

@ -44,7 +44,7 @@ class Organizations::TeamsController < Organizations::BaseController
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
if @organization.teams.count >= 50 if @organization.teams.count >= 50
return render_forbidden("组织的团队数量已超过限制!") return tip_exception("组织的团队数量已超过限制!")
else else
Organizations::CreateTeamForm.new(team_params).validate! Organizations::CreateTeamForm.new(team_params).validate!
@team = Organizations::Teams::CreateService.call(current_user, @organization, team_params) @team = Organizations::Teams::CreateService.call(current_user, @organization, team_params)

View File

@ -12,7 +12,7 @@ class OwnersController < ApplicationController
def show def show
@owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id]) @owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id])
# return render_not_found unless @owner.present? return render_not_found unless @owner.present?
# 组织 # 组织
if @owner.is_a?(Organization) if @owner.is_a?(Organization)
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition

View File

@ -12,6 +12,7 @@ class PraiseTreadController < ApplicationController
begin begin
return normal_status(2, "你已点过赞了") if current_user.liked?(@project) return normal_status(2, "你已点过赞了") if current_user.liked?(@project)
current_user.like!(@project) current_user.like!(@project)
SendTemplateMessageJob.perform_later('ProjectPraised', current_user.id, @project.id) if Site.has_notice_menu?
render_ok({praises_count: @project.praises_count, praised: current_user.liked?(@project)}) render_ok({praises_count: @project.praises_count, praised: current_user.liked?(@project)})
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)

View File

@ -13,6 +13,8 @@ class ProjectsController < ApplicationController
def menu_list def menu_list
menu = [] menu = []
user_is_admin = current_user.admin? || @project.manager?(current_user)
menu.append(menu_hash_by_name("home")) menu.append(menu_hash_by_name("home"))
menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code") menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code")
menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues") menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues")
@ -22,7 +24,8 @@ class ProjectsController < ApplicationController
menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge? menu.append(menu_hash_by_name("wiki")) if @project.has_menu_permission("wiki") && @project.forge?
menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge? menu.append(menu_hash_by_name("resources")) if @project.has_menu_permission("resources") && @project.forge?
menu.append(menu_hash_by_name("activity")) menu.append(menu_hash_by_name("activity"))
menu.append(menu_hash_by_name("settings")) if (current_user.admin? || @project.manager?(current_user)) && @project.forge? menu.append(menu_hash_by_name("settings")) if user_is_admin && @project.forge?
menu.append(menu_hash_by_name("quit")) if !user_is_admin && @project.member(current_user.id) && @project.forge?
render json: menu render json: menu
end end
@ -49,6 +52,13 @@ class ProjectsController < ApplicationController
Projects::CreateForm.new(project_params).validate! Projects::CreateForm.new(project_params).validate!
@project = Projects::CreateService.new(current_user, project_params).call @project = Projects::CreateService.new(current_user, project_params).call
# TODO: fix Educoder shixun
if @project.persisted?
ProjectScore.create(:project_id => @project.id, :score => 0) if @project.project_score.nil?
project_info = ProjectInfo.new(:user_id => current_user.id, :project_id => @project.id)
@project.project_infos << project_info
end
end end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
@ -59,7 +69,7 @@ class ProjectsController < ApplicationController
Projects::MigrateForm.new(mirror_params).validate! Projects::MigrateForm.new(mirror_params).validate!
@project = @project =
if enable_accelerator?(mirror_params[:clone_addr]) if EduSetting.get("mirror_address").to_s.include?("github") && enable_accelerator?(mirror_params[:clone_addr])
source_clone_url = mirror_params[:clone_addr] source_clone_url = mirror_params[:clone_addr]
uid_logger("########## 已动加速器 ##########") uid_logger("########## 已动加速器 ##########")
result = Gitea::Accelerator::MigrateService.call(mirror_params) result = Gitea::Accelerator::MigrateService.call(mirror_params)
@ -71,6 +81,11 @@ class ProjectsController < ApplicationController
else else
Projects::MigrateService.call(current_user, mirror_params) Projects::MigrateService.call(current_user, mirror_params)
end end
elsif EduSetting.get("mirror_address").to_s.include?("cnpmjs") && mirror_params[:clone_addr].include?("github.com")
source_clone_url = mirror_params[:clone_addr]
clone_url = source_clone_url.gsub('github.com', 'github.com.cnpmjs.org')
uid_logger("########## 更改clone_addr ##########")
Projects::MigrateService.call(current_user, mirror_params.merge(source_clone_url: source_clone_url, clone_addr: clone_url))
else else
Projects::MigrateService.call(current_user, mirror_params) Projects::MigrateService.call(current_user, mirror_params)
end end
@ -83,7 +98,7 @@ class ProjectsController < ApplicationController
return @branches = [] unless @project.forge? return @branches = [] unless @project.forge?
# result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier) # result = Gitea::Repository::Branches::ListService.call(@owner, @project.identifier)
result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier) result = Gitea::Repository::Branches::ListNameService.call(@owner, @project.identifier, params[:name])
@branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result["branch_name"]) : result @branches = result.is_a?(Hash) ? (result.key?(:status) ? [] : result["branch_name"]) : result
end end
@ -95,18 +110,18 @@ class ProjectsController < ApplicationController
end end
def group_type_list def group_type_list
project_statics = ProjectStatistic.first # project_statics = ProjectStatistic.first
@project_statics_list = [ @project_statics_list = [
{ {
project_type: 'common', project_type: 'common',
name: '开源托管项目', name: '开源托管项目',
projects_count: project_statics&.common_projects_count || 0 projects_count: Project.common.size || 0
}, },
{ {
project_type: 'mirror', project_type: 'mirror',
name: '开源镜像项目', name: '开源镜像项目',
projects_count: project_statics&.mirror_projects_count || 0 projects_count: Project.sync_mirror.size + Project.mirror.size || 0
} }
] ]
@ -130,7 +145,7 @@ class ProjectsController < ApplicationController
validate_params = project_params.slice(:name, :description, validate_params = project_params.slice(:name, :description,
:project_category_id, :project_language_id, :private, :identifier) :project_category_id, :project_language_id, :private, :identifier)
Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier)).validate! Projects::UpdateForm.new(validate_params.merge(user_id: @project.user_id, project_identifier: @project.identifier, project_name: @project.name)).validate!
private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false
@ -172,6 +187,22 @@ class ProjectsController < ApplicationController
tip_exception(e.message) tip_exception(e.message)
end end
def quit
user_is_admin = current_user.admin? || @project.manager?(current_user)
if !user_is_admin && @project.member(current_user.id) && @project.forge?
ActiveRecord::Base.transaction do
Projects::DeleteMemberInteractor.call(@project.owner, @project, current_user)
SendTemplateMessageJob.perform_later('ProjectMemberLeft', current_user.id, current_user.id, @project.id) if Site.has_notice_menu?
render_ok
end
else
render_forbidden('你不能退出该仓库')
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def watch_users def watch_users
watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct watchers = @project.watchers.includes(:user).order("watchers.created_at desc").distinct
@watchers_count = watchers.size @watchers_count = watchers.size
@ -185,7 +216,7 @@ class ProjectsController < ApplicationController
end end
def fork_users def fork_users
fork_users = @project.fork_users.includes(:user, :project, :fork_project).order("fork_users.created_at desc").distinct fork_users = @project.fork_users.includes(:owner, :project, :fork_project).order("fork_users.created_at desc").distinct
@forks_count = fork_users.size @forks_count = fork_users.size
@fork_users = paginate(fork_users) @fork_users = paginate(fork_users)
end end

View File

@ -2,7 +2,7 @@ class PullRequestsController < ApplicationController
before_action :require_login, except: [:index, :show, :files, :commits] before_action :require_login, except: [:index, :show, :files, :commits]
before_action :require_profile_completed, only: [:create] before_action :require_profile_completed, only: [:create]
before_action :load_repository before_action :load_repository
before_action :check_menu_authorize before_action :check_menu_authorize, only: [:index, :show, :create, :update, :refuse_merge, :pr_merge]
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits] before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits]
before_action :load_pull_request, only: [:files, :commits] before_action :load_pull_request, only: [:files, :commits]
before_action :find_atme_receivers, only: [:create, :update] before_action :find_atme_receivers, only: [:create, :update]
@ -16,7 +16,7 @@ class PullRequestsController < ApplicationController
issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user)) issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user))
@all_issues = issues.distinct @all_issues = issues.distinct
@filter_issues = @all_issues @filter_issues = @all_issues
@filter_issues = @filter_issues.where("subject LIKE ? OR description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present? @filter_issues = @filter_issues.where("issues.subject LIKE ? OR issues.description LIKE ? ", "%#{params[:search]}%", "%#{params[:search]}%") if params[:search].present?
@open_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::OPEN}) @open_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::OPEN})
@close_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::CLOSED}) @close_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::CLOSED})
@merged_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::MERGED}) @merged_issues = @filter_issues.joins(:pull_request).where(pull_requests: {status: PullRequest::MERGED})
@ -29,7 +29,7 @@ class PullRequestsController < ApplicationController
end end
def new def new
@all_branches = Branches::ListService.call(@owner, @project) @all_branches = Branches::ListService.call(@owner, @project, params[:branch_name])
@is_fork = @project.forked_from_project_id.present? @is_fork = @project.forked_from_project_id.present?
@projects_names = [{ @projects_names = [{
project_user_login: @owner.try(:login), project_user_login: @owner.try(:login),
@ -50,7 +50,7 @@ class PullRequestsController < ApplicationController
end end
def get_branches def get_branches
branch_result = Branches::ListService.call(@owner, @project) branch_result = Branches::ListService.call(@owner, @project, params[:name])
render json: branch_result render json: branch_result
# return json: branch_result # return json: branch_result
end end
@ -58,6 +58,7 @@ class PullRequestsController < ApplicationController
def create def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user) # return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params) @pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
if @gitea_pull_request[:status] == :success if @gitea_pull_request[:status] == :success
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"]) @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
@ -89,7 +90,7 @@ class PullRequestsController < ApplicationController
else else
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
return normal_status(-1, "title不能超过255个字符") if params[:title].length > 255 Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
merge_params merge_params
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank? @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
@ -274,12 +275,12 @@ class PullRequestsController < ApplicationController
base: params[:base], #目标分支 base: params[:base], #目标分支
milestone: 0, #里程碑,未与本地的里程碑关联 milestone: 0, #里程碑,未与本地的里程碑关联
} }
assignee_login = User.find_by_id(params[:assigned_to_id])&.login
@requests_params = @local_params.merge({ @requests_params = @local_params.merge({
assignee: current_user.try(:login),
# assignees: ["#{params[:assigned_login].to_s}"], # assignees: ["#{params[:assigned_login].to_s}"],
assignees: ["#{current_user.try(:login).to_s}"], assignees: ["#{assignee_login.to_s}"],
labels: params[:issue_tag_ids], labels: params[:issue_tag_ids]
due_date: Time.now # due_date: Time.now
}) })
@issue_params = { @issue_params = {
author_id: current_user.id, author_id: current_user.id,

View File

@ -150,8 +150,11 @@ class RepositoriesController < ApplicationController
if params[:filepath].present? || @project.educoder? if params[:filepath].present? || @project.educoder?
@contributors = [] @contributors = []
else else
@contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier) result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
@contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result
end end
rescue
@contributors = []
end end
def edit def edit
@ -222,7 +225,8 @@ class RepositoriesController < ApplicationController
@path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" @path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
@readme = result[:status] === :success ? result[:body] : nil @readme = result[:status] === :success ? result[:body] : nil
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha") @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content")
rescue rescue
render json: nil render json: nil
end end
@ -238,7 +242,7 @@ class RepositoriesController < ApplicationController
def archive def archive
domain = Gitea.gitea_config[:domain] domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = Gitea.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{CGI.escape(params[:archive])}" archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"
file_path = [domain, api_url, archive_url].join file_path = [domain, api_url, archive_url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden? file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
@ -252,7 +256,7 @@ class RepositoriesController < ApplicationController
domain = Gitea.gitea_config[:domain] domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url] api_url = Gitea.gitea_config[:base_url]
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{CGI.escape(params[:filepath])}?ref=#{CGI.escape(params[:ref])}" url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}"
file_path = [domain, api_url, url].join file_path = [domain, api_url, url].join
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&") file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&")
@ -376,7 +380,7 @@ class RepositoriesController < ApplicationController
local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id)) local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id))
if local_requests.save if local_requests.save
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"]) if gitea_request[:status] == :success && local_requests.update_attributes(gitea_number: gitea_request["body"]["number"])
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
end end
end end

View File

@ -1,13 +1,23 @@
class SettingsController < ApplicationController class SettingsController < ApplicationController
def show def show
@old_projects_url = nil @old_projects_url = nil
get_navbar
get_add_menu get_add_menu
get_common_menu get_common_menu
get_personal_menu get_personal_menu
get_top_system_notification get_top_system_notification
get_banner
end end
private private
def get_navbar
@navbar = default_laboratory.navbar
if User.current.logged?
pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false}
@navbar << pernal_index
end
end
def get_add_menu def get_add_menu
@add = [] @add = []
Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site| Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
@ -58,4 +68,14 @@ class SettingsController < ApplicationController
def append_http(url) def append_http(url)
url.to_s.start_with?("http") ? url : [request.protocol, request.host_with_port, url].join('') url.to_s.start_with?("http") ? url : [request.protocol, request.host_with_port, url].join('')
end end
def get_banner
@banner = {
title: EduSetting.get("banner_title") || '大学开源',
sub_title: EduSetting.get("banner_sub_title") || '让大学绽放开源之花',
content: EduSetting.get("banner_content") || "Powered by Trustie and GitLink"
}
@banner
end
end end

View File

@ -12,7 +12,7 @@ class Users::StatisticsController < Users::BaseController
@commit_data = [] @commit_data = []
date_range.each do |date| date_range.each do |date|
@date_data << date.strftime("%Y.%m.%d") @date_data << date.strftime("%Y.%m.%d")
@issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size @issue_data << observed_user.issues.issue_issue.where("DATE(created_on) = ?", date).size
@pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size @pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size
date_commit_data = commit_data.blank? ? nil : commit_data.select{|item| item["timestamp"] == date.to_time.to_i} date_commit_data = commit_data.blank? ? nil : commit_data.select{|item| item["timestamp"] == date.to_time.to_i}
@commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i) @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i)

View File

@ -23,6 +23,8 @@ class Users::TemplateMessageSettingsController < Users::BaseController
def get_current_setting def get_current_setting
@current_setting = @_observed_user.user_template_message_setting @current_setting = @_observed_user.user_template_message_setting
@current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil? @current_setting = UserTemplateMessageSetting.build(@_observed_user.id) if @current_setting.nil?
@current_setting.notification_body.merge!(UserTemplateMessageSetting.init_notification_body.except(*@current_setting.notification_body.keys))
@current_setting.email_body.merge!(UserTemplateMessageSetting.init_email_body.except(*@current_setting.email_body.keys))
end end
def setting_params def setting_params

View File

@ -4,9 +4,9 @@ class UsersController < ApplicationController
before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users, :hovercard] before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users, :hovercard]
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard] before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard]
before_action :require_login, only: %i[me list sync_user_info] before_action :require_login, only: %i[me list]
before_action :connect_to_ci_db, only: [:get_user_info] before_action :connect_to_ci_db, only: [:get_user_info]
before_action :convert_image!, only: [:update, :update_image] before_action :convert_image!, only: [:update]
skip_before_action :check_sign, only: [:attachment_show] skip_before_action :check_sign, only: [:attachment_show]
def connect_to_ci_db(options={}) def connect_to_ci_db(options={})
@ -32,8 +32,7 @@ class UsersController < ApplicationController
@waiting_applied_messages = @user.applied_messages.waiting @waiting_applied_messages = @user.applied_messages.waiting
@common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @user.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @user.id}, teams: {authorize: %w(admin owner)} )).common @common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @user.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @user.id}, teams: {authorize: %w(admin owner)} )).common
@common_applied_projects = AppliedProject.where(project_id: @user.full_admin_projects).common @common_applied_projects = AppliedProject.where(project_id: @user.full_admin_projects).common
#@undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size @undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size
@undo_events = @common_applied_transfer_projects.size + @common_applied_projects.size
else else
@waiting_applied_messages = AppliedMessage.none @waiting_applied_messages = AppliedMessage.none
@common_applied_transfer_projects = AppliedTransferProject.none @common_applied_transfer_projects = AppliedTransferProject.none
@ -52,8 +51,6 @@ class UsersController < ApplicationController
@projects_common_count = user_projects.common.size @projects_common_count = user_projects.common.size
@projects_mirrior_count = user_projects.mirror.size @projects_mirrior_count = user_projects.mirror.size
@projects_sync_mirrior_count = user_projects.sync_mirror.size @projects_sync_mirrior_count = user_projects.sync_mirror.size
# 为了缓存活跃用户的基本信息,后续删除
Cache::V2::OwnerCommonService.new(@user.id).read
end end
def watch_users def watch_users
@ -82,7 +79,7 @@ class UsersController < ApplicationController
Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? Util.write_file(@image, avatar_path(@user)) if user_params[:image].present?
@user.attributes = user_params.except(:image) @user.attributes = user_params.except(:image)
unless @user.save unless @user.save
render_error(-1, @user.errors.full_messages.join(", ")) render_error(@user.errors.full_messages.join(", "))
end end
end end
@ -97,6 +94,13 @@ class UsersController < ApplicationController
render_error(-1, '头像修改失败!') render_error(-1, '头像修改失败!')
end end
def get_image
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
redirect_to Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(@user).to_s
end
def me def me
@user = current_user @user = current_user
end end
@ -205,7 +209,7 @@ class UsersController < ApplicationController
def trustie_related_projects def trustie_related_projects
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc") projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
projects_json = [] projects_json = []
domain_url = EduSetting.get('host_name') domain_url = EduSetting.get('host_name') + '/projects'
if projects.present? if projects.present?
projects.each do |p| projects.each do |p|
project_url = "/#{p.owner.login}/#{p.identifier}" project_url = "/#{p.owner.login}/#{p.identifier}"
@ -274,26 +278,68 @@ class UsersController < ApplicationController
render_ok render_ok
end end
def sync_user_info # TODO: For Educoder
def change_password
user = User.find_by_login params[:login] user = User.find_by_login params[:login]
return render_forbidden unless user === current_user return render_error("用户 #{params[:login]} 不存在.") if user.nil?
form_params= {
login: params[:login],
email: user&.mail,
password: params[:password],
user: user
}
Gitea::User::ChangePasswordForm.new(form_params).validate!
sync_params = { sync_params = {
email: params[:email], email: user&.mail,
password: params[:password] password: params[:password]
} }
Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate! if sync_params.present?
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params) if interactor.success?
if interactor.success? user.update!(password: params[:password], is_sync_pwd: true)
user.update!(password: params[:password], mail: params[:email], status: User::STATUS_EDIT_INFO) render_ok
render_ok else
else render_error(interactor.error)
render_error(interactor.error) end
end end
end end
# TODO: For Educoder
def change_email
user = User.find_by_login params[:login]
return render_error("用户 #{rq_params[:login]} 不存在.") if user.nil?
form_params= {
login: params[:login],
email: user&.mail,
user: user
}
Gitea::User::ChangeEmailForm.new(form_params).validate!
sync_params = {
email: params[:email]
}
if sync_params.present?
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params)
if interactor.success?
user.update!(mail: params[:email])
render_ok
else
render_error(interactor.error)
end
end
end
def email_search
return render_error('请输入email') if params[:email].blank?
@user = User.find_by(mail: params[:email])
end
private private
def load_user def load_user
@user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id])
@ -306,6 +352,7 @@ class UsersController < ApplicationController
:occupation, :technical_title, :occupation, :technical_title,
:school_id, :department_id, :province, :city, :school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description, :custom_department, :identity, :student_id, :description,
:show_super_description, :super_description,
:show_email, :show_location, :show_department] :show_email, :show_location, :show_department]
) )
end end

View File

@ -14,7 +14,7 @@ class VersionReleasesController < ApplicationController
def new def new
#获取所有的分支 #获取所有的分支
@all_branches = [] @all_branches = []
get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @repository.try(:identifier)).call get_all_branches = Gitea::Repository::Branches::ListService.new(@user, @repository.try(:identifier), params[:branch_name]).call
if get_all_branches && get_all_branches.size > 0 if get_all_branches && get_all_branches.size > 0
get_all_branches.each do |b| get_all_branches.each do |b|
@all_branches.push(b["name"]) @all_branches.push(b["name"])

View File

@ -91,10 +91,9 @@ await octokit.request('GET /api/users/:login/messages.json')
类型|说明 类型|说明
--------- | ----------- --------- | -----------
|IssueAssigned | 有新指派给我的疑修 | |IssueAssigned | 有新指派给我的疑修 |
|IssueAssignerExpire | 我负责的疑修截止日期到达最后一天 | |IssueExpire | 我创建或负责的疑修截止日期到达最后一天 |
|IssueAtme | 在疑修中@我 | |IssueAtme | 在疑修中@我 |
|IssueChanged | 我创建或负责的疑修状态变更 | |IssueChanged | 我创建或负责的疑修状态变更 |
|IssueCreatorExpire | 我创建的疑修截止日期到达最后一天 |
|IssueDeleted | 我创建或负责的疑修删除 | |IssueDeleted | 我创建或负责的疑修删除 |
|IssueJournal | 我创建或负责的疑修有新的评论 | |IssueJournal | 我创建或负责的疑修有新的评论 |
|LoginIpTip | 登录异常提示 | |LoginIpTip | 登录异常提示 |
@ -109,6 +108,7 @@ await octokit.request('GET /api/users/:login/messages.json')
|ProjectLeft | 账号被移出项目 | |ProjectLeft | 账号被移出项目 |
|ProjectMemberJoined | 我管理的仓库有成员加入 | |ProjectMemberJoined | 我管理的仓库有成员加入 |
|ProjectMemberLeft | 我管理的仓库有成员移出 | |ProjectMemberLeft | 我管理的仓库有成员移出 |
|ProjectMilestoneCompleted | 我管理的仓库有里程碑完成度100% |
|ProjectMilestone | 我管理的仓库有新的里程碑 | |ProjectMilestone | 我管理的仓库有新的里程碑 |
|ProjectPraised | 我管理的仓库被点赞 | |ProjectPraised | 我管理的仓库被点赞 |
|ProjectPullRequest | 我管理/关注的仓库有新的合并请求 | |ProjectPullRequest | 我管理/关注的仓库有新的合并请求 |

View File

@ -50,4 +50,10 @@ class BaseForm
def strip(str) def strip(str)
str.to_s.strip.presence str.to_s.strip.presence
end end
# 1 手机类型0 邮箱类型
# 注意新版的login是自动名生成的
def phone_mail_type value
value =~ /^1\d{10}$/ ? 1 : 0
end
end end

View File

@ -0,0 +1,9 @@
class Gitea::User::ChangeEmailForm
include ActiveModel::Model
attr_accessor :user
attr_accessor :email, :login
validates :email, presence: true, format: { with: CustomRegexp::EMAIL }
validates :login, presence: true
end

View File

@ -0,0 +1,22 @@
class Gitea::User::ChangePasswordForm
include ActiveModel::Model
attr_accessor :user
attr_accessor :email, :login, :password
validates :email, presence: true, format: { with: CustomRegexp::EMAIL }
validates :login, presence: true
validates :password, presence: true
# validate :check_old_password
def check_old_password
return if user.check_password?(old_password.to_s)
errors.add(:old_password, :password_error)
end
# def check_user!
# user === current_user
# end
end

View File

@ -0,0 +1,18 @@
class Users::SyncGiteaForm
include ActiveModel::Model
attr_accessor :login, :password, :email, :user
validates :login, :password, :email, presence: true
validate :check_user, :check_password
def check_user
user = User.find_by(login: login)
raise '用户不存在.' unless user.present?
end
def check_password
raise '用户密码错误.' unless user.check_password?(password)
end
end

View File

@ -4,7 +4,7 @@ class Gitea::User::UpdateForm
attr_accessor :username, :email, :admin, :allow_create_organization, :allow_git_hook, :allow_import_local, attr_accessor :username, :email, :admin, :allow_create_organization, :allow_git_hook, :allow_import_local,
:full_name, :location, :login_name, :max_repo_creation, :must_change_password, :password, :prohibit_login, :full_name, :location, :login_name, :max_repo_creation, :must_change_password, :password, :prohibit_login,
:source_id, :website :source_id, :website, :new_name
validates :username, presence: true validates :username, presence: true
validates :email, presence: true, format: { with: EMAIL_REGEX, multiline: true } validates :email, presence: true, format: { with: EMAIL_REGEX, multiline: true }

View File

@ -1,11 +1,11 @@
class Issues::CreateForm class Issues::CreateForm
include ActiveModel::Model include ActiveModel::Model
attr_accessor :subject attr_accessor :subject, :description
validates :subject, presence: { message: "不能为空" } validates :subject, presence: { message: "不能为空" }
validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" } validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
validates :description, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end end

View File

@ -1,10 +1,12 @@
class Issues::UpdateForm class Issues::UpdateForm
include ActiveModel::Model include ActiveModel::Model
attr_accessor :subject attr_accessor :subject, :description
validates :subject, presence: { message: "不能为空" } validates :subject, presence: { message: "不能为空" }
validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" } validates :subject, length: { maximum: 200, too_long: "不能超过200个字符" }
validates :description, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end end

View File

@ -0,0 +1,7 @@
class Journals::CreateForm
include ActiveModel::Model
attr_accessor :notes
validates :notes, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -0,0 +1,8 @@
class Journals::UpdateForm
include ActiveModel::Model
attr_accessor :notes
validates :notes, length: { maximum: 65535, too_long: "不能超过65535个字符"}
end

View File

@ -1,5 +1,5 @@
class Projects::UpdateForm < BaseForm class Projects::UpdateForm < BaseForm
attr_accessor :name, :description, :project_category_id, :project_language_id, :private, :identifier, :user_id, :project_identifier attr_accessor :name, :description, :project_category_id, :project_language_id, :private, :identifier, :user_id, :project_identifier, :project_name
validates :name, presence: true validates :name, presence: true
validates :name, length: { maximum: 50 } validates :name, length: { maximum: 50 }
validates :description, length: { maximum: 200 } validates :description, length: { maximum: 200 }
@ -10,6 +10,7 @@ class Projects::UpdateForm < BaseForm
check_project_language(project_language_id) check_project_language(project_language_id)
check_repository_name(user_id, identifier) unless identifier.blank? || identifier == project_identifier check_repository_name(user_id, identifier) unless identifier.blank? || identifier == project_identifier
check_project_name(user_id, name) unless name.blank? || name == project_name
end end
end end

View File

@ -10,28 +10,40 @@ module Register
VerifiCodeError = Class.new(Error) VerifiCodeError = Class.new(Error)
private private
def check_login(login) def check_login(login, user=nil)
login = strip(login) login = strip(login)
raise LoginError, "登录名格式有误" unless login =~ CustomRegexp::LOGIN raise LoginError, "登录名格式有误" unless login =~ CustomRegexp::LOGIN
login_exist = Owner.exists?(login: login) || ReversedKeyword.check_exists?(login) login_exist = Owner.exists?(login: login) || ReversedKeyword.check_exists?(login)
raise LoginError, '登录名已被使用' if login_exist if user.present?
raise LoginError, '登录名已被使用' if login_exist && login != user&.login
else
raise LoginError, '登录名已被使用' if login_exist
end
end end
def check_mail(mail) def check_mail(mail, user=nil)
mail = strip(mail) mail = strip(mail)
raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL
mail_exist = Owner.exists?(mail: mail) mail_exist = Owner.exists?(mail: mail)
raise EmailError, '邮箱已被使用' if mail_exist if user.present?
raise EmailError, '邮箱已被使用' if mail_exist && mail != user&.mail
else
raise EmailError, '邮箱已被使用' if mail_exist
end
end end
def check_phone(phone) def check_phone(phone, user=nil)
phone = strip(phone) phone = strip(phone)
raise PhoneError, "手机号格式有误" unless phone =~ CustomRegexp::PHONE raise PhoneError, "手机号格式有误" unless phone =~ CustomRegexp::PHONE
phone_exist = Owner.exists?(phone: phone) phone_exist = Owner.exists?(phone: phone)
raise PhoneError, '手机号已被使用' if phone_exist if user.present?
raise PhoneError, '手机号已被使用' if phone_exist && phone != user&.phone
else
raise PhoneError, '手机号已被使用' if phone_exist
end
end end
def check_password(password) def check_password(password)

View File

@ -10,7 +10,8 @@ module Register
def check! def check!
Rails.logger.info "Register::Form params: code: #{code}; login: #{login}; namespace: #{namespace}; password: #{password}; type: #{type}" Rails.logger.info "Register::Form params: code: #{code}; login: #{login}; namespace: #{namespace}; password: #{password}; type: #{type}"
db_verifi_code = type = phone_mail_type(strip(login))
db_verifi_code =
if type == 1 if type == 1
check_phone(login) check_phone(login)
VerificationCode.where(phone: login, code: code, code_type: 1).last VerificationCode.where(phone: login, code: code, code_type: 1).last

View File

@ -0,0 +1,19 @@
module Register
class LoginCheckColumnsForm < Register::BaseForm
attr_accessor :type, :value, :user
validates :type, presence: true, numericality: true
validates :value, presence: true
validate :check!
def check!
# params[:type] 为事件类型 1登录名(login) 2email(邮箱) 3phone(手机号)
case strip(type).to_i
when 1 then check_login(strip(value), user)
when 2 then check_mail(strip(value), user)
when 3 then check_phone(strip(value), user)
else raise("type值无效")
end
end
end
end

View File

@ -147,6 +147,15 @@ module ApplicationHelper
end end
end end
def url_to_avatar_with_platform_url(source)
platform_url = Rails.application.config_for(:configuration)['platform_url']
if platform_url
return Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(source).to_s
else
return url_to_avatar(source).to_s
end
end
# 主页banner图 # 主页banner图
def banner_img(source_type) def banner_img(source_type)
if File.exist?(disk_filename(source_type, "banner")) if File.exist?(disk_filename(source_type, "banner"))

View File

@ -11,7 +11,7 @@ module RepositoriesHelper
def download_type(str) def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv) default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv)
default_type.include?(str&.downcase) default_type.include?(str&.downcase) || str.blank?
end end
def image_type?(str) def image_type?(str)
@ -22,7 +22,7 @@ module RepositoriesHelper
def is_readme?(type, str) def is_readme?(type, str)
return false if type != 'file' || str.blank? return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"] readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase) readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX
end end
def render_commit_author(author_json) def render_commit_author(author_json)
@ -36,7 +36,6 @@ module RepositoriesHelper
end end
def render_cache_commit_author(author_json) def render_cache_commit_author(author_json)
Rails.logger.info author_json['Email']
if author_json["name"].present? && author_json["email"].present? if author_json["name"].present? && author_json["email"].present?
return find_user_in_redis_cache(author_json['name'], author_json['email']) return find_user_in_redis_cache(author_json['name'], author_json['email'])
end end
@ -57,6 +56,7 @@ module RepositoriesHelper
total_images = ss + ss_src total_images = ss + ss_src
if total_images.length > 0 if total_images.length > 0
total_images.each do |s| total_images.each do |s|
begin
image_title = /\"(.*?)\"/ image_title = /\"(.*?)\"/
r_content = s[0] r_content = s[0]
remove_title = r_content.to_s.scan(image_title) remove_title = r_content.to_s.scan(image_title)
@ -75,6 +75,9 @@ module RepositoriesHelper
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{r_content}&ref=#{ref}"].join new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{r_content}&ref=#{ref}"].join
end end
content = content.gsub(/#{r_content}/, new_r_content) content = content.gsub(/#{r_content}/, new_r_content)
rescue
next
end
end end
end end
@ -84,6 +87,46 @@ module RepositoriesHelper
end end
end end
# author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank?
content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(s_regex)
ss_src = content.to_s.scan(src_regex)
total_sources = ss + ss_src
total_sources.uniq!
total_sources.each do |s|
begin
s_content = s[0]
# 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1]
if image_type?(ext) || download_type(ext)
s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}")
s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
content = content.gsub(s[0], s_content)
else
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub(s[0], "/#{s_content}")
end
rescue
next
end
end
return content
rescue
return str
end
# unix_time values for example: 1604382982 # unix_time values for example: 1604382982
def render_format_time_with_unix(unix_time) def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M") Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
@ -94,10 +137,21 @@ module RepositoriesHelper
date.to_time.strftime("%Y-%m-%d %H:%M") date.to_time.strftime("%Y-%m-%d %H:%M")
end end
def readme_decode64_content(entry, owner, repo, ref, path=nil)
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end
def decode64_content(entry, owner, repo, ref, path=nil) def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name']) if is_readme?(entry['type'], entry['name'])
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
readme_render_decode64_content(content, owner, repo, ref) Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
return Base64.decode64(content).force_encoding('UTF-8')
else else
file_type = File.extname(entry['name'].to_s)[1..-1] file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type) if image_type?(file_type)

View File

@ -0,0 +1,15 @@
class Admins::NewImportUserFromExcel < BaseImportXlsx
UserData = Struct.new(:login, :email, :password, :nickname)
def read_each(&block)
sheet.each_row_streaming(pad_cells: true, offset: 1) do |row|
data = row.map(&method(:cell_value))[0..3]
block.call UserData.new(*data)
end
end
private
def cell_value(obj)
obj&.cell_value
end
end

View File

@ -23,7 +23,11 @@ module Gitea
def run def run
Gitea::UserForm.new(params).validate! Gitea::UserForm.new(params).validate!
response = Gitea::User::RegisterService.call(params.merge(token: token)) response = Gitea::User::RegisterService.call(params.merge(token: token))
render_result(response) if response[:status] == :success
@result = response
else
fail!(response[:message])
end
rescue Exception => exception rescue Exception => exception
Rails.logger.info "Exception ===========> #{exception.message}" Rails.logger.info "Exception ===========> #{exception.message}"
fail!(exception.message) fail!(exception.message)
@ -38,10 +42,6 @@ module Gitea
@error = error @error = error
end end
def render_result(response)
@result = response
end
def token def token
{ {
username: Gitea.gitea_config[:access_key_id], username: Gitea.gitea_config[:access_key_id],

View File

@ -7,6 +7,8 @@ class CacheAsyncClearJob < ApplicationJob
Cache::V2::ProjectCommonService.new(id).clear Cache::V2::ProjectCommonService.new(id).clear
when "owner_common_service" when "owner_common_service"
Cache::V2::OwnnerCommonService.new(id).clear Cache::V2::OwnnerCommonService.new(id).clear
when "project_rank_service"
Cache::V2::ProjectRankService.new(id).clear
end end
end end
end end

View File

@ -3,8 +3,7 @@ class DelayExpiredIssueJob < ApplicationJob
def perform def perform
Issue.where(due_date: Date.today + 1.days).find_each do |issue| Issue.where(due_date: Date.today + 1.days).find_each do |issue|
SendTemplateMessageJob.perform_later('IssueAssignerExpire', issue.id) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('IssueExpire', issue.id) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('IssueCreatorExpire', issue.id) if Site.has_notice_menu?
end end
end end

View File

@ -24,13 +24,6 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::IssueAssigned.get_email_message_content(receiver, operator, issue) receivers_email_string, email_title, email_content = MessageTemplate::IssueAssigned.get_email_message_content(receiver, operator, issue)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'IssueAssignerExpire'
issue_id = args[0]
issue = Issue.find_by_id(issue_id)
return unless issue.present?
receivers = User.where(id: issue&.assigned_to_id)
receivers_string, content, notification_url = MessageTemplate::IssueAssignerExpire.get_message_content(receivers, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id})
when 'IssueAtme' when 'IssueAtme'
receivers, operator_id, issue_id = args[0], args[1], args[2] receivers, operator_id, issue_id = args[0], args[1], args[2]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)
@ -52,13 +45,17 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params) receivers_email_string, email_title, email_content = MessageTemplate::IssueChanged.get_email_message_content(receiver, operator, issue, change_params)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'IssueCreatorExpire' when 'IssueExpire'
issue_id = args[0] issue_id = args[0]
issue = Issue.find_by_id(issue_id) issue = Issue.find_by_id(issue_id)
return unless issue.present? return unless issue.present?
receivers = User.where(id: issue&.author_id) receivers = User.where(id: [issue&.assigned_to_id, issue&.author_id])
receivers_string, content, notification_url = MessageTemplate::IssueCreatorExpire.get_message_content(receivers, issue) receivers_string, content, notification_url = MessageTemplate::IssueExpire.get_message_content(receivers, issue)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id}) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {issue_id: issue.id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::IssueExpire.get_email_message_content(receiver, issue)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'IssueDeleted' when 'IssueDeleted'
operator_id, issue_title, issue_assigned_to_id, issue_author_id = args[0], args[1], args[2], args[3] operator_id, issue_title, issue_assigned_to_id, issue_author_id = args[0], args[1], args[2], args[3]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)
@ -94,6 +91,14 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::OrganizationLeft.get_email_message_content(receiver, organization) receivers_email_string, email_title, email_content = MessageTemplate::OrganizationLeft.get_email_message_content(receiver, organization)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'ProjectForked'
operator_id, project_id = args[0], args[1]
operator = User.find_by_id(operator_id)
project = Project.find_by_id(project_id)
return unless operator.present? && project.present?
receivers = project&.all_managers.where.not(id: operator&.id)
receivers_string, content, notification_url = MessageTemplate::ProjectForked.get_message_content(receivers, operator, project)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
when 'ProjectIssue' when 'ProjectIssue'
operator_id, issue_id = args[0], args[1] operator_id, issue_id = args[0], args[1]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)
@ -163,6 +168,37 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberLeft.get_email_message_content(receiver, user, project) receivers_email_string, email_title, email_content = MessageTemplate::ProjectMemberLeft.get_email_message_content(receiver, user, project)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'ProjectMilestoneCompleted'
milestone_id = args[0]
milestone = Version.find_by_id(milestone_id)
return unless milestone.present? && milestone&.project.present?
receivers = milestone&.project&.all_managers
receivers_string, content, notification_url = MessageTemplate::ProjectMilestoneCompleted.get_message_content(receivers, milestone)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestoneCompleted.get_email_message_content(receiver, milestone)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectMilestone'
milestone_id, operator_id = args[0], args[1]
milestone = Version.find_by_id(milestone_id)
operator = User.find_by_id(operator_id)
return unless milestone.present? && milestone&.project.present? && operator.present?
receivers = milestone&.project&.all_managers.where.not(id: operator_id)
receivers_string, content, notification_url = MessageTemplate::ProjectMilestone.get_message_content(receivers, operator, milestone)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {milestone_id: milestone_id, operator_id: operator_id})
receivers.find_each do |receiver|
receivers_email_string, email_title, email_content = MessageTemplate::ProjectMilestone.get_email_message_content(receiver, operator, milestone)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end
when 'ProjectPraised'
operator_id, project_id = args[0], args[1]
operator = User.find_by_id(operator_id)
project = Project.find_by_id(project_id)
return unless operator.present? && project.present?
receivers = project&.all_managers.where.not(id: operator&.id)
receivers_string, content, notification_url = MessageTemplate::ProjectPraised.get_message_content(receivers, operator, project)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
when 'ProjectPullRequest' when 'ProjectPullRequest'
operator_id, pull_request_id = args[0], args[1] operator_id, pull_request_id = args[0], args[1]
operator = User.find_by_id(operator_id) operator = User.find_by_id(operator_id)
@ -290,6 +326,30 @@ class SendTemplateMessageJob < ApplicationJob
receivers_email_string, email_title, email_content = MessageTemplate::TeamLeft.get_email_message_content(receiver, organization, team) receivers_email_string, email_title, email_content = MessageTemplate::TeamLeft.get_email_message_content(receiver, organization, team)
Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content) Notice::Write::EmailCreateService.call(receivers_email_string, email_title, email_content)
end end
when 'CompetitionBegin'
user_id, competition_id = args[0], args[1]
user = User.find_by_id(user_id)
project = Project.find_by_sql("select *,title as name from competitions where id=#{competition_id}")
return unless user.present? && project.present?
receivers = User.where(id: user_id)
receivers_string, content, notification_url = MessageTemplate::CompetitionBegin.get_message_content(receivers, project.first)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user_id, competition_name: project.first&.name, identifier: project.first&.identifier})
when 'CompetitionReview'
user_id, competition_id = args[0], args[1]
user = User.find_by_id(user_id)
project = Project.find_by_sql("select *,title as name from competitions where id=#{competition_id}")
return unless user.present? && project.present?
receivers = User.where(id: user_id)
receivers_string, content, notification_url = MessageTemplate::CompetitionReview.get_message_content(receivers, project.first)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user_id, competition_name: project.first&.name, identifier: project.first&.identifier})
when 'CompetitionResult'
user_id, competition_id = args[0], args[1]
user = User.find_by_id(user_id)
project = Project.find_by_sql("select *,title as name from competitions where id=#{competition_id}")
return unless user.present? && project.present?
receivers = User.where(id: user_id)
receivers_string, content, notification_url = MessageTemplate::CompetitionResult.get_message_content(receivers, project.first)
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {user_id: user_id, competition_name: project.first&.name, identifier: project.first&.identifier})
end end
end end
end end

View File

@ -1,7 +1,7 @@
module CustomRegexp module CustomRegexp
PHONE = /1\d{10}/ PHONE = /1\d{10}/
EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/ EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ #只含有数字、字母、下划线不能以下划线开头和结尾
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/ LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/ PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
@ -11,5 +11,5 @@ module CustomRegexp
URL_REGEX = /\A(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?\z/i URL_REGEX = /\A(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?\z/i
REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
MD_REGEX = /^.+(\.[m|M][d|D])$/
end end

View File

@ -7,7 +7,7 @@ module Notice
config = Rails.application.config_for(:configuration).symbolize_keys! config = Rails.application.config_for(:configuration).symbolize_keys!
notice_config = config[:notice].symbolize_keys! notice_config = config[:notice].symbolize_keys!
raise 'notice config missing' if notice_config.blank? raise 'notice config missing' if notice_config.blank?
rescue => exception rescue => ex
raise ex if Rails.env.production? raise ex if Rails.env.production?
puts %Q{\033[33m [warning] gitea config or configuration.yml missing, puts %Q{\033[33m [warning] gitea config or configuration.yml missing,

21
app/libs/trace.rb Normal file
View File

@ -0,0 +1,21 @@
module Trace
class << self
def trace_config
trace_config = {}
begin
config = Rails.application.config_for(:configuration).symbolize_keys!
trace_config = config[:trace].symbolize_keys!
raise 'trace config missing' if trace_config.blank?
rescue => ex
raise ex if Rails.env.production?
puts %Q{\033[33m [warning] gitea config or configuration.yml missing,
please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m}
trace_config = {}
end
trace_config
end
end
end

View File

@ -5,10 +5,10 @@ class Ci::Repo < Ci::RemoteBase
has_one :perm, foreign_key: :perm_repo_uid has_one :perm, foreign_key: :perm_repo_uid
has_many :builds, foreign_key: :build_repo_id, dependent: :destroy has_many :builds, foreign_key: :build_repo_id, dependent: :destroy
def self.find_with_namespace(namespace_path, identifier) def self.find_with_namespace(namespace_path, identifier, user_login)
logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} " logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} "
user_login = user_login || namespace_path
user = Ci::User.find_by_user_login namespace_path user = Ci::User.find_by(user_login: user_login)
repo = Ci::Repo.where(repo_namespace: namespace_path, repo_name: identifier).first repo = Ci::Repo.where(repo_namespace: namespace_path, repo_name: identifier).first
[user, repo] [user, repo]

View File

@ -5,7 +5,7 @@ module Matchable
scope :with_project_category, ->(category_id) { where(project_category_id: category_id) unless category_id.blank? } scope :with_project_category, ->(category_id) { where(project_category_id: category_id) unless category_id.blank? }
scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? } scope :with_project_language, ->(language_id) { where(project_language_id: language_id) unless language_id.blank? }
scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) } scope :with_project_type, ->(project_type) { where(project_type: project_type) if Project.project_types.include?(project_type) }
scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "#{search.split(" ").join('|')}%") unless search.blank? } scope :by_name_or_identifier, ->(search) { where("name like :search or identifier LIKE :search", :search => "%#{search.split(" ").join('|')}%") unless search.blank? }
end end
end end

View File

@ -17,7 +17,7 @@
class ForkUser < ApplicationRecord class ForkUser < ApplicationRecord
belongs_to :project belongs_to :project
belongs_to :user belongs_to :owner, class_name: 'Owner', foreign_key: :user_id
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic

View File

@ -39,6 +39,6 @@ class Gitea::Pull < Gitea::Base
serialize :conflicted_files, Array serialize :conflicted_files, Array
belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_number, optional: true belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_id, optional: true
end end

View File

@ -75,7 +75,7 @@ class Issue < ApplicationRecord
scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)} scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)}
scope :closed, ->{where(status_id: 5)} scope :closed, ->{where(status_id: 5)}
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
after_update :change_versions_count after_save :change_versions_count, :send_update_message_to_notice_system
after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic
def incre_project_common def incre_project_common
@ -170,11 +170,25 @@ class Issue < ApplicationRecord
end end
def change_versions_count def change_versions_count
if self.version.present? && self.saved_change_to_status_id? if self.saved_change_to_fixed_version_id?
before_version = Version.find_by_id(self.fixed_version_id_before_last_save)
Rails.logger.info self.fixed_version_id_before_last_save
if before_version.present?
Rails.logger.info self.status_id
Rails.logger.info self.status_id_before_last_save
# 更改前状态为完成 或者 更改前后都为完成状态
if self.status_id_before_last_save == 5
percent = before_version.issues_count == 0 ? 0.0 : ((before_version.closed_issues_count - 1).to_f / before_version.issues_count)
before_version.update_attributes(closed_issues_count: (before_version.closed_issues_count - 1), percent: percent)
end
end
end
if self.version.present? && (self.saved_change_to_status_id? || self.saved_change_to_fixed_version_id?)
if self.status_id == 5 if self.status_id == 5
percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count + 1).to_f / self.version.issues_count) percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count + 1).to_f / self.version.issues_count)
self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count + 1), percent: percent) self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count + 1), percent: percent)
elsif self.status_id_before_last_save == 5 elsif self.status_id_before_last_save == 5 && !self.saved_change_to_fixed_version_id?
percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count - 1).to_f / self.version.issues_count) percent = self.version.issues_count == 0 ? 0.0 : ((self.version.closed_issues_count - 1).to_f / self.version.issues_count)
self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count - 1), percent: percent) self.version.update_attributes(closed_issues_count: (self.version.closed_issues_count - 1), percent: percent)
end end
@ -182,7 +196,11 @@ class Issue < ApplicationRecord
end end
def update_closed_issues_count_in_project! def update_closed_issues_count_in_project!
self.project.decrement!(:closed_issues_count) self.project.decrement!(:closed_issues_count) if self.status_id == 5
end
def send_update_message_to_notice_system
SendTemplateMessageJob.perform_later('IssueExpire', self.id) if Site.has_notice_menu? && self.due_date == Date.today + 1.days
end end
end end

View File

@ -6,7 +6,7 @@
# journalized_id :integer default("0"), not null # journalized_id :integer default("0"), not null
# journalized_type :string(30) default(""), not null # journalized_type :string(30) default(""), not null
# user_id :integer default("0"), not null # user_id :integer default("0"), not null
# notes :text(65535) # notes :text(4294967295)
# created_on :datetime not null # created_on :datetime not null
# private_notes :boolean default("0"), not null # private_notes :boolean default("0"), not null
# parent_id :integer # parent_id :integer

View File

@ -13,61 +13,72 @@
# #
class MessageTemplate < ApplicationRecord class MessageTemplate < ApplicationRecord
PLATFORM = 'GitLink'
def self.build_init_data def self.build_init_data
MessageTemplate::IssueAssignerExpire.destroy_all
MessageTemplate::IssueCreatorExpire.destroy_all
self.create(type: 'MessageTemplate::FollowedTip', sys_notice: '<b>{nickname}</b> 关注了你', notification_url: '{baseurl}/{login}') 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") 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: 'GitLink: {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: "#{PLATFORM}: {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}') 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") 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: 'GitLink: 疑修 {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: "#{PLATFORM}: 疑修 {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_expire.html")
self.create(type: 'MessageTemplate::IssueExpire', sys_notice: '疑修 <b>{title}</b> 已临近截止日期,请尽快处理', notification_url: '{baseurl}/{owner}/{identifier}/issues/{id}', email: email_html, email_title: "#{PLATFORM}: 疑修截止日期到达最后一天")
email_html = File.read("#{email_template_html_dir}/issue_deleted.html") 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: 'GitLink: 疑修 {title} 有状态变更', notification_url: '') self.create(type: 'MessageTemplate::IssueDeleted', sys_notice: '{nickname}已将疑修 <b>{title}</b> 删除', email: email_html, email_title: "#{PLATFORM}: 疑修 {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::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: '') 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") 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: 'GitLink: 你已加入 {organization} 组织') self.create(type: 'MessageTemplate::OrganizationJoined', sys_notice: '你已加入 <b>{organization}</b> 组织', notification_url: '{baseurl}/{login}', email: email_html, email_title: "#{PLATFORM}: 你已加入 {organization} 组织")
email_html = File.read("#{email_template_html_dir}/organization_left.html") 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: 'GitLink: 你已被移出 {organization} 组织') self.create(type: 'MessageTemplate::OrganizationLeft', sys_notice: '你已被移出 <b>{organization}</b> 组织', notification_url: '', email: email_html, email_title: "#{PLATFORM}: 你已被移出 {organization} 组织")
self.create(type: 'MessageTemplate::ProjectDeleted', sys_notice: '你关注的仓库{nickname}/{repository}已被删除', notification_url: '') 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::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}') self.create(type: 'MessageTemplate::ProjectForked', sys_notice: '<b>{nickname1}</b> 复刻了你管理的仓库 <b>{nickname2}/{repository}</b> 到 <b>{nickname1}/{repository}</b>', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_issue.html") 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: 'GitLink: {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: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 新建了一个疑修")
email_html = File.read("#{email_template_html_dir}/project_joined.html") 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: 'GitLink: 你已加入 {repository} 项目') self.create(type: 'MessageTemplate::ProjectJoined', sys_notice: '你已加入 <b>{repository}</b> 项目', notification_url: '{baseurl}/{owner}/{identifier}', email: email_html, email_title: "#{PLATFORM}: 你已加入 {repository} 项目")
email_html = File.read("#{email_template_html_dir}/project_left.html") 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: 'GitLink: 你已被移出 {repository} 项目') self.create(type: 'MessageTemplate::ProjectLeft', sys_notice: '你已被移出 <b>{repository}</b> 项目', notification_url: '', email: email_html, email_title: "#{PLATFORM}: 你已被移出 {repository} 项目")
email_html = File.read("#{email_template_html_dir}/project_member_joined.html") 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: 'GitLink: {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: "#{PLATFORM}: {nickname1} 已加入项目 {nickname2}/{repository}")
email_html = File.read("#{email_template_html_dir}/project_member_left.html") 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: 'GitLink: {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: "#{PLATFORM}: {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}') email_html = File.read("#{email_template_html_dir}/project_milestone.html")
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname}</b> 点赞了你管理的仓库', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::ProjectMilestone', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 创建了一个里程碑:<b>{name}</b>', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 新建了一个里程碑")
email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html")
self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 <b>{nickname}/{repository}</b> 仓库,里程碑 <b>{name}</b> 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: 仓库 {nickname}/{repository} 有里程碑已完成")
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname1}</b> 点赞了你管理的仓库 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/project_pull_request.html") 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: 'GitLink: {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: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求")
email_html = File.read("#{email_template_html_dir}/project_role.html") 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: 'GitLink: 在 {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: '#{PLATFORM}: 在 {nickname}/{repository} 项目你的账号有权限变更', notification_url: '{baseurl}/{owner}/{identifier}')
email_html = File.read("#{email_template_html_dir}/project_setting_changed.html") 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: 'GitLink: 您管理的仓库 {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: "#{PLATFORM}: 您管理的仓库 {nickname2}/{repository} 仓库设置已被更改")
self.create(type: 'MessageTemplate::ProjectTransfer', sys_notice: '你关注的仓库{nickname1}/{repository1}已被转移至{nickname2}/{repository2}', notification_url: '{baseurl}/{owner}/{identifier}') 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') 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") 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: 'GitLink: {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: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 指派给你一个合并请求")
self.create(type: 'MessageTemplate::PullRequestAtme', sys_notice: '<b>{nickname}</b> 在合并请求 <b>{title}</b> 中@我', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') 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") 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: 'GitLink: 合并请求 {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: "#{PLATFORM}: 合并请求 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/pull_request_closed.html") 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: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '') self.create(type: 'MessageTemplate::PullRequestClosed', sys_notice: '你提交的合并请求:{title} <b>被拒绝</b>', email: email_html, email_title: "#{PLATFORM}: 合并请求 {title} 有状态变更", notification_url: '')
self.create(type: 'MessageTemplate::PullRequestJournal', sys_notice: '{nickname}评论合并请求{title}<b>{notes}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') 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") 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: 'GitLink: 合并请求 {title} 有状态变更', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}') self.create(type: 'MessageTemplate::PullRequestMerged', sys_notice: '你提交的合并请求:{title} <b>已通过</b>', email: email_html, email_title: "#{PLATFORM}: 合并请求 {title} 有状态变更", notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}')
email_html = File.read("#{email_template_html_dir}/team_joined.html") email_html = File.read("#{email_template_html_dir}/team_joined.html")
self.create(type: 'MessageTemplate::TeamJoined', sys_notice: '你已被拉入组织 <b>{organization}</b> 的 <b>{team}</b> 团队,拥有<b>{role}</b>权限', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::TeamJoined', sys_notice: '你已被拉入组织 <b>{organization}</b> 的 <b>{team}</b> 团队,拥有<b>{role}</b>权限', email: email_html, email_title: "#{PLATFORM}: 在 {organization} 组织你的账号有权限变更", notification_url: '{baseurl}/{login}')
email_html = File.read("#{email_template_html_dir}/team_left.html") email_html = File.read("#{email_template_html_dir}/team_left.html")
self.create(type: 'MessageTemplate::TeamLeft', sys_notice: '你已被移出组织 <b>{organization}</b> 的 <b>{team}</b> 团队', email: email_html, email_title: 'GitLink: 在 {organization} 组织你的账号有权限变更', notification_url: '{baseurl}/{login}') self.create(type: 'MessageTemplate::TeamLeft', sys_notice: '你已被移出组织 <b>{organization}</b> 的 <b>{team}</b> 团队', email: email_html, email_title: "#{PLATFORM}: 在 {organization} 组织你的账号有权限变更", notification_url: '{baseurl}/{login}')
# 竞赛通知
self.create(type: 'MessageTemplate::CompetitionBegin', sys_notice: '你报名的竞赛 <b>{competition_name}</b> 已进入比赛进行阶段,可在此期间提交作品', notification_url: '{to_url}')
self.create(type: 'MessageTemplate::CompetitionResult', sys_notice: '你报名的竞赛 <b>{competition_name}</b> 已进入成绩公示阶段,可查看排行榜信息', notification_url: '{to_url}')
self.create(type: 'MessageTemplate::CompetitionReview', sys_notice: '你报名的竞赛 <b>{competition_name}</b> 距作品提交结束日期仅剩3天若尚未提交参赛作品请尽快提交', notification_url: '{to_url}')
end end
def self.sys_notice def self.sys_notice

View File

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 报名的竞赛进入比赛进行阶段
# 触发场景
# 赛队成员报名的竞赛已进入比赛进行阶段
# 通知文案格式
# 你报名的竞赛 xxx 已进入比赛进行阶段,可在此阶段提交作品
# 时间x分钟/小时/天/月前
# 通知文案示例
# 你报名的竞赛 代码审查大赛 已进入比赛进行阶段,可在此期间提交作品
# 时间3小时前
# 点击通知跳转页面
# 点击此通知将跳转到代码审查大赛详情页:
# http://117.50.100.12:8080/competitions/lgw7st/home
class MessageTemplate::CompetitionBegin < MessageTemplate
# MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
def self.get_message_content(receivers, competition)
return receivers_string(receivers), sys_notice.to_s.gsub('{competition_name}', competition&.name), notification_url.to_s.gsub('{to_url}', "/competitions/#{competition.identifier}/home")
# rescue
# return '', '', ''
end
end

View File

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 报名的竞赛进入成绩公示阶段
# 触发场景
# 赛队成员报名的竞赛已进入成绩公示阶段
# 通知文案格式
# 你报名的竞赛 xxx 已进入成绩公示阶段,可查看排行榜信息
# 时间x分钟/小时/天/月前
# 通知文案示例
# 你报名的竞赛 代码审查大赛 已进入成绩公示阶段,可查看排行榜信息
# 时间3小时前
# 点击通知跳转页面
# 点击此通知将跳转到代码审查大赛详情页:
# http://117.50.100.12:8080/competitions/lgw7st/home
class MessageTemplate::CompetitionResult < MessageTemplate
# MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
def self.get_message_content(receivers, competition)
return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.title), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home")
rescue
return '', '', ''
end
end

View File

@ -0,0 +1,35 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 报名的竞赛比赛结束时间临近
# 触发场景
# 赛队成员报名的竞赛阶段处于比赛进行中且距比赛结束日期仅剩3天
# 通知文案格式
# 你报名的竞赛 xxx 距作品提交结束日期仅剩3天若尚未提交参赛作品请尽快提交
# 时间x分钟/小时/天/月前
# 通知文案示例
# 你报名的竞赛 代码审查大赛 距作品提交结束日期仅剩3天若尚未提交参赛作品请尽快提交
# 时间3小时前
# 点击通知跳转页面
# 点击此通知将跳转到代码审查大赛详情页:
# http://117.50.100.12:8080/competitions/lgw7st/home
class MessageTemplate::CompetitionReview < MessageTemplate
# MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last)
def self.get_message_content(receivers, competition)
return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.title), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home")
rescue
return '', '', ''
end
end

View File

@ -53,6 +53,7 @@ class MessageTemplate::IssueAssigned < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', issue&.subject) content.gsub!('{title}', issue&.subject)
content.gsub!('{id}', issue&.id.to_s) content.gsub!('{id}', issue&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -359,6 +359,7 @@ class MessageTemplate::IssueChanged < MessageTemplate
else else
content.gsub!(/({ifduedate})(.*)({endduedate})/, '') content.gsub!(/({ifduedate})(.*)({endduedate})/, '')
end end
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -1,29 +1,3 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 我创建的疑修截止日期到达最后一天
class MessageTemplate::IssueCreatorExpire < MessageTemplate class MessageTemplate::IssueCreatorExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last) end
def self.get_message_content(receivers, issue)
project = issue&.project
owner = project&.owner
content = sys_notice.gsub('{title}', issue&.subject)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::IssueAssignerExpire.get_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -41,6 +41,7 @@ class MessageTemplate::IssueDeleted < MessageTemplate
content.gsub!('{login}', operator&.login) content.gsub!('{login}', operator&.login)
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', issue_title) content.gsub!('{title}', issue_title)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -0,0 +1,67 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 我创建或负责的疑修截止日期到达最后一天
class MessageTemplate::IssueExpire < MessageTemplate
# MessageTemplate::IssueCreatorExpire.get_message_content(User.where(login: 'yystopf'), Issue.last)
def self.get_message_content(receivers, issue)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["CreateOrAssign::IssueExpire"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["CreateOrAssign::IssueExpire"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
project = issue&.project
owner = project&.owner
content = sys_notice.gsub('{title}', issue&.subject)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', issue&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::IssueExpire.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, issue)
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.email_body["CreateOrAssign::IssueExpire"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["CreateOrAssign::IssueExpire"] : send_setting
return '', '', '' unless send_setting
project = issue&.project
owner = project&.owner
title = email_title
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{nickname}', owner&.real_name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{repository}', project&.name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', issue&.subject)
content.gsub!('{id}', issue&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::IssueExpire.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -41,6 +41,7 @@ class MessageTemplate::OrganizationJoined < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{login}', organization&.login) content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name) content.gsub!('{organization}', organization&.real_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -41,6 +41,7 @@ class MessageTemplate::OrganizationLeft < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{login}', organization&.login) content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name) content.gsub!('{organization}', organization&.real_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -43,6 +43,7 @@ class MessageTemplate::OrganizationRole < MessageTemplate
content.gsub!('{login}', organization&.login) content.gsub!('{login}', organization&.login)
content.gsub!('{organization}', organization&.real_name) content.gsub!('{organization}', organization&.real_name)
content.gsub!('{role}', role) content.gsub!('{role}', role)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -12,11 +12,21 @@
# email_title :string(255) # email_title :string(255)
# #
# TODO 我管理的仓库被复刻 # 我管理的仓库被复刻
class MessageTemplate::ProjectForked < MessageTemplate class MessageTemplate::ProjectForked < MessageTemplate
# MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf')) # MessageTemplate::ProjectForked.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers) def self.get_message_content(receivers, user, project)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::Forked"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::Forked"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
url = notification_url.gsub('{owner}', user&.login).gsub('{identifier}', project&.identifier)
return receivers_string(receivers), content, url return receivers_string(receivers), content, url
rescue => e rescue => e
Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}") Rails.logger.info("MessageTemplate::ProjectForked.get_message_content [ERROR] #{e}")

View File

@ -56,6 +56,7 @@ class MessageTemplate::ProjectIssue < MessageTemplate
content.gsub!('{identifier}', project&.identifier) content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', issue&.id.to_s) content.gsub!('{id}', issue&.id.to_s)
content.gsub!('{title}', issue&.subject) content.gsub!('{title}', issue&.subject)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -44,6 +44,7 @@ class MessageTemplate::ProjectJoined < MessageTemplate
content.gsub!('{identifier}', project&.identifier) content.gsub!('{identifier}', project&.identifier)
content.gsub!('{nickname}', project&.owner&.real_name) content.gsub!('{nickname}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name) content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -43,6 +43,7 @@ class MessageTemplate::ProjectLeft < MessageTemplate
content.gsub!('{identifier}', project&.identifier) content.gsub!('{identifier}', project&.identifier)
content.gsub!('{nickname}', project&.owner&.real_name) content.gsub!('{nickname}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name) content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -48,6 +48,7 @@ class MessageTemplate::ProjectMemberJoined < MessageTemplate
content.gsub!('{nickname1}', user&.real_name) content.gsub!('{nickname1}', user&.real_name)
content.gsub!('{nickname2}', project&.owner&.real_name) content.gsub!('{nickname2}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name) content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -48,6 +48,7 @@ class MessageTemplate::ProjectMemberLeft < MessageTemplate
content.gsub!('{nickname1}', user&.real_name) content.gsub!('{nickname1}', user&.real_name)
content.gsub!('{nickname2}', project&.owner&.real_name) content.gsub!('{nickname2}', project&.owner&.real_name)
content.gsub!('{repository}', project&.name) content.gsub!('{repository}', project&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -12,14 +12,61 @@
# email_title :string(255) # email_title :string(255)
# #
# TODO 我管理的仓库有新的里程碑 # 我管理的仓库有新的里程碑
class MessageTemplate::ProjectMilestone < MessageTemplate class MessageTemplate::ProjectMilestone < MessageTemplate
# MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf')) # MessageTemplate::ProjectMilestone.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers) def self.get_message_content(receivers, operator, milestone)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::Milestone"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::Milestone"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless receiver.user_template_message_setting.notification_body["ManageProject::Milestone"]
end
end
return '', '', '' if receivers.blank?
project = milestone&.project
owner = project&.owner
content = sys_notice.gsub('{nickname1}', operator&.real_name).gsub('{nickname2}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s)
return receivers_string(receivers), content, url return receivers_string(receivers), content, url
rescue => e rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}") Rails.logger.info("MessageTemplate::ProjectMilestone.get_message_content [ERROR] #{e}")
return '', '', '' return '', '', ''
end end
def self.get_email_message_content(receiver, operator, milestone)
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.email_body["ManageProject::Milestone"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["ManageProject::Milestone"] : send_setting
return '', '', '' unless send_setting
project = milestone&.project
owner = project&.owner
title = email_title
title.gsub!('{nickname1}', operator&.real_name)
title.gsub!('{nickname2}', owner&.real_name)
title.gsub!('{repository}', project&.name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{nickname1}', operator&.real_name)
content.gsub!('{nickname2}', owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', milestone&.id.to_s)
content.gsub!('{name}', milestone&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestone.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end end

View File

@ -0,0 +1,70 @@
# == Schema Information
#
# Table name: message_templates
#
# id :integer not null, primary key
# type :string(255)
# sys_notice :text(65535)
# email :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# notification_url :string(255)
# email_title :string(255)
#
# 我管理的仓库有里程碑完成
class MessageTemplate::ProjectMilestoneCompleted < MessageTemplate
# MessageTemplate::ProjectMilestoneCompleted.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers, milestone)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::MilestoneCompleted"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::MilestoneCompleted"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
project = milestone&.project
owner = project&.owner
content = sys_notice.gsub('{nickname}', owner&.real_name).gsub('{repository}', project&.name).gsub('{name}', milestone&.name)
url = notification_url.gsub('{owner}', owner&.login).gsub('{identifier}', project&.identifier).gsub('{id}', milestone&.id.to_s)
return receivers_string(receivers), content, url
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestoneCompleted.get_message_content [ERROR] #{e}")
return '', '', ''
end
def self.get_email_message_content(receiver, milestone)
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.email_body["ManageProject::MilestoneCompleted"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_email_body["ManageProject::MilestoneCompleted"] : send_setting
return '', '', '' unless send_setting
project = milestone&.project
owner = project&.owner
title = email_title
title.gsub!('{nickname}', owner&.real_name)
title.gsub!('{repository}', project&.name)
content = email
content.gsub!('{receiver}', receiver&.real_name)
content.gsub!('{baseurl}', base_url)
content.gsub!('{nickname}', owner&.real_name)
content.gsub!('{repository}', project&.name)
content.gsub!('{login}', owner&.login)
content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', milestone&.id.to_s)
content.gsub!('{name}', milestone&.name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content
else
return '', '', ''
end
rescue => e
Rails.logger.info("MessageTemplate::ProjectMilestoneCompleted.get_email_message_content [ERROR] #{e}")
return '', '', ''
end
end

View File

@ -12,11 +12,21 @@
# email_title :string(255) # email_title :string(255)
# #
# TODO 我管理的仓库被点赞 # 我管理的仓库被点赞
class MessageTemplate::ProjectPraised < MessageTemplate class MessageTemplate::ProjectPraised < MessageTemplate
# MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf')) # MessageTemplate::ProjectPraised.get_message_content(User.where(login: 'yystopf'))
def self.get_message_content(receivers) def self.get_message_content(receivers, user, project)
receivers.each do |receiver|
if receiver.user_template_message_setting.present?
send_setting = receiver.user_template_message_setting.notification_body["ManageProject::Praised"]
send_setting = send_setting.nil? ? UserTemplateMessageSetting.init_notification_body["ManageProject::Praised"] : send_setting
receivers = receivers.where.not(id: receiver.id) unless send_setting
end
end
return '', '', '' if receivers.blank?
content = sys_notice.gsub('{nickname1}', user&.real_name).gsub('{nickname2}', project&.owner&.real_name).gsub('{repository}', project&.name)
url = notification_url.gsub('{login}', user&.login)
return receivers_string(receivers), content, url return receivers_string(receivers), content, url
rescue => e rescue => e
Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}") Rails.logger.info("MessageTemplate::ProjectPraised.get_message_content [ERROR] #{e}")

View File

@ -56,6 +56,7 @@ class MessageTemplate::ProjectPullRequest < MessageTemplate
content.gsub!('{identifier}', project&.identifier) content.gsub!('{identifier}', project&.identifier)
content.gsub!('{id}', pull_request&.id.to_s) content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{title}', pull_request&.title) content.gsub!('{title}', pull_request&.title)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -46,6 +46,7 @@ class MessageTemplate::ProjectRole < MessageTemplate
content.gsub!('{identifier}', project&.identifier) content.gsub!('{identifier}', project&.identifier)
content.gsub!('{repository}', project&.name) content.gsub!('{repository}', project&.name)
content.gsub!('{role}', role) content.gsub!('{role}', role)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -300,6 +300,7 @@ class MessageTemplate::ProjectSettingChanged < MessageTemplate
else else
content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '') content.gsub!(/({ifnavbar})(.*)({endnavbar})/, '')
end end
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -53,6 +53,7 @@ class MessageTemplate::PullRequestAssigned < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title) content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s) content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -118,6 +118,7 @@ class MessageTemplate::PullRequestChanged < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title) content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s) content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
change_count = change_params.keys.size change_count = change_params.keys.size
# 合并请求审查成员修改 # 合并请求审查成员修改

View File

@ -51,6 +51,7 @@ class MessageTemplate::PullRequestClosed < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title) content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s) content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -51,6 +51,7 @@ class MessageTemplate::PullRequestMerged < MessageTemplate
content.gsub!('{baseurl}', base_url) content.gsub!('{baseurl}', base_url)
content.gsub!('{title}', pull_request&.title) content.gsub!('{title}', pull_request&.title)
content.gsub!('{id}', pull_request&.id.to_s) content.gsub!('{id}', pull_request&.id.to_s)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -45,6 +45,7 @@ class MessageTemplate::TeamJoined < MessageTemplate
content.gsub!('{organization}', organization&.real_name) content.gsub!('{organization}', organization&.real_name)
content.gsub!('{team}', team&.nickname) content.gsub!('{team}', team&.nickname)
content.gsub!('{role}', team&.authorize_name) content.gsub!('{role}', team&.authorize_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -45,6 +45,7 @@ class MessageTemplate::TeamLeft < MessageTemplate
content.gsub!('{organization}', organization&.real_name) content.gsub!('{organization}', organization&.real_name)
content.gsub!('{team}', team&.nickname) content.gsub!('{team}', team&.nickname)
content.gsub!('{role}', team&.authorize_name) content.gsub!('{role}', team&.authorize_name)
content.gsub!('{platform}', PLATFORM)
return receiver&.mail, title, content return receiver&.mail, title, content
else else

View File

@ -83,6 +83,10 @@ class Organization < Owner
after_save :reset_cache_data after_save :reset_cache_data
def gitea_token
team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user&.gitea_token
end
def reset_cache_data def reset_cache_data
Cache::V2::OwnerCommonService.new(self.id).reset Cache::V2::OwnerCommonService.new(self.id).reset
end end

View File

@ -119,6 +119,7 @@ class Project < ApplicationRecord
# has_many :user_grades, dependent: :destroy # has_many :user_grades, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy
has_one :project_score, dependent: :destroy has_one :project_score, dependent: :destroy
has_many :project_infos, :dependent => :destroy
has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy has_many :versions, -> { order("versions.created_on DESC, versions.name DESC") }, dependent: :destroy
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
@ -129,8 +130,8 @@ class Project < ApplicationRecord
has_many :has_pinned_users, through: :pinned_projects, source: :user has_many :has_pinned_users, through: :pinned_projects, source: :user
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
after_create :incre_user_statistic, :incre_platform_statistic after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members, :reset_cache_data after_save :check_project_members
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
before_destroy :decre_project_common, :decre_forked_from_project_count before_destroy :decre_project_common, :decre_forked_from_project_count
after_destroy :decre_user_statistic, :decre_platform_statistic after_destroy :decre_user_statistic, :decre_platform_statistic
scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
@ -154,7 +155,7 @@ class Project < ApplicationRecord
end end
def reset_cache_data def reset_cache_data
CacheAsyncResetJob.perform_later("project_common_service", self.id) CacheAsyncResetJob.set(wait: 5.seconds).perform_later("project_common_service", self.id)
if changes[:user_id].present? if changes[:user_id].present?
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first) CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first)
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last) CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last)
@ -167,6 +168,14 @@ class Project < ApplicationRecord
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}) CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1})
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}) CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1})
end end
if changes[:is_public].present?
if changes[:is_public][0] && !changes[:is_public][1]
CacheAsyncClearJob.perform_later('project_rank_service', self.id)
end
if !changes[:is_public][0] && changes[:is_public][1]
$redis_cache.srem("v2-project-rank-deleted", self.id)
end
end
end end
def decre_project_common def decre_project_common

View File

@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: project_infos
#
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class ProjectInfo < ActiveRecord::Base
belongs_to :project
belongs_to :user
validates_presence_of :project_id, :user_id
validates_uniqueness_of :project_id, :scope => :user_id
end

View File

@ -16,8 +16,8 @@
class ProjectUnit < ApplicationRecord class ProjectUnit < ApplicationRecord
belongs_to :project belongs_to :project
enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7} enum unit_type: {code: 1, issues: 2, pulls: 3, devops: 4, versions: 5, resources: 6, gantt: 7, sonar: 8}
validates :unit_type, uniqueness: { scope: :project_id} validates :unit_type, uniqueness: { scope: :project_id}
def self.init_types(project_id, project_type='common') def self.init_types(project_id, project_type='common')

View File

@ -3,8 +3,8 @@
# Table name: pull_requests # Table name: pull_requests
# #
# id :integer not null, primary key # id :integer not null, primary key
# pull_request_id :integer # gitea_id :integer
# gpid :integer # gitea_number :integer
# user_id :integer # user_id :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
@ -12,7 +12,7 @@
# project_id :integer # project_id :integer
# title :string(255) # title :string(255)
# milestone :integer # milestone :integer
# body :text(65535) # body :text(4294967295)
# head :string(255) # head :string(255)
# base :string(255) # base :string(255)
# issue_id :integer # issue_id :integer
@ -37,8 +37,8 @@ class PullRequest < ApplicationRecord
has_many :pull_request_tags, foreign_key: :pull_request_id has_many :pull_request_tags, foreign_key: :pull_request_id
has_many :project_trends, as: :trend, dependent: :destroy has_many :project_trends, as: :trend, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy
has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_number, class_name: 'Gitea::Pull' has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_id, class_name: 'Gitea::Pull'
scope :merged_and_closed, ->{where.not(status: 0)} scope :merged_and_closed, ->{where.not(status: 0)}
scope :opening, -> {where(status: 0)} scope :opening, -> {where(status: 0)}

View File

@ -29,6 +29,11 @@ class Team < ApplicationRecord
has_many :team_units, dependent: :destroy has_many :team_units, dependent: :destroy
has_many :team_users, dependent: :destroy has_many :team_users, dependent: :destroy
scope :like, lambda { |keywords|
sql = "teams.nickname LIKE :search OR teams.name LIKE :search"
where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
}
validates :name, uniqueness: {scope: :organization_id} validates :name, uniqueness: {scope: :organization_id}
enum authorize: {read: 1, write: 2, admin: 3, owner: 4} enum authorize: {read: 1, write: 2, admin: 3, owner: 4}

View File

@ -29,7 +29,7 @@ class TeamUser < ApplicationRecord
before_destroy :remove_project_member before_destroy :remove_project_member
def self.build(organization_id, user_id, team_id) def self.build(organization_id, user_id, team_id)
self.create!(organization_id: organization_id, user_id: user_id, team_id: team_id) self.find_or_create_by!(organization_id: organization_id, user_id: user_id, team_id: team_id)
end end
def remove_project_member def remove_project_member

View File

@ -22,6 +22,7 @@ class TemplateMessageSetting < ApplicationRecord
end end
def self.build_init_data def self.build_init_data
TemplateMessageSetting.destroy_all
TemplateMessageSetting::CreateOrAssign.build_init_data TemplateMessageSetting::CreateOrAssign.build_init_data
TemplateMessageSetting::ManageProject.build_init_data TemplateMessageSetting::ManageProject.build_init_data
TemplateMessageSetting::Normal.build_init_data TemplateMessageSetting::Normal.build_init_data

View File

@ -27,5 +27,6 @@ class TemplateMessageSetting::CreateOrAssign < TemplateMessageSetting
def self.build_init_data def self.build_init_data
self.find_or_create_by(name: "疑修状态变更", key: "IssueChanged") self.find_or_create_by(name: "疑修状态变更", key: "IssueChanged")
self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged") self.find_or_create_by(name: "合并请求状态变更", key: "PullRequestChanged")
self.find_or_create_by(name: "疑修截止日期到达最后一天", key: "IssueExpire", notification_disabled: false)
end end
end end

View File

@ -29,5 +29,9 @@ class TemplateMessageSetting::ManageProject < TemplateMessageSetting
self.find_or_create_by(name: "有新的合并请求", key: "PullRequest") self.find_or_create_by(name: "有新的合并请求", key: "PullRequest")
self.find_or_create_by(name: "有成员变动", key: "Member") self.find_or_create_by(name: "有成员变动", key: "Member")
self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged") self.find_or_create_by(name: "仓库设置被更改", key: "SettingChanged")
self.find_or_create_by(name: "被点赞", key: "Praised", notification_disabled: false, email_disabled: true)
self.find_or_create_by(name: "被fork", key: "Forked", notification_disabled: false, email_disabled: true)
self.find_or_create_by(name: "有新的里程碑", key: "Milestone", notification_disabled: false)
self.find_or_create_by(name: "有里程碑已完成", key: "MilestoneCompleted", notification_disabled: false)
end end
end end

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