diff --git a/Gemfile b/Gemfile index 48fc0069..d573a4cc 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 a418c5f3..4a104129 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 00000000..ff64ae5a --- /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 8d48892b..c0350e35 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 00000000..7ec671f3 --- /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 00000000..4e79de7b --- /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 3c6bec6a..3a750b51 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 eaffdeca..7490cb27 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 1f5d5f45..63427aa4 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 329ade86..f5ed3380 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 86ab175e..c0e8d01c 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 e1b7dee2..06c00508 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 011735ff..da9f16f7 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 6956c9ce..25cfa97d 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 00000000..72885e7d --- /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 0ae11359..10aaa1ae 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 67a040fe..f6b3cbc9 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 7bd62987..5cea074f 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 68c4e59f..53f6d1ae 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 e81b6880..2b9bbbe6 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 f3eedd0a..def2e2c8 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 6eaa5bc9..40540e5e 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 c70f053f..33fd93f8 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 36d9d6f5..9a4d1855 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 f7029c1c..69491282 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 38981352..cf753767 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 48814191..5e56901a 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 00000000..64115f25 --- /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 557d4d0f..763708c3 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 9d93d314..1dcb2cfd 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 19f56518..28bbccf6 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 00000000..2528d402 --- /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 00000000..90ae185e --- /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 d9ba3eb7..200c2f67 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 00000000..b3778535 --- /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 00000000..a743eb72 --- /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 00000000..03c79ba5 --- /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 ef1a4b47..204e870e 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 b65ee054..2763dc80 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 6ce31522..a8816bd7 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 4bba5423..97a30425 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 5ed2550b..df35f3a2 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 da56ceaf..447ab507 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 34f704cb..9d116cff 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 00000000..84f4bac3 --- /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 00000000..2db4baac --- /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 d17f101f..bd1b5723 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 00000000..e41178e3 --- /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 1bdc7246..14b37333 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 bed8c483..f7c23ddf 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 dafcc3f8..9faaed1f 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 02588380..2b4523bf 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 cccfaed0..7cf1cb3e 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 00000000..9edf746a --- /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 00000000..df12a73d --- /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 00000000..1b7b045e --- /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 00000000..391c83ca --- /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 00000000..daaa24cc --- /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 00000000..c795b0f5 --- /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 1a1626bc..c4b70f52 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 720b08da..eb0e6125 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 9a87980b..afd0dad6 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 20bca80c..845b1702 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 16cd403d..716e7cc5 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 00000000..0b64270f --- /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 00000000..c4963628 --- /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 00000000..7223be38 --- /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 7f20a437..37bd5160 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 361c3f24..9f1f278b 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 f13d6ecf..cc26276f 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 874f6097..31d0db9c 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 d11d9af4..8adcaeb8 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 abe8207e..be79dc59 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 01fa7c9a..a458c180 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 00000000..a4bfa0b7 --- /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 00000000..a64ad628 --- /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 be27eb93..68bfa658 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 3eed48c2..809650ae 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 00000000..5afb75e5 --- /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 00000000..268cdc5c --- /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 623a4d1c..e7c58641 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 1185abd8..22773794 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 ab098b1d..7e950440 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 00000000..316df6b0 --- /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 00000000..cd5f236d --- /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 00000000..8d2d92ff --- /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 00000000..0759f929 --- /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 00000000..6d0fd2fe --- /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 00000000..9f9cd208 --- /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 e69de29b..00000000