diff --git a/Gemfile b/Gemfile index 48fc00694..d573a4cc2 100644 --- a/Gemfile +++ b/Gemfile @@ -118,6 +118,10 @@ gem 'deep_cloneable', '~> 3.0.0' # oauth2 gem 'omniauth', '~> 1.9.0' gem 'omniauth-oauth2', '~> 1.6.0' +gem "omniauth-github" +gem "omniauth-rails_csrf_protection" +gem 'omniauth-gitee', '~> 1.0.0' +gem "omniauth-wechat-oauth2" # global var gem 'request_store' @@ -135,4 +139,4 @@ gem 'doorkeeper' gem 'doorkeeper-jwt' -gem 'gitea-client', '~> 0.10.5' \ No newline at end of file +gem 'gitea-client', '~> 0.11.1' \ No newline at end of file diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index a418c5f37..4a104129b 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -141,6 +141,7 @@ class AccountsController < ApplicationController 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 @@ -152,6 +153,10 @@ class AccountsController < ApplicationController 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 @@ -393,7 +398,7 @@ class AccountsController < ApplicationController end def register_params - params.permit(:login, :namespace, :password, :password_confirmation, :code) + params.permit(:login, :namespace, :password, :password_confirmation, :code, :type) end def reset_password_params diff --git a/app/controllers/admins/feedbacks_controller.rb b/app/controllers/admins/feedbacks_controller.rb new file mode 100644 index 000000000..ff64ae5a1 --- /dev/null +++ b/app/controllers/admins/feedbacks_controller.rb @@ -0,0 +1,49 @@ +class Admins::FeedbacksController < Admins::BaseController + before_action :get_feedback, only: [:new_history, :create_history, :destroy] + + def index + sort_by = Feedback.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' + sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc' + feedbacks = Feedback.order("#{sort_by} #{sort_direction}") + @feedbacks = paginate(feedbacks) + end + + def destroy + if @feedback.destroy + redirect_to admins_feedbacks_path + flash[:success] = "反馈意见删除成功" + else + redirect_to admins_feedbacks_path + flash[:danger] = "反馈意见删除失败" + end + end + + def new_history + @feedback_message_history = FeedbackMessageHistory.new + end + + def create_history + @feedback_message_history = @feedback.feedback_message_histories.new(feedback_message_history_params) + @feedback_message_history.user = current_user + if @feedback_message_history.save + redirect_to admins_feedbacks_path + flash[:success] = "发送通知成功" + else + redirect_to admins_feedbacks_path + flash[:danger] = @feedback_message_history.errors.full_messages.join(", ") + end + end + + private + def feedback_params + params.require(:feedback).permit! + end + + def feedback_message_history_params + params.require(:feedback_message_history).permit(:title, :content) + end + + def get_feedback + @feedback = Feedback.find_by_id(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/admins/topic/banners_controller.rb b/app/controllers/admins/topic/banners_controller.rb index 8d48892bc..c0350e355 100644 --- a/app/controllers/admins/topic/banners_controller.rb +++ b/app/controllers/admins/topic/banners_controller.rb @@ -53,6 +53,6 @@ class Admins::Topic::BannersController < Admins::Topic::BaseController end def banner_params - params.require(:topic_banner).permit(:title, :order_index) + params.require(:topic_banner).permit(:title, :order_index, :url) end end \ No newline at end of file diff --git a/app/controllers/api/v1/projects/code_stats_controller.rb b/app/controllers/api/v1/projects/code_stats_controller.rb new file mode 100644 index 000000000..7ec671f3c --- /dev/null +++ b/app/controllers/api/v1/projects/code_stats_controller.rb @@ -0,0 +1,8 @@ +class Api::V1::Projects::CodeStatsController < Api::V1::BaseController + before_action :require_public_and_member_above, only: [:index] + + def index + @result_object = Api::V1::Projects::CodeStats::ListService.call(@project, {ref: params[:ref]}, current_user&.gitea_token) + puts @result_object + end +end \ No newline at end of file diff --git a/app/controllers/api/v1/users/feedbacks_controller.rb b/app/controllers/api/v1/users/feedbacks_controller.rb new file mode 100644 index 000000000..4e79de7bd --- /dev/null +++ b/app/controllers/api/v1/users/feedbacks_controller.rb @@ -0,0 +1,16 @@ +class Api::V1::Users::FeedbacksController < Api::V1::BaseController + + before_action :load_observe_user + before_action :check_auth_for_observe_user + + def create + @result = Api::V1::Users::Feedbacks::CreateService.call(@observe_user, feedback_params) + return render_error("反馈意见创建失败.") if @result.nil? + return render_ok + end + + private + def feedback_params + params.permit(:content) + end +end \ No newline at end of file diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 3c6bec6a6..3a750b519 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -70,6 +70,21 @@ class Api::V1::UsersController < Api::V1::BaseController render_ok end + def check_phone_verify_code + code = strip(params[:code]) + phone = strip(params[:phone]) + code_type = params[:code_type] + + return tip_exception(-2, "手机号格式有误") unless phone =~ CustomRegexp::PHONE + + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: code_type).last + return render_ok if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试 + + return tip_exception(-6, "验证码不正确") if verifi_code&.code != code + return tip_exception(-6, "验证码已失效") if !verifi_code&.effective? + render_ok + end + def update_email @result_object = Api::V1::Users::UpdateEmailService.call(@observe_user, params, current_user.gitea_token) if @result_object @@ -78,4 +93,13 @@ class Api::V1::UsersController < Api::V1::BaseController return render_error('更改邮箱失败!') end end + + def update_phone + @result_object = Api::V1::Users::UpdatePhoneService.call(@observe_user, params) + if @result_object + return render_ok + else + return render_error('更改手机号失败!') + end + end end \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index eaffdeca0..7490cb27f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -79,8 +79,7 @@ class ApplicationController < ActionController::Base # 判断用户的邮箱或者手机是否可用 # params[:type] 1: 注册;2:忘记密码;3:绑定 def check_mail_and_phone_valid login, type - unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || - login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ + unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ tip_exception(-2, "请输入正确的手机号或邮箱") end @@ -103,8 +102,10 @@ class ApplicationController < ActionController::Base when 1, 2, 4, 9 # 手机类型的发送 sigle_para = {phone: value} - status = Gitlink::Sms.send(mobile: value, code: code) - tip_exception(-2, code_msg(status)) if status != 0 + # status = Gitlink::Sms.send(mobile: value, code: code) + # tip_exception(-2, code_msg(status)) if status != 0 + status = Sms::UcloudService.call(value, code, send_type) + tip_exception(-2, ucloud_code_msg(status)) if status != 0 when 8, 3, 5 # 邮箱类型的发送 sigle_para = {email: value} @@ -116,8 +117,13 @@ class ApplicationController < ActionController::Base send_email_control = LimitForbidControl::SendEmailCode.new(value) tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? begin - UserMailer.register_email(value, code).deliver_now - + if send_type == 3 + UserMailer.find_password(value, code).deliver_now + elsif send_type == 5 + UserMailer.bind_email(value, code).deliver_now + else + UserMailer.register_email(value, code).deliver_now + end Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) send_email_control.increment! # Mailer.run.email_register(code, value) @@ -149,6 +155,27 @@ class ApplicationController < ActionController::Base end end + def ucloud_code_msg status + case status + when 0 + "验证码已经发送到您的手机,请注意查收" + when 171 + "API签名错误" + when 18014 + "无效手机号码" + when 18017 + "无效模板" + when 18018 + "短信模板参数与短信模板不匹配" + when 18023 + "短信内容中含有运营商拦截的关键词" + when 18033 + "变量内容不符合规范" + else + "错误码#{status}" + end + end + def validate_type(object_type) normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) end @@ -638,7 +665,7 @@ class ApplicationController < ActionController::Base def kaminari_paginate(relation) limit = params[:limit] || params[:per_page] - limit = (limit.to_i.zero? || limit.to_i > 25) ? 25 : limit.to_i + limit = (limit.to_i.zero? || limit.to_i > 50) ? 50 : limit.to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i relation.page(page).per(limit) diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 1f5d5f459..63427aa45 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -32,7 +32,7 @@ class AttachmentsController < ApplicationController def get_file normal_status(-1, "参数缺失") if params[:download_url].blank? url = base_url.starts_with?("https:") ? URI.encode(params[:download_url].to_s.gsub("http:", "https:")) : URI.encode(params[:download_url].to_s) - if url.starts_with?(base_url) + if url.starts_with?(base_url) && !url.starts_with?("#{base_url}/repo") domain = GiteaService.gitea_config[:domain] api_url = GiteaService.gitea_config[:base_url] url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?') @@ -213,20 +213,17 @@ class AttachmentsController < ApplicationController def attachment_candown unless current_user.admin? || current_user.business? candown = true - unless params[:type] == 'history' - if @file.container && current_user.logged? - if @file.container.is_a?(Issue) - course = @file.container.project - candown = course.member?(current_user) || course.is_public - elsif @file.container.is_a?(Journal) - course = @file.container.issue.project - candown = course.member?(current_user) || course.is_public - else - course = nil - end - tip_exception(403, "您没有权限进入") if course.present? && !candown - tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication) + if @file.container + if @file.container.is_a?(Issue) + project = @file.container.project + candown = project.is_public || (current_user.logged? && project.member?(current_user)) + elsif @file.container.is_a?(Journal) + project = @file.container.issue.project + candown = project.is_public || (current_user.logged? && project.member?(current_user)) + else + project = nil end + tip_exception(403, "您没有权限进入") if project.present? && !candown end end end diff --git a/app/controllers/bind_users_controller.rb b/app/controllers/bind_users_controller.rb index 329ade866..f5ed33809 100644 --- a/app/controllers/bind_users_controller.rb +++ b/app/controllers/bind_users_controller.rb @@ -1,35 +1,19 @@ class BindUsersController < ApplicationController - # before_action :require_login def create - # user = CreateBindUserService.call(create_params) - # - if params[:type] == "qq" - begin - user = CreateBindUserService.call(current_user, create_params) - successful_authentication(user) if user.id != current_user.id + Rails.logger.debug "--------------开始绑定用户------------" + Rails.logger.debug "--------------params: #{params.to_unsafe_h}" + tip_exception '系统错误' if session[:unionid].blank? - render_ok - rescue ApplicationService::Error => ex - render_error(ex.message) - end - else - begin - tip_exception '系统错误' if session[:unionid].blank? + bind_user = User.try_to_login(params[:username], params[:password]) + tip_exception '用户名或者密码错误' if bind_user.blank? + tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s) + tip_exception '参数错误' unless ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s) + tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s) - bind_user = User.try_to_login(params[:username], params[:password]) - tip_exception '用户名或者密码错误' if bind_user.blank? - tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s) - tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s) - - OpenUsers::Wechat.create!(user: bind_user, uid: session[:unionid]) - successful_authentication(bind_user) - - render_ok - rescue Exception => e - render_error(e.message) - end - end + "OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: bind_user, uid: session[:unionid]) + successful_authentication(bind_user) + @user = bind_user end def new_user diff --git a/app/controllers/concerns/login_helper.rb b/app/controllers/concerns/login_helper.rb index 86ab175ef..c0e8d01c0 100644 --- a/app/controllers/concerns/login_helper.rb +++ b/app/controllers/concerns/login_helper.rb @@ -11,7 +11,7 @@ module LoginHelper def set_autologin_cookie(user) token = Token.get_or_create_permanent_login_token(user, "autologin") - sync_user_token_to_trustie(user.login, token.value) + # sync_user_token_to_trustie(user.login, token.value) Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" cookie_options = { diff --git a/app/controllers/concerns/register_helper.rb b/app/controllers/concerns/register_helper.rb index e1b7dee24..06c005084 100644 --- a/app/controllers/concerns/register_helper.rb +++ b/app/controllers/concerns/register_helper.rb @@ -1,18 +1,21 @@ module RegisterHelper extend ActiveSupport::Concern - def autologin_register(username, email, password, platform= 'forge', need_edit_info = false) + def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false) result = {message: nil, user: nil} + email = email.blank? ? "#{username}@example.org" : email user = User.new(admin: false, login: username, mail: email, type: "User") user.password = password user.platform = platform + user.phone = phone if phone.present? + user.nickname = nickname if nickname.present? if need_edit_info user.need_edit_info - else + else user.activate end - + return unless user.valid? interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) @@ -67,7 +70,7 @@ module RegisterHelper user.password = params[:password] user.mail = params[:email] - if user.save! + if user.save! sync_params = { password: params[:password].to_s, email: params[:email], @@ -75,9 +78,9 @@ module RegisterHelper new_name: params[:username], source_id: 0 } - + interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params) - if interactor.success? + if interactor.success? result[:user] = user else result[:message] = '用户同步Gitea失败!' diff --git a/app/controllers/issue_tags_controller.rb b/app/controllers/issue_tags_controller.rb index 011735ff7..da9f16f71 100644 --- a/app/controllers/issue_tags_controller.rb +++ b/app/controllers/issue_tags_controller.rb @@ -7,7 +7,7 @@ class IssueTagsController < ApplicationController def index - issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}") + issue_tags = @project.issue_tags.includes(:issues).reorder("issue_tags.#{order_name} #{order_type}") @user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user)) @page = params[:page] || 1 @limit = params[:limit] || 15 diff --git a/app/controllers/oauth/base_controller.rb b/app/controllers/oauth/base_controller.rb index 6956c9ce9..25cfa97db 100644 --- a/app/controllers/oauth/base_controller.rb +++ b/app/controllers/oauth/base_controller.rb @@ -3,6 +3,7 @@ class Oauth::BaseController < ActionController::Base include LoginHelper include ControllerRescueHandler include LoggerHelper + include RegisterHelper # include LaboratoryHelper skip_before_action :verify_authenticity_token @@ -13,13 +14,13 @@ class Oauth::BaseController < ActionController::Base private def tip_exception(status = -1, message) - raise Educoder::TipException.new(status, message) + raise Gitlink::TipException.new(status, message) end - + def tip_show_exception(status = -2, message) - raise Educoder::TipException.new(status, message) + raise Gitlink::TipException.new(status, message) end - + def tip_show(exception) uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") render json: exception.tip_json @@ -35,7 +36,7 @@ class Oauth::BaseController < ActionController::Base end def auth_hash - Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") + # Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") request.env['omniauth.auth'] end diff --git a/app/controllers/oauth/callbacks_controller.rb b/app/controllers/oauth/callbacks_controller.rb new file mode 100644 index 000000000..72885e7d9 --- /dev/null +++ b/app/controllers/oauth/callbacks_controller.rb @@ -0,0 +1,93 @@ +class Oauth::CallbacksController < Oauth::BaseController + def create + process_callback_new + rescue Exception => e + Rails.logger.info "授权失败:#{e}" + tip_exception("授权失败") + end + + private + + def config_providers + config = Rails.application.config_for(:configuration) + config.dig("oauth").keys + end + + # QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"} + def process_callback + Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") + if auth_hash.blank? + redirect_to("/login") && return + end + + new_user = false + platform = auth_hash[:provider] + uid = auth_hash[:uid] + mail = auth_hash.info.email || nil + nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname + + open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid) + if open_user.present? && open_user.user.present? + successful_authentication(open_user.user) + else + if current_user.blank? || !current_user.logged? + has_user = User.find_by(mail: mail) + if has_user.present? + "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra) + successful_authentication(has_user) + else + new_user = true + login = build_login_name(platform, auth_hash.info.nickname) + mail = "#{login}@example.org" if mail.blank? + code = %W(0 1 2 3 4 5 6 7 8 9) + rand_password = code.sample(10).join + reg_result = autologin_register(login, mail, rand_password, platform, nil, nickname) + Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ") + if reg_result[:message].blank? + open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra) + successful_authentication(open_user.user) + else + tip_exception(reg_result.present? ? reg_result[:message] : "授权失败") + end + end + else + "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra) + end + end + redirect_to root_path(new_user: new_user) + end + + def process_callback_new + Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") + if auth_hash.blank? + redirect_to("/login") && return + end + platform = auth_hash[:provider] + uid = auth_hash[:uid] + uid = auth_hash.info.unionid if platform == "wechat" + + open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid) + if open_user.present? && open_user.user.present? + successful_authentication(open_user.user) + redirect_to root_path(new_user: false) + return + else + if current_user.blank? || !current_user.logged? + session[:unionid] = uid + else + "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: uid) + end + end + Rails.logger.info("[OAuth2] session[:unionid] -> #{session[:unionid]}") + redirect_to "/bindlogin/#{platform}" + end + + # gitee,github nickname=login,如果系统未占用保留原用户名 + def build_login_name(provider, nickname) + if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank? + nickname + else + User.generate_user_login('p') + end + end +end \ No newline at end of file diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 0ae113590..10aaa1ae6 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -46,6 +46,12 @@ class Organizations::OrganizationsController < Organizations::BaseController @organization.nickname = organization_params[:nickname] if organization_params[:nickname].present? @organization.save! sync_organization_extension! + # 更改组织可见性为私有,则需将该组织下的所有仓库同步更改为私有仓库 + if organization_extension_params[:visibility] == "privacy" + Project.where(user_id: @organization.id).where(is_public: true).each do |project| + update_project_private(project) + end + end Gitea::Organization::UpdateService.call(current_user.gitea_token, login, @organization.reload) Util.write_file(@image, avatar_path(@organization)) if params[:image].present? @@ -123,5 +129,20 @@ class Organizations::OrganizationsController < Organizations::BaseController def sync_organization_extension! @organization.organization_extension.update_attributes!(organization_extension_params) end + + def update_project_private(project) + project.update_attributes!(is_public: false) + project.forked_projects.update_all(is_public: project.is_public) + gitea_params = { + private: true, + default_branch: project.default_branch, + website: project.website, + name: project.identifier + } + gitea_repo = Gitea::Repository::UpdateService.call(@organization, project&.repository&.identifier, gitea_params) + project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]}) + # 更新对应所属分类下的项目数量(私有) + project.project_category.decrement!(:private_projects_count, 1) if project.project_category.present? + end end \ No newline at end of file diff --git a/app/controllers/project_categories_controller.rb b/app/controllers/project_categories_controller.rb index 67a040fef..f6b3cbc9d 100644 --- a/app/controllers/project_categories_controller.rb +++ b/app/controllers/project_categories_controller.rb @@ -10,7 +10,7 @@ class ProjectCategoriesController < ApplicationController end def group_list - @project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc) + @project_categories = ProjectCategory.select("id, name, projects_count, private_projects_count, (projects_count - private_projects_count) as public_projects_count").having('public_projects_count > 0').order(public_projects_count: :desc) # projects = Project.no_anomory_projects.visible # @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size end diff --git a/app/controllers/project_rank_controller.rb b/app/controllers/project_rank_controller.rb index 7bd62987e..5cea074fb 100644 --- a/app/controllers/project_rank_controller.rb +++ b/app/controllers/project_rank_controller.rb @@ -1,10 +1,10 @@ class ProjectRankController < ApplicationController # 根据时间获取热门项目 def index - $redis_cache.zunionstore("recent-days-project-rank", get_timeable_key_names) + $redis_cache.zunionstore("recent-days-project-rank-#{time}", get_timeable_key_names) deleted_data = $redis_cache.smembers("v2-project-rank-deleted") - $redis_cache.zrem("recent-days-project-rank", deleted_data) unless deleted_data.blank? - @project_rank = $redis_cache.zrevrange("recent-days-project-rank", 0, 4, withscores: true) + $redis_cache.zrem("recent-days-project-rank-#{time}", deleted_data) unless deleted_data.blank? + @project_rank = $redis_cache.zrevrange("recent-days-project-rank-#{time}", 0, 9, withscores: true) rescue Exception => e @project_rank = [] end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 68c4e59fb..53f6d1aea 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -40,8 +40,9 @@ class ProjectsController < ApplicationController category_id = params[:category_id] @total_count = if category_id.blank? - ps = ProjectStatistic.first - ps.common_projects_count + ps.mirror_projects_count unless ps.blank? + # ps = ProjectStatistic.first + # ps.common_projects_count + ps.mirror_projects_count unless ps.blank? + @projects.total_count else cate = ProjectCategory.find_by(id: category_id) cate&.projects_count || 0 @@ -52,7 +53,7 @@ class ProjectsController < ApplicationController ActiveRecord::Base.transaction do Projects::CreateForm.new(project_params).validate! @project = Projects::CreateService.new(current_user, project_params).call - + OpenProjectDevOpsJob.perform_later(@project&.id, current_user.id) end rescue Exception => e uid_logger_error(e.message) @@ -154,6 +155,15 @@ class ProjectsController < ApplicationController } gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params) @project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]}) + # 更新对应所属分类下的项目数量(私有) + before_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][0] : @project.is_public + after_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][1] : @project.is_public + before_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][0] : @project.project_category_id + after_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][1] : @project.project_category_id + before_pc = ProjectCategory.find_by_id(before_pc_id) + after_pc = ProjectCategory.find_by_id(after_pc_id) + before_pc.decrement!(:private_projects_count, 1) if before_pc.present? && !before_is_public + after_pc.increment!(:private_projects_count, 1) if after_pc.present? && !after_is_public end SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu? end @@ -171,6 +181,8 @@ class ProjectsController < ApplicationController Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call @project.destroy! @project.forked_projects.update_all(forked_from_project_id: nil) + # 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量 + @project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public render_ok end else diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb index e81b68807..2b9bbbe6f 100644 --- a/app/controllers/pull_requests_controller.rb +++ b/app/controllers/pull_requests_controller.rb @@ -100,20 +100,6 @@ class PullRequestsController < ApplicationController Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate! merge_params - @issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank? - if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists? - if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1 - return normal_status(-1, "最多只能创建一个标记。") - elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1 - @issue&.issue_tags_relates&.destroy_all - params[:issue_tag_ids].each do |tag| - IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag) - end - else - return normal_status(-1, "请输入正确的标记。") - end - end - reviewers = User.where(id: params[:reviewer_ids]) @pull_request.reviewers = reviewers @@ -165,6 +151,8 @@ class PullRequestsController < ApplicationController colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user) if colsed === true @pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE) + # 合并请求下issue处理为关闭 + @issue&.update_attributes!({status_id:5}) SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu? normal_status(1, "已拒绝") else @@ -210,6 +198,8 @@ class PullRequestsController < ApplicationController # @pull_request.project_trend_status! @pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE) @issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id) + # 合并请求下issue处理为关闭 + @issue&.update_attributes!({status_id:5}) SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu? normal_status(1, "合并成功") else diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index f3eedd0a1..def2e2c89 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -7,6 +7,7 @@ class SettingsController < ApplicationController get_sub_competitions get_personal_menu get_third_party + get_third_party_new get_top_system_notification end @@ -67,6 +68,24 @@ class SettingsController < ApplicationController url: EducoderOauth.oauth_url } end + + def get_third_party_new + @third_party_new = [] + @third_party_new << { + name: 'educoder', + url: EducoderOauth.oauth_url, + method: 'get' + } + platform_url = Rails.application.config_for(:configuration)['platform_url'] + config = Rails.application.config_for(:configuration) + (config.dig("oauth").keys - ["educoder", "wechat"]).each do |provider| + @third_party_new << { + name: provider, + url: "#{platform_url}/auth/#{provider}", + method: 'get' + } + end + end def get_top_system_notification @top_system_notification = SystemNotification.is_top.first diff --git a/app/controllers/statistic_controller.rb b/app/controllers/statistic_controller.rb index 6eaa5bc99..40540e5e5 100644 --- a/app/controllers/statistic_controller.rb +++ b/app/controllers/statistic_controller.rb @@ -2,24 +2,24 @@ class StatisticController < ApplicationController # 平台概况 def platform_profile - @platform_user_query = Statistic::PlatformUserQuery.new(params).call - @platform_project_query = Statistic::PlatformProjectQuery.new(params).call - @platform_course_query = Statistic::PlatformCourseQuery.new(params).call + @platform_user_query = Statistic::PlatformUserQuery.new(params).call rescue [0, 0, 0] + @platform_project_query = Statistic::PlatformProjectQuery.new(params).call rescue [0, 0, 0] + @platform_course_query = Statistic::PlatformCourseQuery.new(params).call rescue [0, 0, 0] end # 平台代码提交数据 def platform_code - @platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call - @platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call + @platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call rescue [0, 0] + @platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call rescue [0, 0] end # 项目案例活跃度排行榜 def active_project_rank - @active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call + @active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call rescue [] end # 开发者活跃度排行榜 def active_developer_rank - @active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call + @active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call rescue [] end end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index c70f053f6..33fd93f83 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -57,6 +57,13 @@ class UsersController < ApplicationController Cache::V2::OwnerCommonService.new(@user.id).read end + def action + if params[:action_id].present? && params[:action_type].present? + UserAction.create(:action_id => params[:action_id], :action_type => "#{params[:action_type]}", :user_id => User.current.id, :ip => request.remote_ip) + end + render_ok + end + def watch_users watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc") if params[:search].present? diff --git a/app/helpers/admins/projects_helper.rb b/app/helpers/admins/projects_helper.rb index 36d9d6f5a..9a4d18552 100644 --- a/app/helpers/admins/projects_helper.rb +++ b/app/helpers/admins/projects_helper.rb @@ -6,7 +6,7 @@ module Admins::ProjectsHelper if owner.is_a?(User) link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank') elsif owner.is_a?(Organization) - link_to(project.owner&.real_name, "/organize/#{project&.owner&.login}", target: '_blank') + link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank') else "" end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index f7029c1cd..69491282d 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -10,7 +10,7 @@ module RepositoriesHelper end def download_type(str) - default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk) + default_type = %w(ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk xlsx xls) default_type.include?(str&.downcase) || str.blank? end @@ -91,7 +91,7 @@ module RepositoriesHelper new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join end content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"") - rescue + rescue next end end diff --git a/app/interactors/gitea/create_file_interactor.rb b/app/interactors/gitea/create_file_interactor.rb index 389813520..cf753767c 100644 --- a/app/interactors/gitea/create_file_interactor.rb +++ b/app/interactors/gitea/create_file_interactor.rb @@ -62,7 +62,7 @@ module Gitea file_params = {} file_params = file_params.merge(branch: @params[:branch]) unless @params[:branch].blank? file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank? - file_params = file_params.merge(content: Base64.encode64(@params[:content] || "")) + file_params = file_params.merge(content: @params[:content] || "") file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank? file_params = file_params.merge(committer: @params[:committer]) file_params diff --git a/app/jobs/migrate_remote_repository_job.rb b/app/jobs/migrate_remote_repository_job.rb index 488141910..5e56901a0 100644 --- a/app/jobs/migrate_remote_repository_job.rb +++ b/app/jobs/migrate_remote_repository_job.rb @@ -1,7 +1,7 @@ class MigrateRemoteRepositoryJob < ApplicationJob queue_as :default - def perform(repo_id, token, params) + def perform(repo_id, token, user_id, params) repo = Repository.find_by(id: repo_id) return if repo.blank? @@ -12,6 +12,10 @@ class MigrateRemoteRepositoryJob < ApplicationJob if gitea_repository[0]==201 repo&.project&.update_columns(gpid: gitea_repository[2]["id"]) repo&.mirror&.succeeded! + ## open jianmu devops + project_id = repo&.project&.id + puts "############ mirror project_id,user_id: #{project_id},#{user_id} ############" + OpenProjectDevOpsJob.perform_later(project_id, user_id) if project_id.present? && user_id.present? puts "############ mirror status: #{repo.mirror.status} ############" else repo&.mirror&.failed! diff --git a/app/jobs/open_project_dev_ops_job.rb b/app/jobs/open_project_dev_ops_job.rb new file mode 100644 index 000000000..64115f25f --- /dev/null +++ b/app/jobs/open_project_dev_ops_job.rb @@ -0,0 +1,16 @@ +class OpenProjectDevOpsJob < ApplicationJob + include ProjectsHelper + + queue_as :message + + def perform(project_id, user_id) + project = Project.find_by(id: project_id) + user = User.find_by(id: user_id) + code = jianmu_devops_code(project, user) + uri = URI.parse("#{jianmu_devops_url}/activate?code=#{URI.encode_www_form_component(code)}") + response = Net::HTTP.get_response(uri) + puts "jianmu_devops_url response.code ===== #{response.code}" + SendTemplateMessageJob.perform_later('ProjectOpenDevOps', user_id, project_id) + end + +end \ No newline at end of file diff --git a/app/jobs/send_template_message_job.rb b/app/jobs/send_template_message_job.rb index 557d4d0fa..763708c38 100644 --- a/app/jobs/send_template_message_job.rb +++ b/app/jobs/send_template_message_job.rb @@ -217,6 +217,14 @@ class SendTemplateMessageJob < ApplicationJob receivers = project&.all_managers.where.not(id: operator&.id) receivers_string, content, notification_url = MessageTemplate::ProjectPraised.get_message_content(receivers, operator, project) Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id}) + when 'ProjectOpenDevOps' + operator_id, project_id = args[0], args[1] + operator = User.find_by_id(operator_id) + project = Project.find_by_id(project_id) + return unless operator.present? && project.present? + receivers = User.where(id: operator.id) + receivers_string, content, notification_url = MessageTemplate::ProjectOpenDevOps.get_message_content(receivers, operator, project) + Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id}) when 'ProjectPullRequest' operator_id, pull_request_id = args[0], args[1] operator = User.find_by_id(operator_id) diff --git a/app/libs/educoder_oauth/service.rb b/app/libs/educoder_oauth/service.rb index 9d93d314d..1dcb2cfdd 100644 --- a/app/libs/educoder_oauth/service.rb +++ b/app/libs/educoder_oauth/service.rb @@ -15,7 +15,7 @@ module EducoderOauth::Service result rescue Exception => e - raise Educoder::TipException.new(e.message) + raise Gitlink::TipException.new(e.message) end end @@ -27,7 +27,7 @@ module EducoderOauth::Service result = client.auth_code.get_token(code, redirect_uri: EducoderOauth.redirect_uri).to_hash return result rescue Exception => e - raise Educoder::TipException.new(e.message) + raise Gitlink::TipException.new(e.message) end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 19f565183..28bbccf63 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,7 +1,8 @@ class UserMailer < ApplicationMailer # 注意:这个地方一定要和你的邮箱服务域名一致 # default from: 'notification@trustie.org' - default from: 'noreply@gitlink.org.cn' + # default from: 'noreply@gitlink.org.cn' + default from: 'GitLink ' # 用户注册验证码 def register_email(mail, code) @@ -9,8 +10,24 @@ class UserMailer < ApplicationMailer mail(to: mail, subject: 'Gitink | 注册验证码') end + # 用户找回密码 + def find_password(mail, code) + @code = code + mail(to: mail, subject: 'Gitink | 找回密码验证码') + end + + # 用户绑定邮箱 + def bind_email(mail, code) + @code = code + mail(to: mail, subject: 'Gitink | 绑定邮箱验证码') + end + def update_email(mail, code) @code = code mail(to: mail, subject: 'Gitink | 更改邮箱验证码') end + + def feedback_email(mail, title, content) + mail(to: mail, subject: title, content_type: "text/html", body: content) + end end diff --git a/app/models/feedback.rb b/app/models/feedback.rb new file mode 100644 index 000000000..2528d4022 --- /dev/null +++ b/app/models/feedback.rb @@ -0,0 +1,21 @@ +# == Schema Information +# +# Table name: feedbacks +# +# id :integer not null, primary key +# user_id :integer +# content :text(65535) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_feedbacks_on_user_id (user_id) +# + +class Feedback < ApplicationRecord + + belongs_to :user + has_many :feedback_message_histories, dependent: :destroy + +end diff --git a/app/models/feedback_message_history.rb b/app/models/feedback_message_history.rb new file mode 100644 index 000000000..90ae185e0 --- /dev/null +++ b/app/models/feedback_message_history.rb @@ -0,0 +1,36 @@ +# == Schema Information +# +# Table name: feedback_message_histories +# +# id :integer not null, primary key +# feedback_id :integer +# user_id :integer +# title :string(255) +# content :text(65535) +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_feedback_message_histories_on_feedback_id (feedback_id) +# index_feedback_message_histories_on_user_id (user_id) +# + +class FeedbackMessageHistory < ApplicationRecord + + belongs_to :feedback + belongs_to :user + + before_validation :send_meessage_email, on: :create + + private + + def send_meessage_email + unless UserMailer.feedback_email(feedback&.user&.mail, title, content).deliver_now + errors[:title] << '邮件发送失败!' + end + rescue + errors[:title] << '邮件发送失败!' + end + +end diff --git a/app/models/message_template.rb b/app/models/message_template.rb index d9ba3eb76..200c2f676 100644 --- a/app/models/message_template.rb +++ b/app/models/message_template.rb @@ -52,6 +52,7 @@ class MessageTemplate < ApplicationRecord email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html") self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 {nickname}/{repository} 仓库,里程碑 {name} 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: 仓库 {nickname}/{repository} 有里程碑已完成") self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '{nickname1} 点赞了你管理的仓库 {nickname2}/{repository}', notification_url: '{baseurl}/{login}') + self.create(type: 'MessageTemplate::ProjectOpenDevOps', sys_notice: '您的仓库 {repository} 已成功开通引擎服务,可通过简单的节点编排完成自动化集成与部署。欢迎体验!', notification_url: '{baseurl}/{owner}/{identifier}/devops') email_html = File.read("#{email_template_html_dir}/project_pull_request.html") self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 {nickname2}/{repository} 提交了一个合并请求:{title}', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求") email_html = File.read("#{email_template_html_dir}/project_role.html") diff --git a/app/models/message_template/project_open_dev_ops.rb b/app/models/message_template/project_open_dev_ops.rb new file mode 100644 index 000000000..b37785351 --- /dev/null +++ b/app/models/message_template/project_open_dev_ops.rb @@ -0,0 +1,28 @@ +# == Schema Information +# +# Table name: message_templates +# +# id :integer not null, primary key +# type :string(255) +# sys_notice :text(65535) +# email :text(65535) +# created_at :datetime not null +# updated_at :datetime not null +# notification_url :string(255) +# email_title :string(255) +# + +# 我管理的仓库项目设置被更改 +class MessageTemplate::ProjectOpenDevOps < MessageTemplate + + # MessageTemplate::ProjectOpenDevOps.get_message_content(User.where(login: 'yystopf')) + def self.get_message_content(receivers, user, project) + return '', '', '' if receivers.blank? + content = sys_notice.gsub('{repository}', project&.name) + url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier) + return receivers_string(receivers), content, url + rescue => e + Rails.logger.info("MessageTemplate::ProjectOpenDevOps.get_message_content [ERROR] #{e}") + return '', '', '' + end +end diff --git a/app/models/open_users/gitee.rb b/app/models/open_users/gitee.rb new file mode 100644 index 000000000..a743eb72c --- /dev/null +++ b/app/models/open_users/gitee.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::Gitee < OpenUser + def nickname + extra&.[]('nickname') + end + + def en_type + 'gitee' + end +end diff --git a/app/models/open_users/github.rb b/app/models/open_users/github.rb new file mode 100644 index 000000000..03c79ba58 --- /dev/null +++ b/app/models/open_users/github.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::Github < OpenUser + def nickname + extra&.[]('name') + end + + def en_type + 'github' + end +end diff --git a/app/models/open_users/qq.rb b/app/models/open_users/qq.rb index ef1a4b470..204e870ec 100644 --- a/app/models/open_users/qq.rb +++ b/app/models/open_users/qq.rb @@ -16,7 +16,7 @@ # index_open_users_on_user_id (user_id) # -class OpenUsers::QQ < OpenUser +class OpenUsers::Qq < OpenUser def nickname extra&.[]('nickname') end diff --git a/app/models/owner.rb b/app/models/owner.rb index b65ee0544..2763dc80f 100644 --- a/app/models/owner.rb +++ b/app/models/owner.rb @@ -68,4 +68,9 @@ class Owner < ApplicationRecord has_many :repositories, foreign_key: :user_id, dependent: :destroy has_many :applied_transfer_projects, dependent: :destroy + scope :like, lambda { |keywords| + sql = "CONCAT(lastname, firstname) LIKE :search OR nickname LIKE :search OR login LIKE :search " + where(sql, :search => "%#{keywords.strip}%") unless keywords.blank? + } + end diff --git a/app/models/project.rb b/app/models/project.rb index 6ce31522c..a8816bd76 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -175,6 +175,9 @@ class Project < ApplicationRecord $redis_cache.srem("v2-project-rank-deleted", self.id) end end + if !self.common? + CacheAsyncClearJob.perform_later('project_rank_service', self.id) + end end def decre_project_common diff --git a/app/models/project_category.rb b/app/models/project_category.rb index 4bba5423e..97a304259 100644 --- a/app/models/project_category.rb +++ b/app/models/project_category.rb @@ -2,14 +2,15 @@ # # Table name: project_categories # -# id :integer not null, primary key -# name :string(255) -# position :integer -# projects_count :integer default("0") -# created_at :datetime not null -# updated_at :datetime not null -# ancestry :string(255) -# pinned_index :integer default("0") +# id :integer not null, primary key +# name :string(255) +# position :integer +# projects_count :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# ancestry :string(255) +# pinned_index :integer default("0") +# private_projects_count :integer default("0") # # Indexes # diff --git a/app/models/user.rb b/app/models/user.rb index 5ed2550b8..df35f3a2f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -114,13 +114,13 @@ class User < Owner # trustie: 来自Trustie平台 # forge: 平台本身注册的用户 # military: 军科的用户 - enumerize :platform, in: [:forge, :educoder, :trustie, :military], default: :forge, scope: :shallow + enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat], default: :forge, scope: :shallow belongs_to :laboratory, optional: true has_one :user_extension, dependent: :destroy has_many :open_users, dependent: :destroy has_one :wechat_open_user, class_name: 'OpenUsers::Wechat' - has_one :qq_open_user, class_name: 'OpenUsers::QQ' + has_one :qq_open_user, class_name: 'OpenUsers::Qq' accepts_nested_attributes_for :user_extension, update_only: true has_many :fork_users, dependent: :destroy @@ -177,6 +177,7 @@ class User < Owner has_one :trace_user, dependent: :destroy has_many :user_trace_tasks, dependent: :destroy + has_many :feedbacks, dependent: :destroy # Groups and active users scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } scope :like, lambda { |keywords| @@ -192,7 +193,8 @@ class User < Owner :show_email, :show_location, :show_department, :super_description, :show_super_description, :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true - before_save :update_hashed_password, :set_lastname + # before_save :update_hashed_password, :set_lastname + before_save :update_hashed_password after_save :reset_cache_data after_create do SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie? @@ -558,17 +560,19 @@ class User < Owner def full_name return '游客' unless logged? - name = show_realname? ? lastname + firstname : nickname - name.blank? ? (nickname.blank? ? login : nickname) : name + # name = show_realname? ? lastname + firstname : nickname + # name.blank? ? (nickname.blank? ? login : nickname) : name + nickname.blank? ? login : nickname end # 用户的真实姓名(不考虑用户是否隐藏了真实姓名,课堂模块都用真实姓名) def real_name return '游客' unless logged? - name = lastname + firstname - name = name.blank? ? (nickname.blank? ? login : nickname) : name + # name = lastname + firstname + # name = name.blank? ? (nickname.blank? ? login : nickname) : name # name.gsub(/\s+/, '').strip #6.11 -hs - name.strip + # name.strip + nickname.blank? ? login : nickname end def only_real_name @@ -701,12 +705,13 @@ class User < Owner end def show_real_name - name = lastname + firstname - if name.blank? - nickname.blank? ? login : nickname - else - name - end + # name = lastname + firstname + # if name.blank? + # nickname.blank? ? login : nickname + # else + # name + # end + nickname.blank? ? login : nickname end def update_hashed_password @@ -787,6 +792,15 @@ class User < Owner login end + # 生成数字账号 + CODES = %W(0 1 2 3 4 5 6 7 8 9) + def self.generate_user_login type + code = CODES.sample(8).join + code = type + code.to_s + return User.generate_user_login(type) if User.where(login: code).present? + code + end + def bind_open_user?(type) case type when 'wechat' then wechat_open_user.present? diff --git a/app/queries/projects/list_query.rb b/app/queries/projects/list_query.rb index da56ceafb..447ab5070 100644 --- a/app/queries/projects/list_query.rb +++ b/app/queries/projects/list_query.rb @@ -12,11 +12,16 @@ class Projects::ListQuery < ApplicationQuery def call collection = Project.visible + # 增加私有组织中项目过滤 + collection = collection.joins("left join organization_extensions on organization_extensions.organization_id = projects.user_id") + .where("organization_extensions.visibility is null or organization_extensions.visibility in (0,1)") + .where("projects.user_id > 0") collection = filter_projects(collection) sort = params[:sort_by] || "updated_on" sort_direction = params[:sort_direction] || "desc" + collection = optimize_sorting(collection, sort) if params[:category_id].present? custom_sort(collection, sort, sort_direction) # scope = scope.reorder("projects.#{sort} #{sort_direction}") @@ -36,10 +41,11 @@ class Projects::ListQuery < ApplicationQuery ids = Projects::ElasticsearchService.call(params[:search]) items = items.where(platform: 'forge') if ids.present? - items.where(id: ids).by_name_or_identifier(params[:search]) + items = items.where(id: ids).by_name_or_identifier(params[:search]) else - items.by_name_or_identifier(params[:search]) + items = items.by_name_or_identifier(params[:search]) end + items.or(items.where(user_id: Owner.like(params[:search]).pluck(:id))) end def by_project_type(items) @@ -57,5 +63,20 @@ class Projects::ListQuery < ApplicationQuery def by_pinned(items) (params[:pinned].present? && params[:category_id].present?) ? items.pinned : items end + + # 优化排序 + def optimize_sorting(relations, sort_by) + if sort_by == "updated_on" + relations.where("projects.updated_on>'2010-01-01'") + elsif sort_by == "created_on" + relations.where("projects.created_on>'2010-01-01'") + elsif sort_by == "forked_count" + relations.where("projects.forked_count>=0") + elsif sort_by == "praises_count" + relations.where("projects.praises_count>=0") + else + relations + end + end end diff --git a/app/services/admins/update_user_service.rb b/app/services/admins/update_user_service.rb index 34f704cbe..9d116cffe 100644 --- a/app/services/admins/update_user_service.rb +++ b/app/services/admins/update_user_service.rb @@ -15,13 +15,14 @@ class Admins::UpdateUserService < ApplicationService user.firstname = '' user.password = params[:password] if params[:password].present? - user.user_extension.assign_attributes(user_extension_attributes) + user.user_extension.assign_attributes(user_extension_attributes) if user.user_extension.present? old_login = user.login ActiveRecord::Base.transaction do user.save! - user.user_extension.save! + user.user_extension.save! if user.user_extension.present? update_gitea_user(old_login) + update_gitea_user_email(user.previous_changes[:mail]) end user @@ -65,4 +66,14 @@ class Admins::UpdateUserService < ApplicationService Util.logger_error(ex) raise Error, '保存失败' end + + def update_gitea_user_email(change_options) + return if change_options.blank? + return if user.gitea_uid.blank? || user.gitea_token.blank? + $gitea_client.delete_user_emails({body: {emails: [change_options[0]]}.to_json, query: {access_token: user.gitea_token}}) + $gitea_client.post_user_emails({body: {emails: [change_options[1]]}.to_json, query: {access_token: user.gitea_token}}) + rescue Exception => ex + Util.logger_error(ex) + raise Error, '保存失败' + end end \ No newline at end of file diff --git a/app/services/api/v1/projects/code_stats/list_service.rb b/app/services/api/v1/projects/code_stats/list_service.rb new file mode 100644 index 000000000..84f4bac36 --- /dev/null +++ b/app/services/api/v1/projects/code_stats/list_service.rb @@ -0,0 +1,34 @@ +class Api::V1::Projects::CodeStats::ListService < ApplicationService + + attr_reader :project, :ref, :owner, :repo, :token + attr_accessor :gitea_data + + def initialize(project, params, token=nil) + @project = project + @ref = params[:ref] + @owner = project&.owner.login + @repo = project&.identifier + @token = token + end + + def call + load_gitea_data + + gitea_data + end + + private + def request_params + param = { + access_token: token + } + param.merge!(ref: ref) if ref.present? + + param + end + + def load_gitea_data + @gitea_data = $gitea_client.get_repos_code_stats_by_owner_repo(owner, repo, {query: request_params}) rescue nil + raise Error, '获取贡献者贡献度失败!' unless @gitea_data.is_a?(Hash) + end +end \ No newline at end of file diff --git a/app/services/api/v1/users/feedbacks/create_service.rb b/app/services/api/v1/users/feedbacks/create_service.rb new file mode 100644 index 000000000..2db4baac2 --- /dev/null +++ b/app/services/api/v1/users/feedbacks/create_service.rb @@ -0,0 +1,26 @@ +class Api::V1::Users::Feedbacks::CreateService < ApplicationService + include ActiveModel::Model + + attr_reader :user, :content + attr_accessor :feedback + + validates :content, presence: true + + def initialize(user, params) + @user = user + @content = params[:content] + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + + begin + @feedback = Feedback.new(user: user, content: content) + @feedback.save! + + return @feedback.valid? ? @feedback : nil + rescue + raise Error, "服务器错误,请联系系统管理员!" + end + end +end \ No newline at end of file diff --git a/app/services/api/v1/users/update_email_service.rb b/app/services/api/v1/users/update_email_service.rb index d17f101fd..bd1b5723c 100644 --- a/app/services/api/v1/users/update_email_service.rb +++ b/app/services/api/v1/users/update_email_service.rb @@ -14,7 +14,7 @@ class Api::V1::Users::UpdateEmailService < ApplicationService @mail = params[:email] @old_mail = user.mail @code = params[:code] - @verify_code = VerificationCode.where(email: @mail, code: @code, code_type: 10).last + @verify_code = VerificationCode.where(email: @mail, code_type: 10).last end def call diff --git a/app/services/api/v1/users/update_phone_service.rb b/app/services/api/v1/users/update_phone_service.rb new file mode 100644 index 000000000..e41178e3d --- /dev/null +++ b/app/services/api/v1/users/update_phone_service.rb @@ -0,0 +1,35 @@ +class Api::V1::Users::UpdatePhoneService < ApplicationService + include ActiveModel::Model + + attr_reader :user, :password, :phone, :code, :verify_code + + validates :password, :code, presence: true + validates :phone, presence: true, format: { with: CustomRegexp::PHONE } + + def initialize(user, params) + @user = user + @password = params[:password] + @phone = params[:phone] + @code = params[:code] + @verify_code = VerificationCode.where(phone: @phone, code_type: 4).last + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + raise Error, "密码不正确." unless @user.check_password?(@password) + exist_owner = Owner.find_by(phone: @phone) + raise Error, "手机号已被使用." if exist_owner + is_debug = @code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试 + raise Error, "验证码不正确." if @verify_code&.code != @code && !is_debug + raise Error, "验证码已失效." if !@verify_code&.effective? && !is_debug + + begin + ActiveRecord::Base.transaction do + @user.update_attributes!({phone: @phone}) + end + return true + rescue + raise Error, "服务器错误,请联系系统管理员!" + end + end +end \ No newline at end of file diff --git a/app/services/gitea/repository/entries/create_service.rb b/app/services/gitea/repository/entries/create_service.rb index 1bdc7246d..14b373335 100644 --- a/app/services/gitea/repository/entries/create_service.rb +++ b/app/services/gitea/repository/entries/create_service.rb @@ -56,7 +56,7 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService when 403 then error("你没有权限操作!") when 404 then error("你操作的链接不存在!") when 422 - if @body[:new_branch].include?('/') || @body[:new_branch].include?('\'') || @body[:new_branch].include?('^') || @body[:new_branch].include?('*') + if @body[:new_branch].present? && (@body[:new_branch].include?('/') || @body[:new_branch].include?('\'') || @body[:new_branch].include?('^') || @body[:new_branch].include?('*')) error("不合法的分支名称!") else error("#{filepath}文件已存在,不能重复创建!") diff --git a/app/services/issues/list_query_service.rb b/app/services/issues/list_query_service.rb index bed8c4837..f7c23ddfd 100644 --- a/app/services/issues/list_query_service.rb +++ b/app/services/issues/list_query_service.rb @@ -17,7 +17,11 @@ class Issues::ListQueryService < ApplicationService issues = all_issues.issue_index_includes issues = issues.includes(pull_request: :reviewers) if status_type.to_s == "2" #表示关闭中的 - issues = issues.where(status_id: 5) + if(select_type == "Issue") + issues = issues.where(status_id: 5) + else + issues = issues.joins(:pull_request).where(pull_requests: {status: 2}) + end elsif status_type.to_s == "1" if(select_type == "Issue") issues = issues.where.not(status_id: 5) #默认显示开启中的 diff --git a/app/services/oauth/create_or_find_qq_account_service.rb b/app/services/oauth/create_or_find_qq_account_service.rb index dafcc3f88..9faaed1fd 100644 --- a/app/services/oauth/create_or_find_qq_account_service.rb +++ b/app/services/oauth/create_or_find_qq_account_service.rb @@ -10,7 +10,7 @@ class Oauth::CreateOrFindQqAccountService < ApplicationService def call new_user = false # 存在该用户 - open_user = OpenUsers::QQ.find_by(uid: params['uid']) + open_user = OpenUsers::Qq.find_by(uid: params['uid']) return [open_user.user, new_user] if open_user.present? if user.blank? || !user.logged? @@ -32,7 +32,7 @@ class Oauth::CreateOrFindQqAccountService < ApplicationService Util.download_file(params.dig('info', 'image'), avatar_path) end - new_open_user = OpenUsers::QQ.create!(user: user, uid: params['uid']) + new_open_user = OpenUsers::Qq.create!(user: user, uid: params['uid']) Rails.cache.write(new_open_user.can_bind_cache_key, 1, expires_in: 1.hours) if new_user # 方便后面进行账号绑定 end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 025883805..2b4523bf5 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -16,6 +16,7 @@ class Projects::CreateService < ApplicationService Project.update_common_projects_count! ProjectUnit.init_types(@project.id) Repositories::CreateService.new(user, @project, repository_params).call + upgrade_project_category_private_projects_count else Rails.logger.info("#############___________create_project_erros______###########{@project.errors.messages}") end @@ -28,6 +29,14 @@ class Projects::CreateService < ApplicationService private + def upgrade_project_category_private_projects_count + # 如果为空或者项目为公有项目直接返回 + return unless params[:project_category_id].present? + return if repo_is_public + project_category = ProjectCategory.find_by_id(params[:project_category_id]) + project_category.increment!(:private_projects_count, 1) + end + def authroize_user_id_success (user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?) end diff --git a/app/services/repositories/migrate_service.rb b/app/services/repositories/migrate_service.rb index cccfaed04..7cf1cb3e7 100644 --- a/app/services/repositories/migrate_service.rb +++ b/app/services/repositories/migrate_service.rb @@ -11,7 +11,7 @@ class Repositories::MigrateService < ApplicationService @repository = Repository.new(repository_params) if @repository.save! @repository.set_mirror! - MigrateRemoteRepositoryJob.perform_later(@repository.id, user.gitea_token, gitea_repository_params) + MigrateRemoteRepositoryJob.perform_later(@repository.id, user.gitea_token, user.id, gitea_repository_params) end @repository rescue => e diff --git a/app/services/sms/ucloud_service.rb b/app/services/sms/ucloud_service.rb new file mode 100644 index 000000000..9edf746a1 --- /dev/null +++ b/app/services/sms/ucloud_service.rb @@ -0,0 +1,112 @@ +class Sms::UcloudService < ApplicationService + attr_reader :phone, :code, :send_type + + def initialize(phone, code, send_type) + @phone = phone + @code = code + @send_type = send_type + end + + def call + public_key = EduSetting.get("ucloud_public_key") || "4Z7QYDY0SumplMtmNmd9PERgPPFiMpR1R" + private_key = EduSetting.get("ucloud_private_key") || "7wxMoGoaQ1DtcQjDxgJrOGOXnIiZq4amEWvmi7eBtm2d" + + project_id = "org-3ozbh2" + sign_params = { + "Action" => "SendUSMSMessage", + "ProjectId" => project_id, + "TemplateId" => get_template_id(@send_type), + "PublicKey" => public_key, + "PhoneNumbers.0" => @phone, + "TemplateParams.0" => "#{@code}", + "SigContent" => "GitLink确实开源" + } + sequence = sign_params.sort.map { |k, v| "#{k}#{v}" }.join('') + # Rails.logger.info("create_signature=========#{sequence}#{private_key}") + req_params = sign_params.merge("Signature" => Digest::SHA1.hexdigest("#{sequence}#{private_key}")) + uri = URI("https://api.ucloud.cn") + uri.query = req_params.map { |k, v| "#{k}=#{URI.escape(v.to_s)}" }.join('&') + # Rails.logger.info("uri.query=========#{uri.query}") + + Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http| + req = Net::HTTP::Get.new uri.request_uri + + response = http.request(req) + # Rails.logger.info("ucloud sms response.body=========#{response.body}") + result = ActiveSupport::JSON.decode(response.body) + result['RetCode'] + end + end + + def send_by_params(opt={}) + public_key = "4Z7QYDY0SumplMtmNmd9PERgPPFiMpRR" + private_key = "7wxMoGoaQ1DtcQjDxgJrOGOXnIiZq4amEWvmi7eBtmd" + + project_id = "org-3ozbh2" + sign_params = { + "Action" => "SendUSMSMessage", + "ProjectId" => project_id, + "TemplateId" => "#{opt[:TemplateId]}", + "PublicKey" => public_key, + "PhoneNumbers.0" => "#{opt[:PhoneNumbers]}", + "TemplateParams.0" => "#{opt[:TemplateParams]}", + "SigContent" => "GitLink确实开源" + } + sequence = sign_params.sort.map { |k, v| "#{k}#{v}" }.join('') + # Rails.logger.info("create_signature=========#{sequence}#{private_key}") + req_params = sign_params.merge("Signature" => Digest::SHA1.hexdigest("#{sequence}#{private_key}")) + uri = URI("https://api.ucloud.cn") + uri.query = req_params.map { |k, v| "#{k}=#{URI.escape(v.to_s)}" }.join('&') + # Rails.logger.info("uri.query=========#{uri.query}") + + Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http| + req = Net::HTTP::Get.new uri.request_uri + + response = http.request(req) + # Rails.logger.info("ucloud sms response.body=========#{response.body}") + ActiveSupport::JSON.decode(response.body) + end + end + + def send_sms(template_id) + + end + + def GetProjectList + public_key = "4Z7QYDY0SumplMtmNmd9PERgPPFiMpRR" + private_key = "7wxMoGoaQ1DtcQjDxgJrOGOXnIiZq4amEWvmi7eBtmd" + + sign_params = { + "Action" => "GetProjectList", + "PublicKey" => public_key + } + sequence = sign_params.sort.map { |k, v| "#{k}#{v}" }.join('') + Rails.logger.info("create_signature=========#{sequence}#{private_key}") + req_params = sign_params.merge("Signature" => Digest::SHA1.hexdigest("#{sequence}#{private_key}")) + uri = URI("https://api.ucloud.cn") + uri.query = req_params.map { |k, v| "#{k}=#{URI.escape(v.to_s)}" }.join('&') + Rails.logger.info("uri.query=========#{uri.query}") + + Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http| + req = Net::HTTP::Get.new uri.request_uri + + response = http.request(req) + Rails.logger.info("ucloud sms response.body=========#{response.body}") + response.body + end + end + + + # 1:注册手机验证码 2:找回密码手机验证码 4:绑定手机 9:验证手机号有效 + def get_template_id(send_type) + case send_type + when 1, 2, 9 + "UTA221114S2MGTY" + when 4 + "UTA22112486FXLZ" + else + "UTA221114S2MGTY" + end + end + +end diff --git a/app/views/admins/feedbacks/_history_form_modal.html.erb b/app/views/admins/feedbacks/_history_form_modal.html.erb new file mode 100644 index 000000000..df12a73d3 --- /dev/null +++ b/app/views/admins/feedbacks/_history_form_modal.html.erb @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/app/views/admins/feedbacks/_list.html.erb b/app/views/admins/feedbacks/_list.html.erb new file mode 100644 index 000000000..1b7b045ed --- /dev/null +++ b/app/views/admins/feedbacks/_list.html.erb @@ -0,0 +1,46 @@ + + + + + + + + + + + + + <% if feedbacks.present? %> + <% feedbacks.each_with_index do |feedback, index| %> + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号用户名用户邮箱<%= sort_tag('创建时间', name: 'created_at', path: admins_feedbacks_path) %>反馈意见操作
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: feedbacks } %> + + \ No newline at end of file diff --git a/app/views/admins/feedbacks/index.html.erb b/app/views/admins/feedbacks/index.html.erb new file mode 100644 index 000000000..391c83ca6 --- /dev/null +++ b/app/views/admins/feedbacks/index.html.erb @@ -0,0 +1,9 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('反馈意见') %> +<% end %> + +
+ <%= render partial: 'admins/feedbacks/list', locals: { feedbacks: @feedbacks } %> +
+
+
diff --git a/app/views/admins/feedbacks/index.js.erb b/app/views/admins/feedbacks/index.js.erb new file mode 100644 index 000000000..daaa24cc7 --- /dev/null +++ b/app/views/admins/feedbacks/index.js.erb @@ -0,0 +1 @@ +$('.feedback-list-container').html("<%= j( render partial: 'admins/feedbacks/list', locals: { feedbacks: @feedbacks } ) %>"); \ No newline at end of file diff --git a/app/views/admins/feedbacks/new_history.js.erb b/app/views/admins/feedbacks/new_history.js.erb new file mode 100644 index 000000000..c795b0f5b --- /dev/null +++ b/app/views/admins/feedbacks/new_history.js.erb @@ -0,0 +1,3 @@ +$("#feedback-modals").html("<%= j render(partial: 'admins/feedbacks/history_form_modal', locals: {type: 'new_history'}) %>") +$(".feedback-history-change-modal").modal('show'); +createMDEditor('feedback-history-email-editor', {width: 750, height: 300, placeholder: '请输入邮件正文',watch: false, imageUpload: false }); diff --git a/app/views/admins/project_categories/_list.html.erb b/app/views/admins/project_categories/_list.html.erb index 1a1626bc4..c4b70f52d 100644 --- a/app/views/admins/project_categories/_list.html.erb +++ b/app/views/admins/project_categories/_list.html.erb @@ -4,7 +4,8 @@ 序号 名称 <%= sort_tag('精选', name: 'pinned_index', path: admins_project_categories_path) %> - <%= sort_tag('项目数', name: 'projects_count', path: admins_project_categories_path) %> + <%= sort_tag('项目数', name: 'projects_count', path: admins_project_categories_path) %> + <%= sort_tag('私有项目数', name: 'private_projects_count', path: admins_project_categories_path) %> 精选项目数 <%= sort_tag('创建时间', name: 'created_at', path: admins_project_categories_path) %> 操作 @@ -20,6 +21,7 @@ <%= project_category.pinned_index == 0 ? "" : "√" %> <%= project_category.projects_count %> + <%= project_category.private_projects_count %> <%= project_category.projects.select(:id).where(is_pinned: true).size %> <%= project_category.created_at&.strftime('%Y-%m-%d %H:%M') %> diff --git a/app/views/admins/projects/shared/_list.html.erb b/app/views/admins/projects/shared/_list.html.erb index 720b08dac..eb0e61255 100644 --- a/app/views/admins/projects/shared/_list.html.erb +++ b/app/views/admins/projects/shared/_list.html.erb @@ -5,7 +5,6 @@ ID 项目名称 公开 - 精选 推荐 Issues 资源 @@ -27,7 +26,6 @@ <%= link_to(project.name, "/#{project&.owner&.login}/#{project.identifier}", target: '_blank') %> <%= project.is_public ? '√' : '' %> - <%= project.is_pinned ? '√' : '' %> <%= project.recommend ? '√' : '' %> <%= project.issues.size %> <%= project.attachments.size %> @@ -40,8 +38,6 @@ <%= project.created_on&.strftime('%Y-%m-%d %H:%M') %> <% if project.is_public %> - <%= javascript_void_link '精选', class: 'action pinned-action', data: { id: project.id }, style: project.is_pinned ? 'display: none;' : '' %> - <%= javascript_void_link '取消精选', class: 'action unpinned-action', data: { id: project.id }, style: project.is_pinned ? '' : 'display: none;' %> <%= javascript_void_link '推荐', class: 'action recommend-action', data: { id: project.id }, style: project.recommend ? 'display: none;' : '' %> <%= javascript_void_link '取消推荐', class: 'action unrecommend-action', data: { id: project.id }, style: project.recommend ? '' : 'display: none;' %> <%= link_to "设置推荐等级", edit_admins_project_path(project.id), remote: true, class: "action edit-recommend-action", style: project.recommend ? '' : 'display: none;' %> diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 9a87980b0..afd0dad68 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -56,6 +56,7 @@ <%= sidebar_item_group('#setting-submenu', '网站建设', icon: 'cogs') do %>
  • <%= sidebar_item(admins_faqs_path, 'FAQ', icon: 'question-circle', controller: 'admins-faqs') %>
  • <%= sidebar_item(admins_nps_path, 'NPS用户调研', icon: 'question-circle', controller: 'admins-nps') %>
  • +
  • <%= sidebar_item(admins_feedbacks_path, '用户反馈', icon: 'question-circle', controller: 'admins-feedbacks') %>
  • <% end %>
  • diff --git a/app/views/admins/topic/banners/_form_modal.html.erb b/app/views/admins/topic/banners/_form_modal.html.erb index 20bca80c6..845b17027 100644 --- a/app/views/admins/topic/banners/_form_modal.html.erb +++ b/app/views/admins/topic/banners/_form_modal.html.erb @@ -15,6 +15,12 @@ <%= p.text_field :title,class: "form-control input-lg",required: true%> +
    + + <%= p.text_field :url, class: "form-control",placeholder: ""%> +
    -
    +
    <%= f.label :technical_title, label: '职称' %> <%= select_tag('user[technical_title]', [], class: 'form-control technical-title-select optional', 'data-value': @user.technical_title) %>
    - <%= f.input :student_id, as: :tel, label: '学号', wrapper_html: { class: 'col-md-2', style: @user.user_extension.student? ? '' : 'display:none;' }, input_html: { class: 'student-id-input' } %> + <%= f.input :student_id, as: :tel, label: '学号', wrapper_html: { class: 'col-md-2', style: @user&.user_extension&.student? ? '' : 'display:none;' }, input_html: { class: 'student-id-input' } %>
    diff --git a/app/views/admins/users/shared/_user_list.html.erb b/app/views/admins/users/shared/_user_list.html.erb index 16cd403de..716e7cc54 100644 --- a/app/views/admins/users/shared/_user_list.html.erb +++ b/app/views/admins/users/shared/_user_list.html.erb @@ -27,7 +27,7 @@ <%= user.identity %> <%= display_text(user.created_on&.strftime('%Y-%m-%d %H:%M')) %> <%= display_text(user.last_login_on&.strftime('%Y-%m-%d %H:%M')) %> - <%= link_to user.projects_count, "/users/#{user.login}/projects", target: "_blank" %> + <%= link_to user.projects_count, "/#{user.login}/projects", target: "_blank" %> <%= link_to '编辑', edit_admins_user_path(user), class: 'action' %> diff --git a/app/views/api/v1/projects/code_stats/index.json.jbuilder b/app/views/api/v1/projects/code_stats/index.json.jbuilder new file mode 100644 index 000000000..0b64270f7 --- /dev/null +++ b/app/views/api/v1/projects/code_stats/index.json.jbuilder @@ -0,0 +1,14 @@ +json.author_count @result_object["author_count"] +json.commit_count @result_object["commit_count"] +json.change_files @result_object["change_files"] +json.additions @result_object["additions"] +json.deletions @result_object["deletions"] +json.commit_count_in_all_branches @result_object["commit_count_in_all_branches"] +json.authors @result_object["authors"].each do |author| + json.author do + json.partial! 'api/v1/users/commit_user_email', locals: { user: render_cache_commit_author(author), name: author['name'], email: author['email'] } + end + json.commits author["commits"] + json.additions author["additions"] + json.deletions author["deletions"] +end \ No newline at end of file diff --git a/app/views/api/v1/users/_commit_user_email.json.jbuilder b/app/views/api/v1/users/_commit_user_email.json.jbuilder new file mode 100644 index 000000000..c4963628a --- /dev/null +++ b/app/views/api/v1/users/_commit_user_email.json.jbuilder @@ -0,0 +1,22 @@ +if user.present? + if user.is_a?(Hash) + json.id user["id"] + json.login user["login"] + json.name user["name"] + json.type user["type"] + json.image_url user["avatar_url"] + else + json.id user.id + json.login user.login + json.name user.real_name + json.type user&.type + json.image_url url_to_avatar(user) + end +else + json.id nil + json.login name + json.name name + json.email email + json.type nil + json.image_url User::Avatar.get_letter_avatar_url(name) +end diff --git a/app/views/bind_users/create.json.jbuilder b/app/views/bind_users/create.json.jbuilder new file mode 100644 index 000000000..7223be386 --- /dev/null +++ b/app/views/bind_users/create.json.jbuilder @@ -0,0 +1,9 @@ +json.status 0 +json.username @user.full_name +json.real_name @user.real_name +json.login @user.login +json.user_id @user.id +json.image_url url_to_avatar(@user) +json.admin @user.admin? +json.user_identity @user.identity +json.is_watch current_user&.watched?(@user) \ No newline at end of file diff --git a/app/views/issue_tags/index.json.jbuilder b/app/views/issue_tags/index.json.jbuilder index 7f20a4374..37bd51608 100644 --- a/app/views/issue_tags/index.json.jbuilder +++ b/app/views/issue_tags/index.json.jbuilder @@ -4,6 +4,7 @@ json.user_admin_or_member @user_admin_or_member json.issue_tags do json.array! @issue_tags.each.to_a do |tag| - json.extract! tag, :id, :name, :description, :color, :issues_count, :project_id, :gid, :gitea_url + json.extract! tag, :id, :name, :description, :color, :project_id, :gid, :gitea_url + json.issues_count tag.issues_count - tag.issues.closed.size end end \ No newline at end of file diff --git a/app/views/organizations/organization_users/index.json.jbuilder b/app/views/organizations/organization_users/index.json.jbuilder index 361c3f242..9f1f278bc 100644 --- a/app/views/organizations/organization_users/index.json.jbuilder +++ b/app/views/organizations/organization_users/index.json.jbuilder @@ -1,4 +1,5 @@ json.total_count @organization_users.total_count json.organization_users @organization_users do |org_user| + next if org_user.user.blank? json.partial! "detail", org_user: org_user, organization: @organization end diff --git a/app/views/project_categories/group_list.json.jbuilder b/app/views/project_categories/group_list.json.jbuilder index f13d6ecff..cc26276f5 100644 --- a/app/views/project_categories/group_list.json.jbuilder +++ b/app/views/project_categories/group_list.json.jbuilder @@ -1,5 +1,5 @@ json.array! @project_categories do |category| json.id category.id json.name category.name - json.projects_count category.projects_count + json.projects_count category.public_projects_count end diff --git a/app/views/projects/index.json.jbuilder b/app/views/projects/index.json.jbuilder index 874f60974..31d0db9c5 100644 --- a/app/views/projects/index.json.jbuilder +++ b/app/views/projects/index.json.jbuilder @@ -1,4 +1,4 @@ -json.total_count @projects.total_count +json.total_count @total_count json.projects @projects do |project| # json.partial! "/projects/project_detail", project: project json.id project.id @@ -22,7 +22,7 @@ json.projects @projects do |project| project_educoder = project.project_educoder json.name project_educoder&.owner json.login project_educoder&.repo_name.split('/')[0] - json.image_url render_educoder_avatar_url(project.project_educoder) + # json.image_url render_educoder_avatar_url(project.project_educoder) else user = project.owner json.type user.type diff --git a/app/views/repositories/_simple_entry.json.jbuilder b/app/views/repositories/_simple_entry.json.jbuilder index d11d9af43..8adcaeb83 100644 --- a/app/views/repositories/_simple_entry.json.jbuilder +++ b/app/views/repositories/_simple_entry.json.jbuilder @@ -2,7 +2,7 @@ if @project.forge? is_dir = @sub_entries.is_a?(Array) file_name = entry['name'] file_type = File.extname(file_name.to_s)[1..-1] - direct_download = download_type(file_type) + direct_download = file_name.to_s.downcase != "Makefile".downcase && download_type(file_type) image_type = image_type?(file_type) json.name file_name json.sha entry['sha'] diff --git a/app/views/settings/show.json.jbuilder b/app/views/settings/show.json.jbuilder index abe8207eb..be79dc594 100644 --- a/app/views/settings/show.json.jbuilder +++ b/app/views/settings/show.json.jbuilder @@ -61,6 +61,7 @@ json.setting do json.common @common json.third_party @third_party + json.third_party_new @third_party_new if @top_system_notification.present? json.system_notification do diff --git a/app/views/topics/_banner.json.jbuilder b/app/views/topics/_banner.json.jbuilder index 01fa7c9a2..a458c1800 100644 --- a/app/views/topics/_banner.json.jbuilder +++ b/app/views/topics/_banner.json.jbuilder @@ -1 +1 @@ -json.(banner, :id, :title, :image) \ No newline at end of file +json.(banner, :id, :title, :image, :url) \ No newline at end of file diff --git a/app/views/user_mailer/bind_email.html.erb b/app/views/user_mailer/bind_email.html.erb new file mode 100644 index 000000000..a4bfa0b72 --- /dev/null +++ b/app/views/user_mailer/bind_email.html.erb @@ -0,0 +1,62 @@ + + + + GitLink-验证码发送 + + + + + +
    +
    +
    + + 确实开源 + +
    +
    +
    +

    + 您好! +

    +

    + 您正在GitLink绑定邮箱,请在10分钟内输入此验证码,并进行下一步操作。 + 如非你本人操作,请忽略此邮件。 +

    +
    +
    +

    <%= @code %>

    +
    + + 此邮件为系统所发,请勿直接回复。
    + 要解决问题或了解您的帐户详情,您可以访问 帮助中心。 +
    +
    +

    + 如果您并未发过此请求,则可能是因为其他用户误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。 +

    +
    + +
    +
    + + diff --git a/app/views/user_mailer/find_password.html.erb b/app/views/user_mailer/find_password.html.erb new file mode 100644 index 000000000..a64ad6288 --- /dev/null +++ b/app/views/user_mailer/find_password.html.erb @@ -0,0 +1,62 @@ + + + + GitLink-验证码发送 + + + + + +
    +
    +
    + + 确实开源 + +
    +
    +
    +

    + 您好! +

    +

    + 您正在GitLink找回密码,请在10分钟内输入此验证码,并进行下一步操作。 + 如非你本人操作,请忽略此邮件。 +

    +
    +
    +

    <%= @code %>

    +
    + + 此邮件为系统所发,请勿直接回复。
    + 要解决问题或了解您的帐户详情,您可以访问 帮助中心。 +
    +
    +

    + 如果您并未发过此请求,则可能是因为其他用户误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。 +

    +
    + +
    +
    + + diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index be27eb932..68bfa6589 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -11,7 +11,7 @@ json.user_identity @user.identity json.tidding_count 0 json.user_phone_binded @user.phone.present? json.need_edit_info @user.need_edit_info? -# json.phone @user.phone +json.phone @user.phone # json.email @user.mail json.profile_completed @user.profile_is_completed? json.professional_certification @user.professional_certification diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 3eed48c20..809650ae9 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,21 +1,28 @@ -OmniAuth.config.add_camelization 'qq', 'QQ' +config = Rails.application.config_for(:configuration) + +OmniAuth.config.add_camelization 'qq', 'QQ' if config.dig("oauth", "qq") +# OmniAuth.config.add_camelization 'github', 'GitHub' if config.dig("oauth", "github") +# OmniAuth.config.add_camelization 'gitee', 'Gitee' if config.dig("oauth", "gitee") +# OmniAuth.config.add_camelization 'wechat', 'Wechat' if config.dig("oauth", "wechat") OmniAuth.config.logger = Rails.logger +OmniAuth.config.allowed_request_methods = %i[get post] +OmniAuth.config.before_request_phase = nil +OmniAuth.config.before_callback_phase = nil OmniAuth.config.on_failure = Proc.new { |env| OmniAuth::FailureEndpoint.new(env).redirect_to_failure } -oauth_config = {} -begin - config = Rails.application.config_for(:configuration) - oauth_config = config.dig('oauth', 'qq') - raise 'oauth qq config missing' if oauth_config.blank? -rescue => ex - raise ex if Rails.env.production? - - puts %Q{\033[33m [warning] qq oauth config or configuration.yml missing, - please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} -end - Rails.application.config.middleware.use OmniAuth::Builder do - provider :qq, oauth_config['appid'], oauth_config['secret'], { provider_ignores_state: true } + if config.dig("oauth", "qq") + provider :qq, config.dig("oauth", "qq", "appid"), config.dig("oauth", "qq", "secret"), { provider_ignores_state: true } + end + if config.dig("oauth", "github").present? + provider :github, config.dig("oauth", "github", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true, scope: "user:email" } + end + if config.dig("oauth", "gitee").present? + provider :gitee, config.dig("oauth", "gitee", "appid"), config.dig("oauth", "gitee", "secret"), { provider_ignores_state: true, scope: "user_info emails" } + end + if config.dig("oauth", "wechat").present? + provider :wechat, config.dig("oauth", "wechat", "appid"), config.dig("oauth", "wechat", "secret"), { provider_ignores_state: true, scope: "snsapi_login" } + end end diff --git a/config/initializers/per_form_csrf_tokens.rb b/config/initializers/per_form_csrf_tokens.rb new file mode 100644 index 000000000..5afb75e59 --- /dev/null +++ b/config/initializers/per_form_csrf_tokens.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Be sure to restart your server when you modify this file. + +# Enable per-form CSRF tokens. +# Rails.application.config.action_controller.per_form_csrf_tokens = true +# Rails.application.config.action_controller.forgery_protection_origin_check = true \ No newline at end of file diff --git a/config/locales/forms/api_v1_service.zh-CN.yml b/config/locales/forms/api_v1_service.zh-CN.yml new file mode 100644 index 000000000..268cdc5c4 --- /dev/null +++ b/config/locales/forms/api_v1_service.zh-CN.yml @@ -0,0 +1,5 @@ +'zh-CN': + activemodel: + attributes: + api/v1/users/feedbacks/create_service: + content: "反馈意见" \ No newline at end of file diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 623a4d1c9..e7c586417 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -231,6 +231,8 @@ zh-CN: ignore: name: 'git忽略文件名称' content: 'git忽略文件内容' + feedback_message_history: + title: '' close_pr: 合并请求 roles: Developer: 开发者 diff --git a/config/routes.rb b/config/routes.rb index 1185abd86..22773794c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -20,9 +20,10 @@ Rails.application.routes.draw do get 'attachments/download/:id', to: 'attachments#show' get 'attachments/download/:id/:filename', to: 'attachments#show' - get 'auth/qq/callback', to: 'oauth/qq#create' + # get 'auth/qq/callback', to: 'oauth/qq#create' get 'auth/failure', to: 'oauth/base#auth_failure' get 'auth/cas/callback', to: 'oauth/cas#create' + get 'auth/:provider/callback', to: 'oauth/callbacks#create' get 'oauth/bind', to: 'oauth/educoder#bind' get 'oauth/register', to: 'oauth#register' @@ -267,6 +268,7 @@ Rails.application.routes.draw do get :trustie_related_projects post :sync_user_info get :email_search + post :action scope '/ci', module: :ci do scope do @@ -942,6 +944,10 @@ Rails.application.routes.draw do resources :nps do post :switch_change, on: :collection end + resources :feedbacks, only: [:index, :destroy] do + get :new_history, on: :member + post :create_history, on: :member + end resources :laboratories, only: [:index, :create, :destroy, :update] do member do get :shixuns_for_select diff --git a/config/routes/api.rb b/config/routes/api.rb index ab098b1dc..7e9504401 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -8,11 +8,14 @@ defaults format: :json do post :check_password post :check_email post :check_email_verify_code + post :check_phone_verify_code patch :update_email + patch :update_phone end end scope module: :users do resources :projects, only: [:index] + resources :feedbacks, only: [:create] end scope ':repo' do @@ -51,6 +54,7 @@ defaults format: :json do end end resources :commits, only: [:index] + resources :code_stats, only: [:index] get '/commits/:sha/diff', to: 'commits#diff' get '/git/blobs/:sha', to: 'git#blobs' get '/git/trees/:sha', to: 'git#trees' diff --git a/db/migrate/20221108024322_create_feedbacks.rb b/db/migrate/20221108024322_create_feedbacks.rb new file mode 100644 index 000000000..316df6b05 --- /dev/null +++ b/db/migrate/20221108024322_create_feedbacks.rb @@ -0,0 +1,10 @@ +class CreateFeedbacks < ActiveRecord::Migration[5.2] + def change + create_table :feedbacks do |t| + t.references :user + t.text :content + + t.timestamps + end + end +end diff --git a/db/migrate/20221108100538_create_feedback_message_histories.rb b/db/migrate/20221108100538_create_feedback_message_histories.rb new file mode 100644 index 000000000..cd5f236df --- /dev/null +++ b/db/migrate/20221108100538_create_feedback_message_histories.rb @@ -0,0 +1,12 @@ +class CreateFeedbackMessageHistories < ActiveRecord::Migration[5.2] + def change + create_table :feedback_message_histories do |t| + t.references :feedback + t.references :user + t.string :title + t.text :content + + t.timestamps + end + end +end diff --git a/db/migrate/20221115032403_add_private_projects_count_to_project_category.rb b/db/migrate/20221115032403_add_private_projects_count_to_project_category.rb new file mode 100644 index 000000000..8d2d92ffd --- /dev/null +++ b/db/migrate/20221115032403_add_private_projects_count_to_project_category.rb @@ -0,0 +1,5 @@ +class AddPrivateProjectsCountToProjectCategory < ActiveRecord::Migration[5.2] + def change + add_column :project_categories, :private_projects_count, :integer, default: 0 + end +end diff --git a/db/migrate/20221123023450_update_user_nick_name.rb b/db/migrate/20221123023450_update_user_nick_name.rb new file mode 100644 index 000000000..0759f9291 --- /dev/null +++ b/db/migrate/20221123023450_update_user_nick_name.rb @@ -0,0 +1,23 @@ +class UpdateUserNickName < ActiveRecord::Migration[5.2] + def change + execute("ALTER TABLE `users` MODIFY `nickname` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `open_users` MODIFY `extra` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + execute("ALTER TABLE `issues` MODIFY `subject` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `issues` MODIFY `description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + execute("ALTER TABLE `projects` MODIFY `description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `project_details` MODIFY `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + execute("ALTER TABLE `journals` MODIFY `notes` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `journal_details` MODIFY `old_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `journal_details` MODIFY `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + execute("ALTER TABLE `claims` MODIFY `note` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + execute("ALTER TABLE `commit_logs` MODIFY `message` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + execute("ALTER TABLE `user_extensions` MODIFY `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + + end +end diff --git a/db/migrate/20221124111351_update_pull_request_utf_name.rb b/db/migrate/20221124111351_update_pull_request_utf_name.rb new file mode 100644 index 000000000..6d0fd2fec --- /dev/null +++ b/db/migrate/20221124111351_update_pull_request_utf_name.rb @@ -0,0 +1,16 @@ +class UpdatePullRequestUtfName < ActiveRecord::Migration[5.2] + def change + execute("ALTER TABLE `projects` MODIFY `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `pull_requests` MODIFY `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `pull_requests` MODIFY `body` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `organization_extensions` MODIFY `description` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `version_releases` MODIFY `name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `version_releases` MODIFY `body` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `version_releases` MODIFY `tag_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `versions` MODIFY `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `versions` MODIFY `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `issue_tags` MODIFY `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `issue_tags` MODIFY `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + execute("ALTER TABLE `projects_activity` MODIFY `project_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + end +end diff --git a/db/migrate/20221207128751_update_user_super.rb b/db/migrate/20221207128751_update_user_super.rb new file mode 100644 index 000000000..9f9cd2087 --- /dev/null +++ b/db/migrate/20221207128751_update_user_super.rb @@ -0,0 +1,5 @@ +class UpdateUserSuper < ActiveRecord::Migration[5.2] + def change + execute("ALTER TABLE `user_extensions` MODIFY `super_description` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") + end +end diff --git a/public/123.html b/public/123.html deleted file mode 100644 index e69de29bb..000000000