diff --git a/api_document.md b/api_document.md index 8a579f8e7..a43147bb2 100644 --- a/api_document.md +++ b/api_document.md @@ -51,6 +51,51 @@ http://localhost:3000/api/accounts/remote_register | jq |-- token |string|用户token| +返回值 +```json +{ + "status": 0, + "message": "success", + "user": { + "id": 36400, + "token": "8c87a80d9cfacc92fcb2451845104f35119eda96" + } +} +``` +--- + +#### 独立注册接口 +``` +POST accounts/register +``` +*示例* +```bash +curl -X POST \ +-d "login=2456233122@qq.com" \ +-d "password=djs_D_00001" \ +-d "namespace=16895620" \ +-d "code=forge" \ +http://localhost:3000/api/accounts/remote_register | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +|-|-|-|-| +|login |是|string |邮箱或者手机号 | +|namespace |是|string |登录名 | +|password |是|string |密码 | +|code |是|string |验证码 | + + +*返回参数说明:* + +|参数名|类型|说明| +|-|-|-| +|user|json object |返回数据| +|-- id |int |用户id | +|-- token |string|用户token| + + 返回值 ```json { diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index d165d9370..b8783c44e 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,4 +1,5 @@ class AccountsController < ApplicationController + include ApplicationHelper #skip_before_action :check_account, :only => [:logout] @@ -109,60 +110,46 @@ class AccountsController < ApplicationController # 用户注册 # 注意:用户注册需要兼顾本地版,本地版是不需要验证码及激活码以及使用授权的,注册完成即可使用 # params[:login] 邮箱或者手机号 + # params[:namespace] 登录名 # params[:code] 验证码 # code_type 1:注册手机验证码 8:邮箱注册验证码 - # 本地forge注册入口 + # 本地forge注册入口需要重新更改逻辑 def register + # type只可能是1或者8 + user = nil begin - # 查询验证码是否正确;type只可能是1或者8 - type = phone_mail_type(params[:login].strip) - # code = params[:code].strip + Register::Form.new(register_params).validate! - if type == 1 - uid_logger("start register by phone: type is #{type}") - pre = 'p' - email = nil - phone = params[:login] - # verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last - # TODO: 暂时限定邮箱注册 - return normal_status(-1, '只支持邮箱注册') - else - uid_logger("start register by email: type is #{type}") - pre = 'm' - email = params[:login] - phone = nil - return normal_status(-1, "该邮箱已注册") if User.exists?(mail: params[:login]) - return normal_status(-1, "邮箱格式错误") unless params[:login] =~ CustomRegexp::EMAIL - # verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last - end - # uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") - # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) - # todo 上线前请删除万能验证码"513231" - return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD + user = Users::RegisterService.call(register_params) + password = register_params[:password].strip - code = generate_identifier User, 8, pre - login = pre + code - @user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User") - @user.password = params[:password] - # 现在因为是验证码,所以在注册的时候就可以激活 - @user.activate - # 必须要用save操作,密码的保存是在users中 - - interactor = Gitea::RegisterInteractor.call({username: login, email: email, password: params[:password]}) + # gitea用户注册, email, username, password + interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) if interactor.success? gitea_user = interactor.result - result = Gitea::User::GenerateTokenService.new(login, params[:password]).call - @user.gitea_token = result['sha1'] - @user.gitea_uid = gitea_user[:body]['id'] - if @user.save! - UserExtension.create!(user_id: @user.id) - successful_authentication(@user) - normal_status("注册成功") + result = Gitea::User::GenerateTokenService.call(user.login, password) + user.gitea_token = result['sha1'] + user.gitea_uid = gitea_user[:body]['id'] + if user.save! + UserExtension.create!(user_id: user.id) + successful_authentication(user) + render_ok end else tip_exception(-1, interactor.error) end + rescue Register::BaseForm::EmailError => e + render_error(-2, e.message) + rescue Register::BaseForm::LoginError => e + render_error(-3, e.message) + rescue Register::BaseForm::PhoneError => e + render_error(-4, e.message) + rescue Register::BaseForm::PasswordFormatError => e + render_error(-5, e.message) + rescue Register::BaseForm::VerifiCodeError => e + render_error(-6, e.message) rescue Exception => e + Gitea::User::DeleteService.call(user.login) unless user.nil? uid_logger_error(e.message) tip_exception(-1, e.message) end @@ -297,7 +284,7 @@ class AccountsController < ApplicationController # 发送验证码 # params[:login] 手机号或者邮箱号 - # params[:type]为事件通知类型 1:用户注册注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 + # params[:type]为事件通知类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加 # 发送验证码:send_type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 9: 验收手机号有效 def get_verification_code @@ -311,19 +298,14 @@ class AccountsController < ApplicationController sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}") tip_exception(501, "请求不合理") if sign != params[:smscode] + logger.info "########### 验证码:#{verification_code}" logger.info("########get_verification_code: login_type: #{login_type}, send_type:#{send_type}, ") # 记录验证码 check_verification_code(verification_code, send_type, value) - sucess_status + render_ok end - # 1 手机类型;0 邮箱类型 - # 注意新版的login是自动名生成的 - def phone_mail_type value - value =~ /^1\d{10}$/ ? 1 : 0 - end - # check user's login or email or phone is used # params[:value] 手机号或者邮箱号或者登录名 # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) @@ -381,4 +363,9 @@ class AccountsController < ApplicationController def check_params params.permit(:type, :value) end + + def register_params + params.permit(:login, :namespace, :password, :code) + end + end diff --git a/app/controllers/concerns/render_helper.rb b/app/controllers/concerns/render_helper.rb index fad401539..81e85d1ce 100644 --- a/app/controllers/concerns/render_helper.rb +++ b/app/controllers/concerns/render_helper.rb @@ -3,8 +3,8 @@ module RenderHelper render json: { status: 0, message: 'success' }.merge(data) end - def render_error(message = '') - render json: { status: -1, message: message } + def render_error(status = -1, message = '') + render json: { status: status, message: message } end def render_not_acceptable(message = '请求已拒绝') diff --git a/app/forms/base_form.rb b/app/forms/base_form.rb index 8f4f9d2ca..437217f00 100644 --- a/app/forms/base_form.rb +++ b/app/forms/base_form.rb @@ -25,5 +25,9 @@ class BaseForm def check_reversed_keyword(repository_name) raise "项目标识已被占用." if ReversedKeyword.check_exists?(repository_name) end - + + private + def strip(str) + str.to_s.strip.presence + end end diff --git a/app/forms/register/base_form.rb b/app/forms/register/base_form.rb new file mode 100644 index 000000000..df5abd871 --- /dev/null +++ b/app/forms/register/base_form.rb @@ -0,0 +1,51 @@ +module Register + class BaseForm < ::BaseForm + include ActiveModel::Model + + Error = Class.new(StandardError) + EmailError = Class.new(Error) + LoginError = Class.new(Error) + PhoneError = Class.new(Error) + PasswordFormatError = Class.new(Error) + VerifiCodeError = Class.new(Error) + + private + def check_login(login) + login = strip(login) + raise LoginError, "登录名格式有误" unless login =~ CustomRegexp::LOGIN + + login_exist = Owner.exists?(login: login) || ReversedKeyword.check_exists?(login) + raise LoginError, '登录名已被使用' if login_exist + end + + def check_mail(mail) + mail = strip(mail) + raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL + + mail_exist = Owner.exists?(mail: mail) + raise EmailError, '邮箱已被使用' if mail_exist + end + + def check_phone(phone) + phone = strip(phone) + raise PhoneError, "手机号格式有误" unless phone =~ CustomRegexp::PHONE + + phone_exist = Owner.exists?(phone: phone) + raise PhoneError, '手机号已被使用' if phone_exist + end + + def check_password(password) + password = strip(password) + raise PasswordFormatError, "8~16位密码,支持字母数字和符号" unless password =~ CustomRegexp::PASSWORD + end + + def check_verifi_code(verifi_code, code) + code = strip(code) + # return if code == "123123" # TODO 万能验证码,用于测试 + + raise VerifiCodeError, "验证码不正确" if verifi_code&.code != code + raise VerifiCodeError, "验证码已失效" if !verifi_code&.effective? + end + + end +end diff --git a/app/forms/register/check_columns_form.rb b/app/forms/register/check_columns_form.rb index 5fdb82fa0..20c5b1e89 100644 --- a/app/forms/register/check_columns_form.rb +++ b/app/forms/register/check_columns_form.rb @@ -1,5 +1,5 @@ module Register - class CheckColumnsForm < BaseForm + class CheckColumnsForm < Register::BaseForm attr_accessor :type, :value validates :type, presence: true, numericality: true @@ -8,42 +8,12 @@ module Register def check! # params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号) - case strip_type - when 1 then check_login - when 2 then check_mail - when 3 then check_phone + case strip(type).to_i + when 1 then check_login(strip(value)) + when 2 then check_mail(strip(value)) + when 3 then check_phone(strip(value)) else raise("type值无效") end end - - private - def check_login - raise("登录名格式有误") unless strip_value =~ CustomRegexp::LOGIN - - login_exist = Owner.exists?(login: strip_value) || ReversedKeyword.check_exists?(strip_value) - raise('登录名已被使用') if login_exist - end - - def check_mail - raise("邮件格式有误") unless strip_value =~ CustomRegexp::EMAIL - - mail_exist = Owner.exists?(mail: strip_value) - raise('邮箱已被使用') if mail_exist - end - - def check_phone - raise("手机号格式有误") unless strip_value =~ CustomRegexp::PHONE - - phone_exist = Owner.exists?(phone: strip_value) - raise('手机号已被使用') if phone_exist - end - - def strip_value - value&.strip - end - - def strip_type - type&.strip.to_i - end end end diff --git a/app/forms/register/form.rb b/app/forms/register/form.rb new file mode 100644 index 000000000..bad7a23e6 --- /dev/null +++ b/app/forms/register/form.rb @@ -0,0 +1,27 @@ +module Register + class Form < Register::BaseForm + # login 登陆方式,支持邮箱、登陆、手机号等 + # namespace 用户空间地址 + # type: 1:手机号注册;2:邮箱注册 + attr_accessor :login, :namespace, :password, :code, :type + + validates :login, :code, :password, :namespace, presence: true + validate :check! + + def check! + Rails.logger.info "Register::Form params: code: #{code}; login: #{login}; namespace: #{namespace}; password: #{password}; type: #{type}" + db_verifi_code = + if type == 1 + check_phone(login) + VerificationCode.where(phone: login, code: code, code_type: 1).last + elsif type == 0 + check_mail(login) + VerificationCode.where(email: login, code: code, code_type: 8).last + end + + check_login(namespace) + check_verifi_code(db_verifi_code, code) + check_password(password) + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c37fd59da..9cad9f44b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -455,5 +455,11 @@ module ApplicationHelper sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root') end end + + # 1 手机类型;0 邮箱类型 + # 注意新版的login是自动名生成的 + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index d03f14e6f..acd34fbbd 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,10 +1,11 @@ class UserMailer < ApplicationMailer # 注意:这个地方一定要和你的邮箱服务域名一致 - default from: 'notification@gitlink.org.cn' + default from: 'notification@trustie.org' # 用户注册验证码 def register_email(mail, code) @code = code - mail(to: mail, subject: 'GitLink | 注册确实开源邮箱验证') + mail(to: mail, subject: 'Gitink | 注册验证码') end + end diff --git a/app/services/gitea/user/delete_service.rb b/app/services/gitea/user/delete_service.rb new file mode 100644 index 000000000..5df3cb6b2 --- /dev/null +++ b/app/services/gitea/user/delete_service.rb @@ -0,0 +1,31 @@ +class Gitea::User::DeleteService < Gitea::ClientService + attr_reader :username + + def initialize(username) + @username = username + end + + def call + response = delete(request_url, params) + + render_status(response) + end + + private + def token + { + username: Gitea.gitea_config[:access_key_id], + password: Gitea.gitea_config[:access_key_secret] + } + end + + def request_url + "/admin/users/#{username}" + end + + def params + Hash.new.merge(token: token) + end + + +end diff --git a/app/services/users/register_service.rb b/app/services/users/register_service.rb new file mode 100644 index 000000000..bb3b3ada1 --- /dev/null +++ b/app/services/users/register_service.rb @@ -0,0 +1,58 @@ +class Users::RegisterService < ApplicationService + def initialize(params) + @login = params[:login] + @namespace = params[:namespace] + @password = params[:password] + @code = params[:code] + end + + def call + code = strip(@code) + login = strip(@login) + namespace = strip(@namespace) + password = strip(@password) + + Rails.logger.info "Users::RegisterService params: ##### #{params} " + + email, phone = + if register_type == 1 + phone_register(login, code) + elsif register_type == 0 + mail_register(login, code) + end + + user = User.new(admin: false, login: namespace, mail: email, phone: phone, type: "User") + user.password = password + user.activate # 现在因为是验证码,所以在注册的时候就可以激活 + + user + end + + private + # 手机注册 + def phone_register(login, code) + Rails.logger.info("start register by phone: phone is #{login}") + email = nil + phone = login + + [email, phone] + end + + # 邮箱注册 + def mail_register(login, code) + Rails.logger.info("start register by email: email is #{login}") + email = login + phone = nil + + [email, phone] + end + + def register_type + phone_mail_type(@login) + end + + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + end + +end