add: new update user info simple and sync gitea

This commit is contained in:
yystopf 2022-05-24 10:59:52 +08:00
parent b0092487e6
commit c27cc063e6
4 changed files with 428 additions and 379 deletions

View File

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

@ -27,4 +27,32 @@ module RegisterHelper
result result
end 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

@ -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

@ -203,6 +203,7 @@ Rails.application.routes.draw do
post :remote_password post :remote_password
post :change_password post :change_password
post :check post :check
post :simple_update
end end
end end