diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index f61ba2478..a04a16aa9 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,332 +1,365 @@ -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, :hovercard] - before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard] - before_action :require_login, only: %i[me sync_user_info] - before_action :connect_to_ci_db, only: [:get_user_info] - before_action :convert_image!, only: [:update, :update_image] - 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 - #待办事项,现在未做 - if User.current.admin? || User.current.login == @user.login - @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_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 = @common_applied_transfer_projects.size + @common_applied_projects.size - else - @waiting_applied_messages = AppliedMessage.none - @common_applied_transfer_projects = AppliedTransferProject.none - @common_applied_projects = AppliedProject.none - @undo_events = 0 - end - #用户的组织数量 - # @user_composes_count = @user.composes.size - @user_composes_count = 0 - user_organizations = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)) + @user.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @user.organizations.with_visibility("common") - @user_org_count = user_organizations.size - normal_projects = Project.members_projects(@user.id).to_sql - org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @user.id}).to_sql - projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct - user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? projects : 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 - # 为了缓存活跃用户的基本信息,后续删除 - Cache::V2::OwnerCommonService.new(@user.id).read - 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).merge(User.like(params[:search])) - @watchers_count = watchers.size - @watchers = paginate(watchers) - end - - def hovercard - end - - def update - 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) - Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? - @user.attributes = user_params.except(:image) - unless @user.save - render_error(-1, @user.errors.full_messages.join(", ")) - end - end - - def update_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) - - Util.write_file(@image, avatar_path(@user)) - return render_ok({message: '头像修改成功'}) - rescue Exception => e - uid_logger_error(e.message) - render_error(-1, '头像修改失败!') - 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 - @user = current_user - end - - # 贴吧获取用户信接口 - def get_user_info - begin - @user = current_user - begin - result = Notice::Read::CountService.call(current_user.id) - @message_unread_total = result.nil? ? 0 : result[2]["unread_notification"] - rescue - @message_unread_total = 0 - end - # 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') - 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') - 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 - - def sync_user_info - user = User.find_by_login params[:login] - return render_forbidden unless user === current_user - - sync_params = { - email: params[:email], - password: params[:password] - } - - Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate! - - interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params) - if interactor.success? - user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE) - render_ok - else - render_error(interactor.error) - end - 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, :image, - user_extension_attributes: [ - :gender, :location, :location_city, - :occupation, :technical_title, - :school_id, :department_id, :province, :city, - :custom_department, :identity, :student_id, :description, - :show_super_description, :super_description, - :show_email, :show_location, :show_department] - ) - 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 - +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, :hovercard] + before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard] + before_action :require_login, only: %i[me sync_user_info] + before_action :connect_to_ci_db, only: [:get_user_info] + before_action :convert_image!, only: [:update, :update_image] + skip_before_action :check_sign, only: [:attachment_show] + # before_action :sso_login, only: [:get_user_info] + + 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 + #待办事项,现在未做 + if User.current.admin? || User.current.login == @user.login + @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_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 = @common_applied_transfer_projects.size + @common_applied_projects.size + else + @waiting_applied_messages = AppliedMessage.none + @common_applied_transfer_projects = AppliedTransferProject.none + @common_applied_projects = AppliedProject.none + @undo_events = 0 + end + #用户的组织数量 + # @user_composes_count = @user.composes.size + @user_composes_count = 0 + user_organizations = User.current.logged? ? @user.organizations.with_visibility(%w(common limited)) + @user.organizations.with_visibility("privacy").joins(:team_users).where(team_users: {user_id: current_user.id}) : @user.organizations.with_visibility("common") + @user_org_count = user_organizations.size + normal_projects = Project.members_projects(@user.id).to_sql + org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: @user.id}).to_sql + projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct + user_projects = User.current.logged? && (User.current.admin? || User.current.login == @user.login) ? projects : 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 + # 为了缓存活跃用户的基本信息,后续删除 + Cache::V2::OwnerCommonService.new(@user.id).read + 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).merge(User.like(params[:search])) + @watchers_count = watchers.size + @watchers = paginate(watchers) + end + + def hovercard + end + + def update + 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) + Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? + @user.attributes = user_params.except(:image) + unless @user.save + render_error(-1, @user.errors.full_messages.join(", ")) + end + end + + def update_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) + + Util.write_file(@image, avatar_path(@user)) + return render_ok({message: '头像修改成功'}) + rescue Exception => e + uid_logger_error(e.message) + render_error(-1, '头像修改失败!') + 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 + @user = current_user + end + + # 贴吧获取用户信接口 + def get_user_info + begin + @user = current_user + begin + result = Notice::Read::CountService.call(current_user.id) + @message_unread_total = result.nil? ? 0 : result[2]["unread_notification"] + rescue + @message_unread_total = 0 + end + # 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') + 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') + 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 + + def sync_user_info + user = User.find_by_login params[:login] + return render_forbidden unless user === current_user + + sync_params = { + email: params[:email], + password: params[:password] + } + + Users::UpdateInfoForm.new(sync_params.merge(login: params[:login])).validate! + + interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params) + if interactor.success? + user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE) + render_ok + else + render_error(interactor.error) + end + 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, :image, + user_extension_attributes: [ + :gender, :location, :location_city, + :occupation, :technical_title, + :school_id, :department_id, :province, :city, + :custom_department, :identity, :student_id, :description, + :show_super_description, :super_description, + :show_email, :show_location, :show_department] + ) + 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 + + def sso_login + if params[:ticket].present? && !current_user.logged? && params[:websiteName].nil? + info = Base64.decode64(params[:ticket]) || Base64.decode64(params[:info].gsub(" ", "+")).force_encoding("utf-8") + # login 邮箱 手机号 姓名 学校/单位 + user_info = info.split("&&") + # Rails.logger.info("user_info====== #{info}") + login = user_info[0] + email = user_info[1] + phone = user_info[2] + real_name = user_info[3] + department_name = user_info[4] + + # 没有登录时,新建用户并登录 + if current_user.logged? + user = current_user + else + user = User.where("login = ? or phone = ? or mail = ? ", "edu_#{login}", phone, email).first + unless user + ActiveRecord::Base.transaction do + phone_rand = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sample(4).join + user_params = { status: 1, type: 'User', login: "e_#{login}", lastname: "#{real_name}", mail: "#{email}", + nickname: "#{real_name}", professional_certification: 0, certification: 0, grade: 0, + password: "12345678", phone: "#{phone_rand}", profile_completed: 1 } + user = User.create!(user_params) + UserExtension.create!(user_id: user.id, gender: 1, custom_department: "#{department_name}") + end + end + successful_authentication(user) + end + end + end + end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c9096fe22..25b642d73 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,486 +1,486 @@ -# 所有的方法请按首字母的顺序依次列出 -module ApplicationHelper - include Gitlink::I18n - include GitHelper - - ONE_MINUTE = 60 * 1000 - ONE_HOUR = 60 * ONE_MINUTE - ONE_DAY = 24 * ONE_HOUR - ONE_MONTH = 30 * ONE_DAY - - ONE_YEAR = 12 * ONE_MONTH - - # 全局参数配置 - def edu_setting name - EduSetting.get(name) - end - - # xss共计问题 - def content_safe content - tags = %w( - a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl - dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark - ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td - tfoot th thead time tr u ul var wbr div span - ) - attributes = %w(href src width height alt cite datetime title class name xml:lang abbr style) - sanitize content, tags: tags, attributes: attributes - end - - def graduation_navigation graduation - graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务" - end - - def graduation_navigation_id course - course.course_modules.find_by(module_type: "graduation").try(:id) - end - - # git用户 - # git用户命名规则:login+"@educoder.net" - def git_username(email) - User.find_by_mail(email) || User.find_by_login(email.split("@").first) - end - - # 不同的类型扩展不同的目录 - def relative_path - "avatars" - end - - def replace_bytes_to_b(size_string) - return size_string.gsub("Bytes", "B").gsub("bytes", "B").gsub("字节", "B") - end - - def storage_path - File.join(Rails.root, "public", "images", relative_path) - end - - # 推荐实训 - def recommend_shixun(shixun) - tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0 - shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and - shixun_id != #{shixun.id}").pluck(:shixun_id) - - shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",") - Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id - in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3) - - end - - # shixun开启挑战对应的行为名及url - def task_operation_url current_myshixun, shixun - if current_myshixun.blank? - name = shixun.status == 0 ? "模拟实战" : "开启挑战" - url = "/shixuns/#{shixun.identifier}/shixun_exec" - else - identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier) - if current_myshixun.status == 1 - name = "查看实战" - else - name = "继续挑战" - end - url = identifier - end - [name, url] - end - - # 获取当前时间 - def time_from_now(time) - if String === time - time = Time.parse(time) - end - - lastUpdateTime = time.to_i*1000 - - currentTime = Time.now.to_i*1000 - timePassed = currentTime - lastUpdateTime - timeIntoFormat = 0 - updateAtValue = "" - if timePassed < 0 - updateAtValue = "刚刚" - elsif timePassed < ONE_MINUTE - updateAtValue = "1分钟前" - elsif timePassed < ONE_HOUR - timeIntoFormat = timePassed / ONE_MINUTE - updateAtValue = timeIntoFormat.to_s + "分钟前" - elsif (timePassed < ONE_DAY) - timeIntoFormat = timePassed / ONE_HOUR - updateAtValue = timeIntoFormat.to_s + "小时前" - elsif (timePassed < ONE_MONTH) - timeIntoFormat = timePassed / ONE_DAY - updateAtValue = timeIntoFormat.to_s + "天前" - elsif (timePassed < ONE_YEAR) - timeIntoFormat = timePassed / ONE_MONTH - updateAtValue = timeIntoFormat.to_s + "个月前" - else - timeIntoFormat = timePassed / ONE_YEAR - updateAtValue = timeIntoFormat.to_s + "年前" - end - updateAtValue - end - - # 计算到结束还有多长时间 **天**小时**分 - def how_much_time(time) - if time.nil? || time < Time.now #6.21 -hs 增加小于time.now - '' - else - result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + " 天 " - result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 " - result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + " 分 " - end - end - - def format_time(time) - time.present? ? time.strftime("%Y-%m-%d %H:%M") : '' - end - - # 用户图像url,如果不存在的话,source为匿名用户,即默认使用匿名用户图像 - def url_to_avatar(source) - if File.exist?(disk_filename(source&.class, source&.id)) - ctime = File.ctime(disk_filename(source.class, source.id)).to_i - if %w(User Organization).include?(source.class.to_s) - File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" - else - File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" - end - elsif source.class.to_s == 'User' - source.get_letter_avatar_url - 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图 - def banner_img(source_type) - if File.exist?(disk_filename(source_type, "banner")) - ctime = File.ctime(disk_filename(source_type, "banner")).to_i - File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}" - end - end - - def disk_filename(source_type,source_id,image_file=nil) - File.join(storage_path, "#{source_type}", "#{source_id}") - end - - def disk_auth_filename(source_type, source_id, type) - File.join(storage_path, "#{source_type}", "#{source_id}#{type}") - end - - def disk_real_name_auth_filename(source_id) - disk_auth_filename('UserAuthentication', source_id, 'ID') - end - - def auth_file_url(source_type, source_id, type) - File.join('/images', relative_path, source_type, "#{source_id}#{type}") - end - - def real_name_auth_file_url(source_id) - auth_file_url('UserAuthentication', source_id, 'ID') - end - - def disk_professional_auth_filename(source_id) - disk_auth_filename('UserAuthentication', source_id, 'PRO') - end - - def professional_auth_file_url(source_id) - auth_file_url('UserAuthentication', source_id, 'PRO') - end - - def shixun_url_to_avatar(shixun) - if File.exist?(disk_filename(shixun.class, shixun.id)) - File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}") - else - File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg") - end - end - - # 选用实训的学校情况 - def school_user_detail shixun - user_ids = shixun.myshixuns.map(&:user_id).uniq # 走缓存取数据 - school_ids = UserExtension.where(user_id:user_ids).pluck(:school_id).uniq - school_names = School.where(id: school_ids[0..1]).pluck(:name) - school_size = school_ids.size - str = school_size > 0 ? "#{school_names.join("、")}等 #{school_size}所" : "0所" - end - - # 普通/分组 作业作品状态数组 - def student_work_status homework, user_id, course, work - status = [] - homework_setting = homework.homework_group_setting user_id, true - work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id) - late_time = homework.late_time || course.end_date - - if course.is_end && work && work.work_status > 0 - status << "查看作品" - elsif !course.is_end - if homework_setting.publish_time && homework_setting.publish_time < Time.now - # 作业未截止时 - if homework_setting.end_time > Time.now - if homework.homework_type == "group" && homework.homework_detail_group.base_on_project - if work.project_id.nil? || work.project_id == 0 - status << "创建项目" - status << "关联项目" - elsif work.work_status == 0 - status << "取消关联" - status << "提交作品" - else - status << "修改作品" - end - else - if work.work_status == 0 - status << "提交作品" - else - status << "修改作品" - end - end - - # 补交阶段 - elsif homework.allow_late && (late_time.nil? || late_time > Time.now) - if homework.homework_type == "group" && homework.homework_detail_group.base_on_project - if work.project_id.nil? || work.project_id == 0 - status << "创建项目" - status << "关联项目" - elsif work.work_status == 0 - status << "取消关联" - status << "补交作品" - else - status << "补交附件" - status << "查看作品" - end - else - if work.work_status == 0 - status << "补交作品" - else - status << "补交附件" - status << "查看作品" - end - end - - # 匿评阶段 - elsif work.work_status != 0 - if homework.homework_detail_manual.comment_status == 3 - work_ids = homework.student_works.has_committed.pluck(:id) - if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0 - status << "匿评作品" - end - end - status << "查看作品" - end - end - end - end - - def commit_des_status work, homework - status = [] - homework_setting = homework.homework_group_setting work.user_id - - # 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结 - if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 && - ((homework_setting.end_time && homework_setting.end_time > Time.now) || - (homework.allow_late && homework.late_time && homework.late_time > Time.now)) - work.description.present? ? status << "修改总结" : status << "提交总结" - end - end - - def download_url attachment,options={} - attachment_path(attachment,options) - end - - # 耗时:天、小时、分、秒 - # 小于1分钟则不显示 - def game_spend_time time - day = time / 86400 - hour = time % (24*60*60) / (60*60) - min = time % (24*60*60) % (60*60) / 60 - sec = time % (24*60*60) % (60*60) % 60 - if day < 1 - if hour < 1 - if min < 1 - if sec < 1 - time = "--" - else - time = "#{sec}秒" - end - else - time = "#{min}分钟 #{sec}秒" - end - else - time = "#{hour}小时 #{min}分钟 #{sec}秒" - end - else - time = "#{day}天 #{hour}小时 #{min}分钟 #{sec}秒" - end - return time - end - - def absolute_path(file_path) - file_root_directory + File.join(edu_setting('attachment_folder'), file_path) - end - - def file_root_directory - Rails.root.to_s - end - - def file_storage_directory - file_root_directory + edu_setting('attachment_folder') - end - - def local_path(file) - File.join(file.disk_directory, file.disk_filename) - end - - def update_downloads(file) - file.update_attributes(:downloads => file.downloads + 1) - end - - # 项目信息, - def project_info work, current_user, course_identity - project = work.project - if project - if project.status == 9 - {id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count} - else - project_score = project.project_score - if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT - {id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count, - all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, - attachment_score: project_score.attachment_score, message_score: project_score.message_score} - else - {id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count, - all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, - attachment_score: project_score.attachment_score, message_score: project_score.message_score} - end - end - else - {id: -1, name: "--", title: "--"} - end - end - - def message_content(content) - content = (strip_html content).strip - content = content.gsub(/\s+/, " ") - if content.gsub(" ", "") == "" - content = "[非文本消息]" - end - content - end - - def strip_html(text, len=0, endss="...") - ss = "" - if !text.nil? && text.length>0 - ss=text.gsub(/<\/?.*?>/, '').strip - ss = ss.gsub(/ */, '') - ss = ss.gsub(/\r\n/,'') #新增 - ss = ss.gsub(/\n/,'') #新增 - if len > 0 && ss.length > len - ss = ss[0, len] + endss - elsif len > 0 && ss.length <= len - ss = ss - #ss = truncate(ss, :length => len) - end - end - ss - end - - def strip_export_title(content) - con_ = "" - if content.length > 0 - con_ = strip_tags(content) - con_ = con_.gsub(/\r\n/,'').gsub(/ */, '').strip - end - con_ - end - - def pdf_load_sources(*arg) - arr = arg.map do |path| - content_tag(:script) do - File.open(Rails.root.join('public', path)).read.to_s.html_safe - end - end - - raw arr.join('') - end - - - - # 导出pdf时,转化markdown为html - def to_markdown(text,origin_url) - return nil if text.blank? - options = { - :autolink => true, - :no_intra_emphasis => true, - :fenced_code_blocks => true, - :lax_html_blocks => true, - :strikethrough => true, - :superscript => false, - :tables => true - } - markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options) - m_t = markdown.render(text) - m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t - end - - def shixun_status_class(shixun) - case shixun.status - when 0 then 'text-info' - when 1 then 'text-warning' - when 2 then 'text-success' - when 3 then 'text-secondary' - end - end - - def render_unix_time(date) - date.to_time.to_i - end - - def find_user_by_login(login) - User.find_by_login login - end - - def find_user_by_login_and_mail(login, mail) - User.find_by(login: login, mail: mail) - end - - def find_user_by_gitea_uid(gitea_uid) - User.find_by(gitea_uid: gitea_uid) - end - - def find_user_in_redis_cache(login, email) - $redis_cache.hgetall("v2-owner-common:#{login}-#{email}") - end - - def find_user_in_redis_cache_by_id(id) - $redis_cache.hgetall("v2-owner-common:#{id}") - end - - def render_base64_decoded(str) - return nil if str.blank? - Base64.decode64 str - end - - def render_admin_statistics_item - url = Rails.application.config_for(:configuration)["admin_statistics_url"] - - return if url.blank? - content_tag(:li) do - sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root') - end - end - - # 1 手机类型;0 邮箱类型 - # 注意新版的login是自动名生成的 - def phone_mail_type value - value =~ /^1\d{10}$/ ? 1 : 0 - end - - def strip(str) - str.to_s.strip.presence - end - -end +# 所有的方法请按首字母的顺序依次列出 +module ApplicationHelper + include Gitlink::I18n + include GitHelper + + ONE_MINUTE = 60 * 1000 + ONE_HOUR = 60 * ONE_MINUTE + ONE_DAY = 24 * ONE_HOUR + ONE_MONTH = 30 * ONE_DAY + + ONE_YEAR = 12 * ONE_MONTH + + # 全局参数配置 + def edu_setting name + EduSetting.get(name) + end + + # xss共计问题 + def content_safe content + tags = %w( + a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl + dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark + ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td + tfoot th thead time tr u ul var wbr div span + ) + attributes = %w(href src width height alt cite datetime title class name xml:lang abbr style) + sanitize content, tags: tags, attributes: attributes + end + + def graduation_navigation graduation + graduation.class.to_s == "GraduationTopic" ? "毕设选题" : "毕设任务" + end + + def graduation_navigation_id course + course.course_modules.find_by(module_type: "graduation").try(:id) + end + + # git用户 + # git用户命名规则:login+"@educoder.net" + def git_username(email) + User.find_by_mail(email) || User.find_by_login(email.split("@").first) + end + + # 不同的类型扩展不同的目录 + def relative_path + "avatars" + end + + def replace_bytes_to_b(size_string) + return size_string.gsub("Bytes", "B").gsub("bytes", "B").gsub("字节", "B") + end + + def storage_path + File.join(Rails.root, "public", "images", relative_path) + end + + # 推荐实训 + def recommend_shixun(shixun) + tag_repertoire_id = shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0 + shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{tag_repertoire_id} and + shixun_id != #{shixun.id}").pluck(:shixun_id) + + shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",") + Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id + in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3) + + end + + # shixun开启挑战对应的行为名及url + def task_operation_url current_myshixun, shixun + if current_myshixun.blank? + name = shixun.status == 0 ? "模拟实战" : "开启挑战" + url = "/shixuns/#{shixun.identifier}/shixun_exec" + else + identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier) + if current_myshixun.status == 1 + name = "查看实战" + else + name = "继续挑战" + end + url = identifier + end + [name, url] + end + + # 获取当前时间 + def time_from_now(time) + if String === time + time = Time.parse(time) + end + + lastUpdateTime = time.to_i*1000 + + currentTime = Time.now.to_i*1000 + timePassed = currentTime - lastUpdateTime + timeIntoFormat = 0 + updateAtValue = "" + if timePassed < 0 + updateAtValue = "刚刚" + elsif timePassed < ONE_MINUTE + updateAtValue = "1分钟前" + elsif timePassed < ONE_HOUR + timeIntoFormat = timePassed / ONE_MINUTE + updateAtValue = timeIntoFormat.to_s + "分钟前" + elsif (timePassed < ONE_DAY) + timeIntoFormat = (timePassed.to_f / ONE_HOUR).ceil + updateAtValue = timeIntoFormat.to_s + "小时前" + elsif (timePassed < ONE_MONTH) + timeIntoFormat = (timePassed.to_f / ONE_DAY).ceil + updateAtValue = timeIntoFormat.to_s + "天前" + elsif (timePassed < ONE_YEAR) + timeIntoFormat = (timePassed.to_f / ONE_MONTH).ceil + updateAtValue = timeIntoFormat.to_s + "个月前" + else + timeIntoFormat = timePassed / ONE_YEAR + updateAtValue = timeIntoFormat.to_s + "年前" + end + updateAtValue + end + + # 计算到结束还有多长时间 **天**小时**分 + def how_much_time(time) + if time.nil? || time < Time.now #6.21 -hs 增加小于time.now + '' + else + result = ((time - Time.now.to_i).to_i / (24*60*60)).to_s + " 天 " + result += (((time - Time.now.to_i).to_i % (24*60*60)) / (60*60)).to_s + " 小时 " + result + ((((time - Time.now.to_i).to_i % (24*60*60)) % (60*60)) / 60).to_s + " 分 " + end + end + + def format_time(time) + time.present? ? time.strftime("%Y-%m-%d %H:%M") : '' + end + + # 用户图像url,如果不存在的话,source为匿名用户,即默认使用匿名用户图像 + def url_to_avatar(source) + if File.exist?(disk_filename(source&.class, source&.id)) + ctime = File.ctime(disk_filename(source.class, source.id)).to_i + if %w(User Organization).include?(source.class.to_s) + File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" + else + File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" + end + elsif source.class.to_s == 'User' + source.get_letter_avatar_url + 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图 + def banner_img(source_type) + if File.exist?(disk_filename(source_type, "banner")) + ctime = File.ctime(disk_filename(source_type, "banner")).to_i + File.join("images/avatars", ["#{source_type}", "banner"]) + "?t=#{ctime}" + end + end + + def disk_filename(source_type,source_id,image_file=nil) + File.join(storage_path, "#{source_type}", "#{source_id}") + end + + def disk_auth_filename(source_type, source_id, type) + File.join(storage_path, "#{source_type}", "#{source_id}#{type}") + end + + def disk_real_name_auth_filename(source_id) + disk_auth_filename('UserAuthentication', source_id, 'ID') + end + + def auth_file_url(source_type, source_id, type) + File.join('/images', relative_path, source_type, "#{source_id}#{type}") + end + + def real_name_auth_file_url(source_id) + auth_file_url('UserAuthentication', source_id, 'ID') + end + + def disk_professional_auth_filename(source_id) + disk_auth_filename('UserAuthentication', source_id, 'PRO') + end + + def professional_auth_file_url(source_id) + auth_file_url('UserAuthentication', source_id, 'PRO') + end + + def shixun_url_to_avatar(shixun) + if File.exist?(disk_filename(shixun.class, shixun.id)) + File.join("images/#{relative_path}", "#{shixun.class}", "#{shixun.id}") + else + File.join("educoder", "index", "shixun", "shixun#{rand(23)}.jpg") + end + end + + # 选用实训的学校情况 + def school_user_detail shixun + user_ids = shixun.myshixuns.map(&:user_id).uniq # 走缓存取数据 + school_ids = UserExtension.where(user_id:user_ids).pluck(:school_id).uniq + school_names = School.where(id: school_ids[0..1]).pluck(:name) + school_size = school_ids.size + str = school_size > 0 ? "#{school_names.join("、")}等 #{school_size}所" : "0所" + end + + # 普通/分组 作业作品状态数组 + def student_work_status homework, user_id, course, work + status = [] + homework_setting = homework.homework_group_setting user_id, true + work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id) + late_time = homework.late_time || course.end_date + + if course.is_end && work && work.work_status > 0 + status << "查看作品" + elsif !course.is_end + if homework_setting.publish_time && homework_setting.publish_time < Time.now + # 作业未截止时 + if homework_setting.end_time > Time.now + if homework.homework_type == "group" && homework.homework_detail_group.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "提交作品" + else + status << "修改作品" + end + else + if work.work_status == 0 + status << "提交作品" + else + status << "修改作品" + end + end + + # 补交阶段 + elsif homework.allow_late && (late_time.nil? || late_time > Time.now) + if homework.homework_type == "group" && homework.homework_detail_group.base_on_project + if work.project_id.nil? || work.project_id == 0 + status << "创建项目" + status << "关联项目" + elsif work.work_status == 0 + status << "取消关联" + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + else + if work.work_status == 0 + status << "补交作品" + else + status << "补交附件" + status << "查看作品" + end + end + + # 匿评阶段 + elsif work.work_status != 0 + if homework.homework_detail_manual.comment_status == 3 + work_ids = homework.student_works.has_committed.pluck(:id) + if StudentWorksEvaluationDistribution.where(student_work_id: work_ids, user_id: user_id).size > 0 + status << "匿评作品" + end + end + status << "查看作品" + end + end + end + end + + def commit_des_status work, homework + status = [] + homework_setting = homework.homework_group_setting work.user_id + + # 作业已发布且作业未截止(补交未截止)且提交了作品才能提交或修改总结 + if homework_setting.publish_time && homework_setting.publish_time < Time.now && work.work_status > 0 && + ((homework_setting.end_time && homework_setting.end_time > Time.now) || + (homework.allow_late && homework.late_time && homework.late_time > Time.now)) + work.description.present? ? status << "修改总结" : status << "提交总结" + end + end + + def download_url attachment,options={} + attachment_path(attachment,options) + end + + # 耗时:天、小时、分、秒 + # 小于1分钟则不显示 + def game_spend_time time + day = time / 86400 + hour = time % (24*60*60) / (60*60) + min = time % (24*60*60) % (60*60) / 60 + sec = time % (24*60*60) % (60*60) % 60 + if day < 1 + if hour < 1 + if min < 1 + if sec < 1 + time = "--" + else + time = "#{sec}秒" + end + else + time = "#{min}分钟 #{sec}秒" + end + else + time = "#{hour}小时 #{min}分钟 #{sec}秒" + end + else + time = "#{day}天 #{hour}小时 #{min}分钟 #{sec}秒" + end + return time + end + + def absolute_path(file_path) + file_root_directory + File.join(edu_setting('attachment_folder'), file_path) + end + + def file_root_directory + Rails.root.to_s + end + + def file_storage_directory + file_root_directory + edu_setting('attachment_folder') + end + + def local_path(file) + File.join(file.disk_directory, file.disk_filename) + end + + def update_downloads(file) + file.update_attributes(:downloads => file.downloads + 1) + end + + # 项目信息, + def project_info work, current_user, course_identity + project = work.project + if project + if project.status == 9 + {id: -1, name: "#{project.name}(已删除)", title: "该项目已删除", author: project.creator, member_count: project.project_members.count} + else + project_score = project.project_score + if project.is_public || current_user.manager_of_project?(project) || course_identity < Course::STUDENT + {id: project.id, name: project.name, author: project.creator, member_count: project.project_members.count, + all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, + attachment_score: project_score.attachment_score, message_score: project_score.message_score} + else + {id: -1, name: "#{project.name}", title: "该项目是私有的", author: project.creator, member_count: project.project_members.count, + all_score: project_score.all_score, code_score: project_score.code_score, issue_score: project_score.issue_score, + attachment_score: project_score.attachment_score, message_score: project_score.message_score} + end + end + else + {id: -1, name: "--", title: "--"} + end + end + + def message_content(content) + content = (strip_html content).strip + content = content.gsub(/\s+/, " ") + if content.gsub(" ", "") == "" + content = "[非文本消息]" + end + content + end + + def strip_html(text, len=0, endss="...") + ss = "" + if !text.nil? && text.length>0 + ss=text.gsub(/<\/?.*?>/, '').strip + ss = ss.gsub(/ */, '') + ss = ss.gsub(/\r\n/,'') #新增 + ss = ss.gsub(/\n/,'') #新增 + if len > 0 && ss.length > len + ss = ss[0, len] + endss + elsif len > 0 && ss.length <= len + ss = ss + #ss = truncate(ss, :length => len) + end + end + ss + end + + def strip_export_title(content) + con_ = "" + if content.length > 0 + con_ = strip_tags(content) + con_ = con_.gsub(/\r\n/,'').gsub(/ */, '').strip + end + con_ + end + + def pdf_load_sources(*arg) + arr = arg.map do |path| + content_tag(:script) do + File.open(Rails.root.join('public', path)).read.to_s.html_safe + end + end + + raw arr.join('') + end + + + + # 导出pdf时,转化markdown为html + def to_markdown(text,origin_url) + return nil if text.blank? + options = { + :autolink => true, + :no_intra_emphasis => true, + :fenced_code_blocks => true, + :lax_html_blocks => true, + :strikethrough => true, + :superscript => false, + :tables => true + } + markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options) + m_t = markdown.render(text) + m_t&.include?("src=\"") ? m_t&.gsub("src=\"","src=\"#{origin_url}") : m_t + end + + def shixun_status_class(shixun) + case shixun.status + when 0 then 'text-info' + when 1 then 'text-warning' + when 2 then 'text-success' + when 3 then 'text-secondary' + end + end + + def render_unix_time(date) + date.to_time.to_i + end + + def find_user_by_login(login) + User.find_by_login login + end + + def find_user_by_login_and_mail(login, mail) + User.find_by(login: login, mail: mail) + end + + def find_user_by_gitea_uid(gitea_uid) + User.find_by(gitea_uid: gitea_uid) + end + + def find_user_in_redis_cache(login, email) + $redis_cache.hgetall("v2-owner-common:#{login}-#{email}") + end + + def find_user_in_redis_cache_by_id(id) + $redis_cache.hgetall("v2-owner-common:#{id}") + end + + def render_base64_decoded(str) + return nil if str.blank? + Base64.decode64 str + end + + def render_admin_statistics_item + url = Rails.application.config_for(:configuration)["admin_statistics_url"] + + return if url.blank? + content_tag(:li) do + sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root') + end + end + + # 1 手机类型;0 邮箱类型 + # 注意新版的login是自动名生成的 + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + end + + def strip(str) + str.to_s.strip.presence + end + +end