class AccountsController < ApplicationController before_action :require_login, only: [:login_check, :simple_update] include ApplicationHelper #skip_before_action :check_account, :only => [:logout] def simple_update 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+/, "")) Register::RemoteForm.new(simple_update_params.merge(user_id: current_user.id)).validate! ActiveRecord::Base.transaction do result = auto_update(current_user, simple_update_params) if result[:message].blank? UserAction.create(:action_id => current_user.id, :action_type => "sync_educoder_user", :user_id => current_user.id, :ip => request.remote_ip) if params[:platform] == "educoder" render_ok else render_error(result[:message]) end end end def index render json: session end # 其他平台同步注册的用户 def remote_register Register::RemoteForm.new(remote_register_params).validate! username = params[:username]&.gsub(/\s+/, "") tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username) email = params[:email]&.gsub(/\s+/, "") password = params[:password] platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") ActiveRecord::Base.transaction do result = autologin_register(username, email, password, platform) if result[:message].blank? render_ok({user: result[:user]}) else render_error(result[:message]) end end rescue Exception => e uid_logger_error(e.message) tip_exception(-1, e.message) end # 其他平台修改用户的信息,这边同步修改 def remote_update ActiveRecord::Base.transaction do user_params = params[:user_params] user_extension_params = params[:user_extension_params] u = User.find_by(login: params[:old_user_login]) user_mail = u.try(:mail) if u.present? ue = u.user_extension u.login = user_params["login"] if user_params["login"] u.mail = user_params["mail"] if user_params["mail"] u.lastname = user_params["lastname"] if user_params["lastname"] ue.gender = user_extension_params["gender"] ue.school_id = user_extension_params["school_id"] ue.location = user_extension_params["location"] ue.location_city = user_extension_params["location_city"] ue.identity = user_extension_params["identity"] ue.technical_title = user_extension_params["technical_title"] ue.student_id = user_extension_params["student_id"] ue.description = user_extension_params["description"] ue.save! u.save! sync_params = {} if (user_params["mail"] && user_params["mail"] != user_mail) sync_params = sync_params.merge(email: user_params["mail"]) end if sync_params.present? interactor = Gitea::User::UpdateInteractor.call(u.login, sync_params) if interactor.success? render_ok else render_error(interactor.error) end end end end rescue Exception => e uid_logger_error(e.message) tip_exception(-1, e.message) end # 其他平台同步登录 def remote_login @user = User.try_to_login(params[:login], params[:password]) if @user successful_authentication(@user) render_ok({user: {id: @user.id, token: @user.gitea_token}}) else render_error("用户不存在") end end #修改密码 def remote_password @user = User.find_by(login: params[:login]) return render_error("未找到相关用户!") if @user.blank? sync_params = { password: params[:password].to_s, email: @user.mail, login_name: @user.login, source_id: 0 } interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) if interactor.success? @user.update_attribute(:password, params[:password]) render_ok else render_error(interactor.error) end end # 用户注册 # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 # params[:login] 邮箱或者手机号 # params[:namespace] 登录名 # params[:code] 验证码 # code_type 1:注册手机验证码 8:邮箱注册验证码 # 本地forge注册入口需要重新更改逻辑 def register # type只可能是1或者8 user = nil begin Register::Form.new(register_params).validate! user = Users::RegisterService.call(register_params) user.mail = "#{user.login}@example.org" if user.mail.blank? 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 result = Gitea::User::GenerateTokenService.call(user.login, password) user.gitea_token = result['sha1'] user.gitea_uid = gitea_user[:body]['id'] if user.save! UserExtension.create!(user_id: user.id) # 绑定授权账号 if ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s) && session[:unionid].present? "OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: user, uid: session[:unionid]) end successful_authentication(user) render_ok end elsif interactor.result[:message].to_s.include?("user already exists") UserAction.create(:action_id => 2, :action_type => "register_error", :user_id => user.try(:id).to_i, :ip => "code: #{register_params[:code]}; login: #{register_params[:login]}; namespace: #{register_params[:namespace]}; password: #{password};") normal_status(-1, "用户已注册,请勿连续操作。") else tip_exception(-1, interactor.result[:message]) end rescue Register::BaseForm::EmailError => e render_result(-2, e.message) rescue Register::BaseForm::LoginError => e render_result(-3, e.message) rescue Register::BaseForm::PhoneError => e render_result(-4, e.message) rescue Register::BaseForm::PasswordFormatError => e render_result(-5, e.message) rescue Register::BaseForm::PasswordConfirmationError => e render_result(-7, e.message) rescue Register::BaseForm::VerifiCodeError => e render_result(-6, e.message) rescue Exception => e if user.present? && !e.message.to_s.include?("user already exists") # Gitea::User::DeleteService.call(user.login) # user.destroy end Rails.logger.error("##:register error--#{user.try(:id)},message:#{e.message}") UserAction.create(:action_id => 1, :action_type => "register_error", :user_id => user.try(:id).to_i, :ip => "code: #{register_params[:code]}; login: #{register_params[:login]}; namespace: #{register_params[:namespace]}; password: #{password};") logger_error(e) tip_exception(-1, "注册失败") end end # 用户登录 def login Users::LoginForm.new(login_params).validate! @user = User.try_to_login(params[:login], params[:password]) return normal_status(-2, "错误的账号或密码") if @user.blank? # user is already in local database return normal_status(-2, "违反平台使用规范,账号已被锁定") if @user.locked? login_control = LimitForbidControl::UserLogin.new(@user) return normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? password_ok = @user.check_password?(params[:password].to_s) unless password_ok if login_control.remain_times-1 == 0 normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") else normal_status(-2, "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会") end login_control.increment! return end LimitForbidControl::UserLogin.new(@user).clear successful_authentication(@user) sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 # session[:user_id] = @user.id end def change_password return render_error("两次输入的密码不一致") if params[:password].to_s != params[:new_password_repeat].to_s @user = User.find_by(login: params[:login]) return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691 return render_error("未找到相关用户!") if @user.blank? return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) sync_params = { password: params[:password].to_s, email: @user.mail, login_name: @user.name, source_id: 0 } interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) if interactor.success? @user.update_attribute(:password, params[:password]) render_ok else render_error(interactor.error) end end # 忘记密码 def reset_password begin Accounts::ResetPasswordForm.new(reset_password_params).validate! user = find_user return render_error('未找到相关账号') if user.blank? user = Accounts::ResetPasswordService.call(user, reset_password_params) LimitForbidControl::UserLogin.new(user).clear if user.save! render_ok rescue Register::BaseForm::EmailError => e render_result(-2, e.message) rescue Register::BaseForm::PhoneError => e render_result(-4, e.message) rescue Register::BaseForm::PasswordFormatError => e render_result(-5, e.message) rescue Register::BaseForm::PasswordConfirmationError => e render_result(-7, e.message) rescue Register::BaseForm::VerifiCodeError => e render_result(-6, e.message) rescue ActiveRecord::Rollback => e render_result(-1, "服务器异常") rescue Exception => e uid_logger_error(e.message) tip_exception(e.message) end end def successful_authentication(user) uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") # Valid user self.logged_user = user # generate a key and set cookie if autologin set_autologin_cookie(user) 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) session[:"#{default_yun_session}"] = user.id Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") # 注册完成后有一天的试用申请(先去掉) # UserDayCertification.create(user_id: user.id, status: 1) end def set_autologin_cookie(user) token = Token.get_or_create_permanent_login_token(user, "autologin") # sync_user_token_to_trustie(user.login, token.value) cookie_options = { :value => token.value, :expires => 1.month.from_now, :path => '/', :secure => false, :httponly => true } if edu_setting('cookie_domain').present? cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) end cookies[autologin_cookie_name] = cookie_options cookies.signed[:user_id] ||= user.id logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") end def logout Rails.logger.info("########___logout_current_user____________########{current_user.try(:id)}") UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) logout_user render :json => {status: 1, message: "退出成功!"} end # 检验邮箱是否已被注册及邮箱或者手机号是否合法 # 参数type为事件类型 1:注册;2:忘记密码;3:绑定 def valid_email_and_phone check_mail_and_phone_valid(params[:login], params[:type]) end # 发送验证码 # params[:login] 手机号或者邮箱号 # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效 def get_verification_code code = %W(0 1 2 3 4 5 6 7 8 9) value = params[:login] type = params[:type].strip.to_i login_type = phone_mail_type(value) send_type = verify_type(login_type, type) verification_code = code.sample(6).join status, message = InfoRiskControlService.call(value, request.remote_ip) tip_exception(420, message) if status == 0 sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") tip_exception(501, "请求不合理") if sign != params[:smscode] logger.info "########### 验证码:#{verification_code}" logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") # 记录验证码 check_verification_code(verification_code, send_type, value) render_ok end # check user's login or email or phone is used # params[:value] 手机号或者邮箱号或者登录名 # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) def check Register::CheckColumnsForm.new(check_params).validate! render_ok end def login_check Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate! render_ok end def check_keywords text = params[:text].to_s.each_char.select { |c| c.bytes.first < 240 }.join('') data = ! ReversedKeyword.check_exists?(text) result = { status: 0, data: data, message: data ? "" : "无法使用以下关键词:#{text},请重新命名" } render_ok(result) end private # type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 # login_type 1:手机类型 2:邮箱类型 def verify_type login_type, type case type when 1 login_type == 1 ? 1 : 8 when 2 login_type == 1 ? 2 : 3 when 3 login_type == 1 ? 4 : tip_exception('请填写正确的手机号') when 4 login_type == 1 ? tip_exception('请填写正确的邮箱') : 5 when 5 login_type == 1 ? 9 : tip_exception('请填写正确的手机号') end end def generate_login(login) type = phone_mail_type(login.strip) 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 login_params params.require(:account).permit(:login, :password) end def check_params params.permit(:type, :value) end def register_params params.permit(:login, :namespace, :password, :password_confirmation, :code, :type) end def reset_password_params params.permit(:login, :password, :password_confirmation, :code) end def find_user phone_or_mail = strip(reset_password_params[:login]) User.where("phone = :search OR mail = :search", search: phone_or_mail).last end def remote_register_params params.permit(:username, :email, :password, :platform) end def simple_update_params params.permit(:username, :email, :password, :platform) end end