From 8e7d831cff817bfc02ab1007bcfc3a76b0bcf977 Mon Sep 17 00:00:00 2001 From: xiaoxiaoqiong Date: Thu, 3 Mar 2022 16:22:35 +0800 Subject: [PATCH] =?UTF-8?q?cookie=20token=E7=81=B5=E6=B4=BB=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/accounts_controller.rb | 698 +++++++++++------------ app/controllers/concerns/login_helper.rb | 6 +- app/controllers/users_controller.rb | 520 ++++++++--------- 3 files changed, 614 insertions(+), 610 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 889b7ccf..8df61ee2 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,349 +1,349 @@ -class AccountsController < ApplicationController - - #skip_before_action :check_account, :only => [:logout] - - def index - render json: session - end - - # 其他平台同步注册的用户 - def remote_register - username = params[:username]&.gsub(/\s+/, "") - email = params[:email]&.gsub(/\s+/, "") - phone = params[:phone]&.gsub(/\s+/, "") - password = params[:password] - platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") - - ActiveRecord::Base.transaction do - return render_error("该手机号已注册") if phone.present? && User.where(phone: phone).exists? - result = autologin_register(username, email, password, platform, phone) - if result[:message].blank? - PlatformStatistic.data.increment!(:users_count) - 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 - } - - 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[:code] 验证码 - # code_type 1:注册手机验证码 8:邮箱注册验证码 - # 本地forge注册入口 - def register - begin - # 查询验证码是否正确;type只可能是1或者8 - type = phone_mail_type(params[:login].strip) - # code = params[:code].strip - - if type == 1 - uid_logger("start register by phone: type is #{type}") - pre = 'p' - email = nil - phone = params[:login] - # verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last - # TODO: 暂时限定邮箱注册 - return normal_status(-1, '只支持邮箱注册') - else - uid_logger("start register by email: type is #{type}") - pre = 'm' - email = params[:login] - phone = nil - return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login]) - return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL - # verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last - end - # uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") - # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) - # todo 上线前请删除万能验证码"513231" - return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD - - code = generate_identifier User, 8, pre - login = pre + code - @user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User") - @user.password = params[:password] - # 现在因为是验证码,所以在注册的时候就可以激活 - @user.activate - # 必须要用save操作,密码的保存是在users中 - - interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]}) - if interactor.success? - gitea_user = interactor.result - result = Gitea::User::GenerateTokenService.new(login, params[:password]).call - @user.gitea_token = result['sha1'] - @user.gitea_uid = gitea_user[:body]['id'] - if @user.save! - UserExtension.create!(user_id: @user.id) - successful_authentication(@user) - normal_status("注册成功") - end - else - tip_exception(-1, interactor.error) - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(-1, e.message) - end - end - - # 用户登录 - def login - @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 - - successful_authentication(@user) - sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 - - # session[:user_id] = @user.id - end - - # 忘记密码 - def reset_password - begin - code = params[:code] - login_type = phone_mail_type(params[:login].strip) - # 获取验证码 - if login_type == 1 - phone = params[:login] - verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last - user = User.find_by_phone(phone) - else - email = params[:login] - verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last - user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs - end - return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip - return normal_status(-2, "验证码已失效") if !verifi_code&.effective? - return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD - - user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] - ActiveRecord::Base.transaction do - user.save! - LimitForbidControl::UserLogin.new(user).clear - end - sucess_status - 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_cookie_name) - 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 - - sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") - tip_exception(501, "请求不合理") if sign != params[:smscode] - - logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") - - # 记录验证码 - check_verification_code(verification_code, send_type, value) - sucess_status - end - - # 1 手机类型;0 邮箱类型 - # 注意新版的login是自动名生成的 - def phone_mail_type value - value =~ /^1\d{10}$/ ? 1 : 0 - 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 - -end +class AccountsController < ApplicationController + + #skip_before_action :check_account, :only => [:logout] + + def index + render json: session + end + + # 其他平台同步注册的用户 + def remote_register + username = params[:username]&.gsub(/\s+/, "") + email = params[:email]&.gsub(/\s+/, "") + phone = params[:phone]&.gsub(/\s+/, "") + password = params[:password] + platform = (params[:platform] || 'forge')&.gsub(/\s+/, "") + + ActiveRecord::Base.transaction do + return render_error("该手机号已注册") if phone.present? && User.where(phone: phone).exists? + result = autologin_register(username, email, password, platform, phone) + if result[:message].blank? + PlatformStatistic.data.increment!(:users_count) + 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 + } + + 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[:code] 验证码 + # code_type 1:注册手机验证码 8:邮箱注册验证码 + # 本地forge注册入口 + def register + begin + # 查询验证码是否正确;type只可能是1或者8 + type = phone_mail_type(params[:login].strip) + # code = params[:code].strip + + if type == 1 + uid_logger("start register by phone: type is #{type}") + pre = 'p' + email = nil + phone = params[:login] + # verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last + # TODO: 暂时限定邮箱注册 + return normal_status(-1, '只支持邮箱注册') + else + uid_logger("start register by email: type is #{type}") + pre = 'm' + email = params[:login] + phone = nil + return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login]) + return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL + # verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last + end + # uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") + # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) + # todo 上线前请删除万能验证码"513231" + return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD + + code = generate_identifier User, 8, pre + login = pre + code + @user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User") + @user.password = params[:password] + # 现在因为是验证码,所以在注册的时候就可以激活 + @user.activate + # 必须要用save操作,密码的保存是在users中 + + interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]}) + if interactor.success? + gitea_user = interactor.result + result = Gitea::User::GenerateTokenService.new(login, params[:password]).call + @user.gitea_token = result['sha1'] + @user.gitea_uid = gitea_user[:body]['id'] + if @user.save! + UserExtension.create!(user_id: @user.id) + successful_authentication(@user) + normal_status("注册成功") + end + else + tip_exception(-1, interactor.error) + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(-1, e.message) + end + end + + # 用户登录 + def login + @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 + + successful_authentication(@user) + sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 + + # session[:user_id] = @user.id + end + + # 忘记密码 + def reset_password + begin + code = params[:code] + login_type = phone_mail_type(params[:login].strip) + # 获取验证码 + if login_type == 1 + phone = params[:login] + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last + user = User.find_by_phone(phone) + else + email = params[:login] + verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last + user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs + end + return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip + return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD + + user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] + ActiveRecord::Base.transaction do + user.save! + LimitForbidControl::UserLogin.new(user).clear + end + sucess_status + 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_action) + 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 + + sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") + tip_exception(501, "请求不合理") if sign != params[:smscode] + + logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") + + # 记录验证码 + check_verification_code(verification_code, send_type, value) + sucess_status + end + + # 1 手机类型;0 邮箱类型 + # 注意新版的login是自动名生成的 + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + 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 + +end diff --git a/app/controllers/concerns/login_helper.rb b/app/controllers/concerns/login_helper.rb index 12cf3bb6..c0ad5d5d 100644 --- a/app/controllers/concerns/login_helper.rb +++ b/app/controllers/concerns/login_helper.rb @@ -9,9 +9,13 @@ module LoginHelper edu_setting('autologin_cookie_name').presence || 'autologin_forge_military' end + def autologin_action + EduSetting.get('autologin_action').presence || 'autologin' + end + def set_autologin_cookie(user) Rails.logger.info("set_cookie_user_id is=======> #{user.id}") - token = Token.get_or_create_permanent_login_token(user, autologin_cookie_name) + token = Token.get_or_create_permanent_login_token(user, autologin_action) cookie_options = { :value => token.value, :expires => 1.month.from_now, diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6b6b8fcb..8c49b0fc 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,260 +1,260 @@ -class UsersController < ApplicationController - include ApplicationHelper - include Ci::DbConnectable - - before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users] - before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users] - before_action :require_login, only: %i[me list] - before_action :connect_to_ci_db, only: [:get_user_info] - skip_before_action :check_sign, only: [:attachment_show] - - def connect_to_ci_db(options={}) - if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?) - return - end - if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE - connect_to_trustie_ci_database(options) - else - connect_to_ci_database(options) - end - end - - def list - scope = User.active.recent.like(params[:search]).includes(:user_extension) - @total_count = scope.size - @users = paginate(scope) - end - - def show - #待办事项,现在未做 - @undo_events = 0 - #用户的组织数量 - # @user_composes_count = @user.composes.size - @user_composes_count = 0 - @user_org_count = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)).size + @user.organizations.with_visibility("privacy").joins(:organization_users).where(organization_users: {user_id: current_user.id}).size : @user.organizations.with_visibility("common").size - user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? @user.projects : @user.projects.visible - @projects_common_count = user_projects.common.size - @projects_mirrior_count = user_projects.mirror.size - @projects_sync_mirrior_count = user_projects.sync_mirror.size - end - - def watch_users - watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc") - if params[:search].present? - search_user_ids = User.where(id: watchers.pluck(:watchable_id)).like(params[:search]).pluck(:id) - watchers = watchers.where(watchable_id: search_user_ids) - end - @watchers_count = watchers.size - @watchers = paginate(watchers) - end - - def fan_users - watchers = @user.watchers.includes(:user).order("watchers.created_at desc") - watchers = watchers.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present? - - @watchers_count = watchers.size - @watchers = paginate(watchers) - end - - def update - @user = User.find params[:id] - @user.update!(user_params) - render_ok - end - - def me - @user = current_user - end - - # 贴吧获取用户信接口 - def get_user_info - begin - @user = current_user - # TODO 等消息上线再打开注释 - #@tidding_count = unviewed_tiddings(current_user) if current_user.present? - rescue Exception => e - uid_logger_error(e.message) - missing_template - end - - end - - def attachment_show - file_name = params[:file_name] - path = params[:path] || file_storage_directory - send_file "#{path}/#{file_name}", :filename => "#{file_name}", - :type => 'game', - :disposition => 'attachment' #inline can open in browser - end - - def html_show - @contents = File.read("#{params[:path]}") - respond_to do |format| - format.html {render :layout => false} - end - end - - # Redo: 消息总数缓存 - def get_navigation_info - # @old_domain = edu_setting('old_edu_host') - # @user = current_user - # # 新消息数 - # @new_message = @user.tidings.where("created_at > '#{@user.click_time}'").count > 0 || @user.private_messages.where("created_at > '#{@user.click_time}'").count > 0 - # - # @user_url = "/users/#{@user.login}" - # @career = Career.where(status: true).order("created_at asc").pluck(:id, :name) - # @auth = User.current.ec_school.present? ? "#{@old_domain}/ecs/department?school_id=#{User.current.ec_school}" : nil - end - - # 用户回复功能 - def reply_message - message = JournalsForMessage.new(reply_message_params) - message.user_id = current_user.id - message.save! - - render_ok(id: message.id) - end - - # 搜索用户具有管理员角色的项目 - def search_user_projects - projects = Project.where.not(status: 9) - - projects = projects.joins(members: :member_roles).where(member_roles: { role_id: 3 }) - projects = projects.where(members: { user_id: current_user.id }) - - search = params[:search].to_s.strip - projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present? - - @projects = projects.select(:id, :name) - end - - #TODO 个人主页信息,forge上弃用-hs, 0602 - def homepage_info - #待办事项,现在未做 - @undo_events = 10 - #用户的组织数量 - # @user_composes_count = @user.composes.size - @user_composes_count = 10 - end - - def brief_introduction - content = params[:content].to_s.strip - - current_user.user_extension.update!(brief_introduction: content) - - render_ok - end - - def attendance - attendance = Users::AttendanceService.call(current_user) - render_ok(grade: current_user.grade, next_gold: attendance.next_gold) - rescue Users::AttendanceService::Error => ex - render_error(ex.message) - end - - # 其他平台登录后,必须将token同步到forge平台,实现sso登录功能 - def sync_token - return render_error('未找相关用户!') unless @user - token = Token.get_or_create_permanent_login_token(@user, autologin_cookie_name) - token.update_column(:value, params[:token]) - render_ok - end - - def trustie_related_projects - projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc") - projects_json = [] - domain_url = EduSetting.get('host_name') + '/projects' - if projects.present? - projects.each do |p| - project_url = "/#{p.owner.login}/#{p.identifier}" - pj = { - id: p.id, - name: p.name, - is_public: p.is_public, - updated_on: p.updated_on.strftime("%Y-%m-%d"), - status: p.status, - is_member: p.member?(current_user.try(:id)), - owner: { - name: p.owner.try(:show_real_name), - login: p.owner.login - }, - members_count: p&.members.size, - issues_count: p.issues_count - p.pull_requests_count, - commits_count: p&.project_score&.changeset_num.to_i, - http_url: domain_url + project_url, - http_collaborator_url: domain_url + project_url + "/setting/collaborator", - http_issues_url: domain_url + project_url + "/issues", - http_commits_url: domain_url + project_url + "/commits", - project_score: p&.project_score.present? ? p&.project_score&.as_json(:except=>[:created_at, :updated_at]).merge!(commit_time: format_time(p&.project_score&.commit_time)) : {} - } - projects_json.push(pj) - end - end - Rails.logger.info("==========projects_json========+########{projects_json}") - render json: { projects: projects_json.present? ? projects_json : {} } - end - - def trustie_projects - user_id = User.select(:id, :login).where(login: params[:login])&.first&.id - projects = Project.visible - - projects = projects.joins(:members).where(members: { user_id: user_id }) - - search = params[:search].to_s.strip - projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present? - - projects = projects.select(:id, :name).limit(10).as_json - render json: { projects: projects } - end - - def projects - is_current_admin_user = User.current.logged? && (current_user&.admin? || current_user.id == @user.id) - scope = Projects::ListMyQuery.call(params, @user,is_current_admin_user) - @total_count = scope.size - @projects = paginate(scope) - end - - # TODO 其他平台登录时同步修改gitea平台对应用户的密码 - # 该方法主要用于:别的平台初次部署对接forge平台,同步用户后,gitea平台对应的用户密码与forge平台用户密码不一致是问题 - def sync_gitea_pwd - return render_error("未找到相关的用户") if @user.blank? - - flag = sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) - flag ? render_ok : render_error('同步失败!') - end - - # TODO - # 同步trusite平台用户的salt信息,只需同步一次,同步完成后,该方法可以删除 - def sync_salt - user = User.find_by_login params[:login] - return if user.blank? - user.update_column(:salt, params[:salt]) - render_ok - end - - private - def load_user - @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) - end - - def user_params - params.require(:user).permit(:nickname, :lastname, :show_realname,:login,:mail, - user_extension_attributes: [ - :gender, :location, :location_city, - :occupation, :technical_title, - :school_id, :department_id,:identity, :student_id, :description] - ) - end - - def reply_message_params - normal_status(-1, "参数不对") if params[:journals_for_message][:jour_type].nil? || params[:journals_for_message][:jour_id].nil? || - params[:journals_for_message][:notes].nil? || params[:journals_for_message][:reply_id].nil? - params.require(:journals_for_message).permit(:jour_type, :jour_id, :notes, :m_parent_id, :reply_id) - end - - def check_user_exist - return if @user.present? - render_not_found - end - -end +class UsersController < ApplicationController + include ApplicationHelper + include Ci::DbConnectable + + before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users] + before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users] + before_action :require_login, only: %i[me list] + before_action :connect_to_ci_db, only: [:get_user_info] + skip_before_action :check_sign, only: [:attachment_show] + + def connect_to_ci_db(options={}) + if !(current_user && !current_user.is_a?(AnonymousUser) && current_user.devops_certification?) + return + end + if current_user.ci_cloud_account.server_type == Ci::CloudAccount::SERVER_TYPE_TRUSTIE + connect_to_trustie_ci_database(options) + else + connect_to_ci_database(options) + end + end + + def list + scope = User.active.recent.like(params[:search]).includes(:user_extension) + @total_count = scope.size + @users = paginate(scope) + end + + def show + #待办事项,现在未做 + @undo_events = 0 + #用户的组织数量 + # @user_composes_count = @user.composes.size + @user_composes_count = 0 + @user_org_count = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)).size + @user.organizations.with_visibility("privacy").joins(:organization_users).where(organization_users: {user_id: current_user.id}).size : @user.organizations.with_visibility("common").size + user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? @user.projects : @user.projects.visible + @projects_common_count = user_projects.common.size + @projects_mirrior_count = user_projects.mirror.size + @projects_sync_mirrior_count = user_projects.sync_mirror.size + end + + def watch_users + watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc") + if params[:search].present? + search_user_ids = User.where(id: watchers.pluck(:watchable_id)).like(params[:search]).pluck(:id) + watchers = watchers.where(watchable_id: search_user_ids) + end + @watchers_count = watchers.size + @watchers = paginate(watchers) + end + + def fan_users + watchers = @user.watchers.includes(:user).order("watchers.created_at desc") + watchers = watchers.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present? + + @watchers_count = watchers.size + @watchers = paginate(watchers) + end + + def update + @user = User.find params[:id] + @user.update!(user_params) + render_ok + end + + def me + @user = current_user + end + + # 贴吧获取用户信接口 + def get_user_info + begin + @user = current_user + # TODO 等消息上线再打开注释 + #@tidding_count = unviewed_tiddings(current_user) if current_user.present? + rescue Exception => e + uid_logger_error(e.message) + missing_template + end + + end + + def attachment_show + file_name = params[:file_name] + path = params[:path] || file_storage_directory + send_file "#{path}/#{file_name}", :filename => "#{file_name}", + :type => 'game', + :disposition => 'attachment' #inline can open in browser + end + + def html_show + @contents = File.read("#{params[:path]}") + respond_to do |format| + format.html {render :layout => false} + end + end + + # Redo: 消息总数缓存 + def get_navigation_info + # @old_domain = edu_setting('old_edu_host') + # @user = current_user + # # 新消息数 + # @new_message = @user.tidings.where("created_at > '#{@user.click_time}'").count > 0 || @user.private_messages.where("created_at > '#{@user.click_time}'").count > 0 + # + # @user_url = "/users/#{@user.login}" + # @career = Career.where(status: true).order("created_at asc").pluck(:id, :name) + # @auth = User.current.ec_school.present? ? "#{@old_domain}/ecs/department?school_id=#{User.current.ec_school}" : nil + end + + # 用户回复功能 + def reply_message + message = JournalsForMessage.new(reply_message_params) + message.user_id = current_user.id + message.save! + + render_ok(id: message.id) + end + + # 搜索用户具有管理员角色的项目 + def search_user_projects + projects = Project.where.not(status: 9) + + projects = projects.joins(members: :member_roles).where(member_roles: { role_id: 3 }) + projects = projects.where(members: { user_id: current_user.id }) + + search = params[:search].to_s.strip + projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present? + + @projects = projects.select(:id, :name) + end + + #TODO 个人主页信息,forge上弃用-hs, 0602 + def homepage_info + #待办事项,现在未做 + @undo_events = 10 + #用户的组织数量 + # @user_composes_count = @user.composes.size + @user_composes_count = 10 + end + + def brief_introduction + content = params[:content].to_s.strip + + current_user.user_extension.update!(brief_introduction: content) + + render_ok + end + + def attendance + attendance = Users::AttendanceService.call(current_user) + render_ok(grade: current_user.grade, next_gold: attendance.next_gold) + rescue Users::AttendanceService::Error => ex + render_error(ex.message) + end + + # 其他平台登录后,必须将token同步到forge平台,实现sso登录功能 + def sync_token + return render_error('未找相关用户!') unless @user + token = Token.get_or_create_permanent_login_token(@user, autologin_action) + token.update_column(:value, params[:token]) + render_ok + end + + def trustie_related_projects + projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc") + projects_json = [] + domain_url = EduSetting.get('host_name') + '/projects' + if projects.present? + projects.each do |p| + project_url = "/#{p.owner.login}/#{p.identifier}" + pj = { + id: p.id, + name: p.name, + is_public: p.is_public, + updated_on: p.updated_on.strftime("%Y-%m-%d"), + status: p.status, + is_member: p.member?(current_user.try(:id)), + owner: { + name: p.owner.try(:show_real_name), + login: p.owner.login + }, + members_count: p&.members.size, + issues_count: p.issues_count - p.pull_requests_count, + commits_count: p&.project_score&.changeset_num.to_i, + http_url: domain_url + project_url, + http_collaborator_url: domain_url + project_url + "/setting/collaborator", + http_issues_url: domain_url + project_url + "/issues", + http_commits_url: domain_url + project_url + "/commits", + project_score: p&.project_score.present? ? p&.project_score&.as_json(:except=>[:created_at, :updated_at]).merge!(commit_time: format_time(p&.project_score&.commit_time)) : {} + } + projects_json.push(pj) + end + end + Rails.logger.info("==========projects_json========+########{projects_json}") + render json: { projects: projects_json.present? ? projects_json : {} } + end + + def trustie_projects + user_id = User.select(:id, :login).where(login: params[:login])&.first&.id + projects = Project.visible + + projects = projects.joins(:members).where(members: { user_id: user_id }) + + search = params[:search].to_s.strip + projects = projects.where('projects.name LIKE ?', "%#{search}%") if search.present? + + projects = projects.select(:id, :name).limit(10).as_json + render json: { projects: projects } + end + + def projects + is_current_admin_user = User.current.logged? && (current_user&.admin? || current_user.id == @user.id) + scope = Projects::ListMyQuery.call(params, @user,is_current_admin_user) + @total_count = scope.size + @projects = paginate(scope) + end + + # TODO 其他平台登录时同步修改gitea平台对应用户的密码 + # 该方法主要用于:别的平台初次部署对接forge平台,同步用户后,gitea平台对应的用户密码与forge平台用户密码不一致是问题 + def sync_gitea_pwd + return render_error("未找到相关的用户") if @user.blank? + + flag = sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) + flag ? render_ok : render_error('同步失败!') + end + + # TODO + # 同步trusite平台用户的salt信息,只需同步一次,同步完成后,该方法可以删除 + def sync_salt + user = User.find_by_login params[:login] + return if user.blank? + user.update_column(:salt, params[:salt]) + render_ok + end + + private + def load_user + @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) + end + + def user_params + params.require(:user).permit(:nickname, :lastname, :show_realname,:login,:mail, + user_extension_attributes: [ + :gender, :location, :location_city, + :occupation, :technical_title, + :school_id, :department_id,:identity, :student_id, :description] + ) + end + + def reply_message_params + normal_status(-1, "参数不对") if params[:journals_for_message][:jour_type].nil? || params[:journals_for_message][:jour_id].nil? || + params[:journals_for_message][:notes].nil? || params[:journals_for_message][:reply_id].nil? + params.require(:journals_for_message).permit(:jour_type, :jour_id, :notes, :m_parent_id, :reply_id) + end + + def check_user_exist + return if @user.present? + render_not_found + end + +end