diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index ad1251d2..e76dbf81 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -181,6 +181,7 @@ class AccountsController < ApplicationController user = Users::RegisterService.call(register_params) user.company_name = params[:company_name] if params[:company_name].present? user.user_type = params[:user_type] if params[:user_type].present? + user.professional_field = params[:professional_field] if params[:professional_field].present? user.mail = "#{user.login}@example.org" password = register_params[:password].strip diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 55f5cfb2..37a41ff7 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,6 +1,78 @@ class Api::V1::UsersController < Api::V1::BaseController - def index - render_ok + before_action :load_observe_user + before_action :check_auth_for_observe_user + + def send_email_vefify_code + code = %W(0 1 2 3 4 5 6 7 8 9) + verification_code = code.sample(6).join + mail = params[:email] + code_type = params[:code_type] + + sign = Digest::MD5.hexdigest("#{OPENKEY}#{mail}") + Rails.logger.info sign + + tip_exception(501, "请求不合理") if sign != params[:smscode] + + # 60s内不能重复发送 + send_email_limit_cache_key = "send_email_60_second_limit:#{mail}" + tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) + send_email_control = LimitForbidControl::SendEmailCode.new(mail) + tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? + begin + UserMailer.update_email(mail, verification_code).deliver_now + + Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) + send_email_control.increment! + rescue Exception => e + logger_error(e) + tip_exception(-2,"邮件发送失败,请稍后重试") + end + ver_params = {code_type: code_type, code: verification_code, email: mail} + data = VerificationCode.new(ver_params) + if data.save! + render_ok + else + tip_exception(-1, "创建数据失败") + end + end + + def check_password + password = params[:password] + return render_error("8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD + return render_error("密码错误") unless @observe_user.check_password?(password) + render_ok + end + + def check_email + mail = strip(params[:email]) + return render_error("邮件格式有误") unless mail =~ CustomRegexp::EMAIL + + exist_owner = Owner.find_by(mail: mail) + return render_error('邮箱已被使用') if exist_owner + render_ok + end + + def check_email_verify_code + code = strip(params[:code]) + mail = strip(params[:email]) + code_type = params[:code_type] + + return render_error("邮件格式有误") unless mail =~ CustomRegexp::EMAIL + + verifi_code = VerificationCode.where(email: mail, code: code, code_type: code_type).last + + return render_error("验证码不正确") if verifi_code&.code != code + return render_error("验证码已失效") 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 + return render_ok + else + return render_error('更改邮箱失败!') + end end end \ No newline at end of file diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index d413879a..f74da636 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -31,13 +31,11 @@ class AttachmentsController < ApplicationController def get_file normal_status(-1, "参数缺失") if params[:download_url].blank? - download_url = params[:download_url].to_s - download_url = download_url.gsub("http:", "https:") if base_url.include?("https:") - url = URI.encode(download_url) + 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) domain = GiteaService.gitea_config[:domain] api_url = GiteaService.gitea_config[:base_url] - url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?') + url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?') request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join response = Faraday.get(request_url) filename = url.to_s.split("/").pop() diff --git a/app/controllers/competition_infos_controller.rb b/app/controllers/competition_infos_controller.rb index e495de81..5b7f1eb2 100644 --- a/app/controllers/competition_infos_controller.rb +++ b/app/controllers/competition_infos_controller.rb @@ -3,12 +3,13 @@ class CompetitionInfosController < ApplicationController before_action :find_competition, only: [:show, :edit, :update, :update_zone_or_sub, :enroll, :upload, :enroll_status, :statistics, :enroll_list, :ranking_list, :enroll_update, :enroll_status_update, :upload_enroll_template, :enroll_template, :online_switch] - before_action :require_admin, only: [:index, :new, :edit, :create] + before_action :require_admin, only: [:new, :edit, :create] before_action :check_competition_manager, only: [:update, :enroll_status_update] def index competition_infos = CompetitionInfo.order(created_at: :desc) - competition_infos = competition_infos.where("title like ?", "%#{params[:name]}%") if params[:name].present? + competition_infos = competition_infos.where("competition_infos.title like ?", "%#{params[:name]}%") if params[:name].present? + competition_infos = competition_infos.joins(:watchers).where(watchers: { user_id: current_user.id }) if params[:category].to_s == "watched" @competition_infos = paginate(competition_infos) respond_to do |format| format.html @@ -19,7 +20,7 @@ class CompetitionInfosController < ApplicationController def recommend sort_direction = ["asc", "desc"].include?(params[:sort_direction].to_s) ? params[:sort_direction] : "desc" sort_by = "created_at" - competition_infos = CompetitionInfo.where(status: true).order(created_at: :desc) + competition_infos = CompetitionInfo.where(status: true) competition_infos = competition_infos.where("title like ?", "%#{params[:name]}%") if params[:name].present? @total_count= competition_infos.count if params[:sort_by].to_s == "hot" @@ -201,6 +202,7 @@ class CompetitionInfosController < ApplicationController end def show + @competition_info.increment!(:visits) end def enroll_status_update @@ -323,7 +325,7 @@ class CompetitionInfosController < ApplicationController def competition_info_params params.require(:competition_info).permit(:title, :zones, :zones_local, :sub_competitions, :identifier, :content, :video_url, :is_local, :manager_ids, :upload_date, :enroll_date, :guide, :about_us, - :banner_url, :enroll_template, :enroll_columns, :applet_banner_url) + :banner_url, :enroll_template, :enroll_columns, :applet_banner_url,:start_at) end def find_competition diff --git a/app/controllers/concerns/api/user_helper.rb b/app/controllers/concerns/api/user_helper.rb index e6156ea5..4c7b713f 100644 --- a/app/controllers/concerns/api/user_helper.rb +++ b/app/controllers/concerns/api/user_helper.rb @@ -16,4 +16,13 @@ module Api::UserHelper end @observe_user end + + # 是否具有查看用户或编辑用户的权限 + def check_auth_for_observe_user + return render_forbidden unless current_user.admin? || @observe_user.id == current_user.id + end + + def strip(str) + str.to_s.strip.presence + end end \ No newline at end of file diff --git a/app/controllers/oauth/educoder_controller.rb b/app/controllers/oauth/educoder_controller.rb index 3ef36e71..8f7b4771 100644 --- a/app/controllers/oauth/educoder_controller.rb +++ b/app/controllers/oauth/educoder_controller.rb @@ -8,7 +8,7 @@ class Oauth::EducoderController < Oauth::BaseController ::OauthEducoderForm.new({login: login, token: token, callback_url: callback_url}).validate! - open_user= OpenUsers::Educoder.find_by(uid: login) + open_user= OpenUsers::Educoder.find_by(uid: login) || OpenUsers::Educoder.find_by(uid: mail) if open_user.present? && open_user.user.present? && open_user.user.email_binded? Rails.logger.info "######## open_user exist and open_user.user exsit and email is binded ok" @@ -32,4 +32,41 @@ class Oauth::EducoderController < Oauth::BaseController render_error(ex.message) end end + + # 需要educoder那边设置回调地址 + def create + begin + code = params['code'].to_s.strip + tip_exception("code不能为空") if code.blank? + + new_user = false + result = EducoderOauth::Service.access_token(code) + result = EducoderOauth::Service.user_info(result[:access_token]) + + # 存在该用户 + open_user = OpenUsers::Educoder.find_by(uid: result['login']) + if open_user.present? && open_user.user.present? + successful_authentication(open_user.user) + else + if current_user.blank? || !current_user.logged? + new_user = true + login = User.generate_login('E') + reg_result = autologin_register(login,"#{login}@forge.com", "Ec#{login}2021#", 'educoder', true) + if reg_result[:message].blank? + open_user = OpenUsers::Educoder.create!(user_id: reg_result[:user][:id], uid: result['login'], extra: result) + autosync_register_trustie(login, "Ec#{login}2021#", "#{login}@forge.com") + successful_authentication(open_user.user) + else + render_error(reg_result[:message]) + end + else + OpenUsers::Educoder.create!(user: current_user, uid: result['login'], extra: result) + end + end + + redirect_to root_path(new_user: new_user) + rescue Exception => ex + render_error(ex.message) + end + end end diff --git a/app/controllers/oauth/gitlink_controller.rb b/app/controllers/oauth/gitlink_controller.rb new file mode 100644 index 00000000..df4fd24a --- /dev/null +++ b/app/controllers/oauth/gitlink_controller.rb @@ -0,0 +1,71 @@ +class Oauth::GitlinkController < Oauth::BaseController + def bind + begin + login = params[:login] + mail = params[:mail] || nil + callback_url = params[:callback_url] + token = params[:token] + + ::OauthEducoderForm.new({login: login, token: token, callback_url: callback_url}).validate! + + open_user= OpenUsers::Gitlink.find_by(uid: login) || OpenUsers::Gitlink.find_by(uid: mail) + + if open_user.present? && open_user.user.present? && open_user.user.email_binded? + Rails.logger.info "######## open_user exist and open_user.user exsit and email is binded ok" + successful_authentication(open_user.user) + + redirect_to callback_url + else + Rails.logger.info "######## open user not exits" + user = User.find_by(login: login) || User.find_by(mail: mail) + + if user.is_a?(User) && !user.is_a?(AnonymousUser) + OpenUsers::Gitlink.create!(user: user, uid: login) + successful_authentication(user) + + redirect_to callback_url + else + redirect_to oauth_register_path(login: login, mail: mail, callback_url: callback_url) + end + end + rescue WechatOauth::Error => ex + render_error(ex.message) + end + end + + # 需要gitlink那边设置回调地址 + def create + begin + code = params['code'].to_s.strip + tip_exception("code不能为空") if code.blank? + + new_user = false + result = GitlinkOauth::Service.access_token(code) + result = GitlinkOauth::Service.user_info(result[:access_token]) + + # 存在该用户 + open_user = OpenUsers::Gitlink.find_by(uid: result['login']) + if open_user.present? && open_user.user.present? + successful_authentication(open_user.user) + else + if current_user.blank? || !current_user.logged? + new_user = true + login = User.generate_login('E') + reg_result = autologin_register(login,"#{login}@gitlink.org.cn", "Ec#{login}2021#", 'gitlink', true) + if reg_result[:message].blank? + open_user = OpenUsers::Gitlink.create!(user_id: reg_result[:user][:id], uid: result['login'], extra: result) + successful_authentication(open_user.user) + else + render_error(reg_result[:message]) + end + else + OpenUsers::Gitlink.create!(user: current_user, uid: result['login'], extra: result) + end + end + + redirect_to root_path(new_user: new_user) + rescue Exception => ex + render_error(ex.message) + end + end +end diff --git a/app/controllers/owners_controller.rb b/app/controllers/owners_controller.rb index 28a5210d..067fe4da 100644 --- a/app/controllers/owners_controller.rb +++ b/app/controllers/owners_controller.rb @@ -12,7 +12,7 @@ class OwnersController < ApplicationController def show @owner = Owner.find_by(login: params[:id]) || Owner.find_by(id: params[:id]) - return render_not_found unless @owner.present? + # return render_not_found unless @owner.present? # 组织 if @owner.is_a?(Organization) return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index f55a817e..3a40d9bf 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -268,19 +268,6 @@ class RepositoriesController < ApplicationController redirect_to file_path end - def archive - domain = GiteaService.gitea_config[:domain] - api_url = GiteaService.gitea_config[:base_url] - archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}" - - file_path = [domain, api_url, archive_url].join - file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden? - - return render_not_found if !request.format.zip? && !request.format.gzip? - - redirect_to file_path - end - private def find_project diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index 95224353..d2752cff 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -5,6 +5,8 @@ class SettingsController < ApplicationController get_add_menu get_common_menu get_personal_menu + get_third_party + get_professional_fields get_top_system_notification end @@ -49,6 +51,29 @@ class SettingsController < ApplicationController end end + def get_third_party + @third_party = [] + @third_party << { + name: 'GitLink', + url: GitlinkOauth.oauth_url + } + @third_party << { + name: 'Openkyin', + url: GitlinkOauth.oauth_url + } + end + + def get_professional_fields + # @professional_fields = Site.dict + + if Site.dict.count == 0 + "自动化、计算机、机械、材料、航空航天、电子信息、电气、医学、建筑、理学、教育、管理、其他".split("、").each_with_index do |key,index| + Site.dict.create!(name: key, url: index, key: "professional_field") + end + end + @professional_fields = Site.get_dict_data("professional_field") + end + def get_top_system_notification @top_system_notification = SystemNotification.is_top.first end diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb index aa364261..f338fd9a 100644 --- a/app/controllers/watchers_controller.rb +++ b/app/controllers/watchers_controller.rb @@ -48,7 +48,9 @@ class WatchersController < ApplicationController case target_type when "project" @target = target_type.capitalize.constantize.find_by(id: params[:id]) - else + when "competition_info" + @target = CompetitionInfo.where(:identifier => params[:id]).exists? ? CompetitionInfo.find_by(:identifier => params[:id]) : CompetitionInfo.find_by(id: params[:id]) + else @target = target_type.capitalize.constantize.find_by(login: params[:id]) #用户 end diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 318c7930..e16a5203 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -2304,4 +2304,189 @@ await octokit.request('GET /api/users/:login/applied_projects/:id/refuse.json') "created_at": "2021-06-09 16:41", "time_ago": "7分钟前" } +``` + + +## 用户发送邮件验证码 +用户发送邮件验证码 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/v1/yystopf/send_email_vefify_code.json +``` + +```javascript +await octokit.request('GET /api/v1/:login/send_email_vefify_code.json') +``` + +### HTTP 请求 +`GET /api/v1/:login/send_email_vefify_code.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|code_type |int |10: 更新邮箱| +|email |string |邮箱| +|smscode |string |邮箱md5加密值| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户验证邮件验证码 +用户验证邮件验证码 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/v1/yystopf/check_email_verify_code.json +``` + +```javascript +await octokit.request('POST /api/v1/:login/check_email_verify_code.json') +``` + +### HTTP 请求 +`POST /api/v1/:login/check_email_verify_code.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|code_type |int |10: 更新邮箱| +|email |string |邮箱| +|code |string |邮箱验证码| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户验证密码 +用户验证密码,检查是否和用户密码一致 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/v1/yystopf/check_password.json +``` + +```javascript +await octokit.request('POST /api/v1/:login/check_password.json') +``` + +### HTTP 请求 +`POST /api/v1/:login/check_password.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|password |string |用户密码| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户验证邮箱 +用户验证邮箱是否符合规范以及是否已被使用 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/v1/yystopf/check_email.json +``` + +```javascript +await octokit.request('POST /api/v1/:login/check_email.json') +``` + +### HTTP 请求 +`POST /api/v1/:login/check_email.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|email |string |邮箱地址| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户更改邮箱 +用户更改一个新的邮箱 + +> 示例: + +```shell +curl -X PATCH http://localhost:3000/api/v1/yystopf/update_email.json +``` + +```javascript +await octokit.request('PATCH /api/v1/:login/update_email.json') +``` + +### HTTP 请求 +`PATCH /api/v1/:login/update_email.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|password |string |用户密码| +|email |string |邮箱地址| +|code |string |邮箱验证码| + + +> 请求的JSON示例: + +```json +{ + "password": "Aa19960425.", + "code": "657134", + "email": "yystopf@163.com" +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} ``` \ No newline at end of file diff --git a/app/libs/educoder_oauth.rb b/app/libs/educoder_oauth.rb new file mode 100644 index 00000000..0c3fb61b --- /dev/null +++ b/app/libs/educoder_oauth.rb @@ -0,0 +1,18 @@ +module EducoderOauth + class << self + attr_accessor :client_id, :client_secret, :base_url, :redirect_uri + + def logger + @_logger ||= STDOUT + end + + def logger=(l) + @_logger = l + end + + def oauth_url + "#{base_url}/oauth2?call_url=/oauth/authorize?client_id=#{client_id}&redirect_uri=#{URI.encode_www_form_component(redirect_uri)}&response_type=code" + end + + end +end \ No newline at end of file diff --git a/app/libs/gitlink_oauth.rb b/app/libs/gitlink_oauth.rb new file mode 100644 index 00000000..f07602a9 --- /dev/null +++ b/app/libs/gitlink_oauth.rb @@ -0,0 +1,18 @@ +module GitlinkOauth + class << self + attr_accessor :client_id, :client_secret, :base_url, :redirect_uri + + def logger + @_logger ||= STDOUT + end + + def logger=(l) + @_logger = l + end + + def oauth_url + "#{base_url}/oauth2?call_url=/oauth/authorize?client_id=#{client_id}&redirect_uri=#{URI.encode_www_form_component(redirect_uri)}&response_type=code" + end + + end +end \ No newline at end of file diff --git a/app/libs/gitlink_oauth/service.rb b/app/libs/gitlink_oauth/service.rb new file mode 100644 index 00000000..8afc913c --- /dev/null +++ b/app/libs/gitlink_oauth/service.rb @@ -0,0 +1,37 @@ +require 'oauth2' + +module GitlinkOauth::Service + module_function + + def request(method, url, params) + begin + Rails.logger.info("[GitlinkOauth] [#{method.to_s.upcase}] #{url} || #{params}") + + client = Faraday.new(url: GitlinkOauth.base_url) + response = client.public_send(method, url, params) + result = JSON.parse(response.body) + + Rails.logger.info("[GitlinkOauth] [#{response.status}] #{result}") + + result + rescue Exception => e + raise Gitlink::TipException.new(e.message) + end + end + + def access_token(code) + begin + Rails.logger.info("[GitlinkOauth] [code] #{code} ") + Rails.logger.info("[GitlinkOauth] [redirect_uri] #{GitlinkOauth.redirect_uri} ") + client = OAuth2::Client.new(GitlinkOauth.client_id, GitlinkOauth.client_secret, site: GitlinkOauth.base_url) + result = client.auth_code.get_token(code, redirect_uri: GitlinkOauth.redirect_uri).to_hash + return result + rescue Exception => e + raise Gitlink::TipException.new(e.message) + end + end + + def user_info(access_token) + request(:get, '/api/users/me.json', {access_token: access_token}) + end +end \ No newline at end of file diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index acd34fbb..21ed5b0d 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -8,4 +8,8 @@ class UserMailer < ApplicationMailer mail(to: mail, subject: 'Gitink | 注册验证码') end + def update_email(mail, code) + @code = code + mail(to: mail, subject: 'Gitink | 更改邮箱验证码') + end end diff --git a/app/models/competition_info.rb b/app/models/competition_info.rb index 353599a9..952393ed 100644 --- a/app/models/competition_info.rb +++ b/app/models/competition_info.rb @@ -30,6 +30,7 @@ class CompetitionInfo < ApplicationRecord has_many :competition_users + has_many :watchers, as: :watchable, dependent: :destroy serialize :admin_data, JSON diff --git a/app/models/message_template.rb b/app/models/message_template.rb index bc6c5a71..d9ba3eb7 100644 --- a/app/models/message_template.rb +++ b/app/models/message_template.rb @@ -13,7 +13,7 @@ # class MessageTemplate < ApplicationRecord - self.inheritance_column = nil + # self.inheritance_column = nil PLATFORM = 'GitLink' def self.build_init_data diff --git a/app/models/message_template/competition_begin.rb b/app/models/message_template/competition_begin.rb index b521d745..5cf8c72b 100644 --- a/app/models/message_template/competition_begin.rb +++ b/app/models/message_template/competition_begin.rb @@ -28,7 +28,7 @@ class MessageTemplate::CompetitionBegin < MessageTemplate # MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last) def self.get_message_content(receivers, competition) - return receivers_string(receivers), sys_notice.to_s.gsub('{competition_name}', competition&.name), notification_url.to_s.gsub('{to_url}', "/competitions/#{competition.identifier}/home") + return receivers_string(receivers), sys_notice.to_s.gsub('{competition_name}', competition&.name.to_s), notification_url.to_s.gsub('{to_url}', "/competitions/#{competition.identifier}/home") # rescue # return '', '', '' end diff --git a/app/models/message_template/competition_result.rb b/app/models/message_template/competition_result.rb index c949a38c..33dfdbc1 100644 --- a/app/models/message_template/competition_result.rb +++ b/app/models/message_template/competition_result.rb @@ -28,7 +28,7 @@ class MessageTemplate::CompetitionResult < MessageTemplate # MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last) def self.get_message_content(receivers, competition) - return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.title), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home") + return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.name.to_s), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home") rescue return '', '', '' end diff --git a/app/models/message_template/competition_review.rb b/app/models/message_template/competition_review.rb index 12bf5a88..2e25c27e 100644 --- a/app/models/message_template/competition_review.rb +++ b/app/models/message_template/competition_review.rb @@ -28,7 +28,7 @@ class MessageTemplate::CompetitionReview < MessageTemplate # MessageTemplate::FollowedTip.get_message_content(User.where(login: 'yystopf'), User.last) def self.get_message_content(receivers, competition) - return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.title), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home") + return receivers_string(receivers), sys_notice.gsub('{competition_name}', competition&.name.to_s), notification_url.gsub('{to_url}', "/competitions/#{competition.identifier}/home") rescue return '', '', '' end diff --git a/app/models/open_users/gitlink.rb b/app/models/open_users/gitlink.rb new file mode 100644 index 00000000..044c2e68 --- /dev/null +++ b/app/models/open_users/gitlink.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::Gitlink < OpenUser + def nickname + extra&.[]('nickname') + end + + def en_type + 'gitlink' + end +end diff --git a/app/models/site.rb b/app/models/site.rb index af5e7816..771090a6 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -15,9 +15,10 @@ class Site < ApplicationRecord # add: 添加类链接 # personal: 个人名下类链接, # common: 普通链接 - enum site_type: { add: 0, personal: 1, common: 2 } + # dict: 字典类型 + enum site_type: { add: 0, personal: 1, common: 2, dict: 3 } - scope :by_search, -> (keyword){ where("name LIKE :keyword OR url LIKE :keyword", keyword: "%#{strip_param(keyword)}%") unless strip_param(keyword).blank? } + scope :by_search, -> (keyword){ where("name LIKE :keyword OR url LIKE :keyword OR `key` LIKE :keyword", keyword: "%#{strip_param(keyword)}%") unless strip_param(keyword).blank? } scope :by_site_type, -> (site_type){ where(site_type: strip_param(site_type)) unless strip_param(site_type).blank? } def self.set_default_menu @@ -76,4 +77,13 @@ class Site < ApplicationRecord end } end + + def self.get_dict_data(type) + professional_fields =[] + Site.dict.where(key: type).select(:name, :url).each do |site| + hash = { name: "#{site.name}", value: "#{site.url}" } + professional_fields << hash + end + professional_fields + end end diff --git a/app/queries/admins/user_query.rb b/app/queries/admins/user_query.rb index 5a49bf14..0c8144fe 100644 --- a/app/queries/admins/user_query.rb +++ b/app/queries/admins/user_query.rb @@ -36,6 +36,9 @@ class Admins::UserQuery < ApplicationQuery # 单位 users = users.where("company_name LIKE :name ", name: "%#{params[:company_name]}%") if params[:company_name].present? + # 专业领域 + users = users.where(professional_field: params[:professional_field]) if params[:professional_field].present? + # 授权类型 if params[:auto_trial].present? users = users.joins(user_extension: :school).where(schools: { auto_users_trial: params[:auto_trial].to_i == 1 }) diff --git a/app/services/api/v1/users/update_email_service.rb b/app/services/api/v1/users/update_email_service.rb new file mode 100644 index 00000000..e11dd2f6 --- /dev/null +++ b/app/services/api/v1/users/update_email_service.rb @@ -0,0 +1,68 @@ +class Api::V1::Users::UpdateEmailService < ApplicationService + include ActiveModel::Model + + attr_reader :user, :token, :password, :mail, :old_mail, :code, :verify_code + attr_accessor :gitea_data + + validates :password, :code, presence: true + validates :mail, presence: true, format: { with: CustomRegexp::EMAIL } + + def initialize(user, params, token =nil) + @user = user + @token = token + @password = params[:password] + @mail = params[:email] + @old_mail = user.mail + @code = params[:code] + @verify_code = VerificationCode.where(email: @mail, code: @code, code_type: 10).last + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + raise Error, "密码不正确." unless @user.check_password?(@password) + raise Error, "验证码不正确." if @verify_code&.code != @code + raise Error, "验证码已失效." if !@verify_code&.effective? + + # begin + ActiveRecord::Base.transaction do + change_user_email + excute_data_to_gitea + excute_change_email_from_gitea + end + + return gitea_data + + # rescue + # raise Error, "服务器错误,请联系系统管理员!" + # end + end + + private + def request_params + { + access_token: token + } + end + + def request_body + { + email: @mail, + login_name: @user.login, + source_id: 0 + } + end + + def change_user_email + @user.update_attributes!({mail: @mail}) + end + + def excute_data_to_gitea + Rails.logger.info request_body + @gitea_data = $gitea_client.patch_admin_users_by_username(@user.login, {body: request_body.to_json}) + end + + def excute_change_email_from_gitea + $gitea_client.delete_user_emails({body: {emails: [@old_mail]}.to_json, query: request_params}) + $gitea_client.post_user_emails({body: {emails: [@mail]}.to_json, query: request_params}) + end +end \ No newline at end of file diff --git a/app/views/admins/sites/index.html.erb b/app/views/admins/sites/index.html.erb index 8a5fa1bf..a8edc0c9 100644 --- a/app/views/admins/sites/index.html.erb +++ b/app/views/admins/sites/index.html.erb @@ -6,7 +6,7 @@ <%= form_tag(admins_sites_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
+ 您好! +
++ 你正在进行GitLink邮箱更改操作,如非本人操作,请忽略。 +
+<%= @code %>
++ 如果您并未发过此请求,则可能是因为其他用户在注册时误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。 +
+用户发送邮件验证码
+ +++示例:
+
curl -X GET http://localhost:3000/api/v1/yystopf/send_email_vefify_code.json
+await octokit.request('GET /api/v1/:login/send_email_vefify_code.json')
+GET /api/v1/:login/send_email_vefify_code.json
| 参数 | +类型 | +字段说明 | +
|---|---|---|
| login | +string | +用户标识 | +
| code_type | +int | +10: 更新邮箱 | +
| string | +邮箱 | +|
| smscode | +string | +邮箱md5加密值 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+用户验证邮件验证码
+ +++示例:
+
curl -X POST http://localhost:3000/api/v1/yystopf/check_email_verify_code.json
+await octokit.request('POST /api/v1/:login/check_email_verify_code.json')
+POST /api/v1/:login/check_email_verify_code.json
| 参数 | +类型 | +字段说明 | +
|---|---|---|
| login | +string | +用户标识 | +
| code_type | +int | +10: 更新邮箱 | +
| string | +邮箱 | +|
| code | +string | +邮箱验证码 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+用户验证密码,检查是否和用户密码一致
+ +++示例:
+
curl -X POST http://localhost:3000/api/v1/yystopf/check_password.json
+await octokit.request('POST /api/v1/:login/check_password.json')
+POST /api/v1/:login/check_password.json
| 参数 | +类型 | +字段说明 | +
|---|---|---|
| login | +string | +用户标识 | +
| password | +string | +用户密码 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+用户验证邮箱是否符合规范以及是否已被使用
+ +++示例:
+
curl -X POST http://localhost:3000/api/v1/yystopf/check_email.json
+await octokit.request('POST /api/v1/:login/check_email.json')
+POST /api/v1/:login/check_email.json
| 参数 | +类型 | +字段说明 | +
|---|---|---|
| login | +string | +用户标识 | +
| string | +邮箱地址 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+用户更改一个新的邮箱
+ +++示例:
+
curl -X PATCH http://localhost:3000/api/v1/yystopf/update_email.json
+await octokit.request('PATCH /api/v1/:login/update_email.json')
+PATCH /api/v1/:login/update_email.json
| 参数 | +类型 | +字段说明 | +
|---|---|---|
| login | +string | +用户标识 | +
| password | +string | +用户密码 | +
| string | +邮箱地址 | +|
| code | +string | +邮箱验证码 | +
++请求的JSON示例:
+
{
+ "password": "Aa19960425.",
+ "code": "657134",
+ "email": "yystopf@163.com"
+}
+++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接)
diff --git a/public/images/nav_logo.png b/public/images/nav_logo.png new file mode 100644 index 00000000..39706d1c Binary files /dev/null and b/public/images/nav_logo.png differ diff --git a/public/import_user.xlsx b/public/import_user.xlsx index f1896df4..31ba9c55 100644 Binary files a/public/import_user.xlsx and b/public/import_user.xlsx differ