Merge branch 'develop' into standalone_develop

This commit is contained in:
viletyy 2022-09-29 13:59:04 +08:00
commit 3d475fdedd
10 changed files with 653 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -16,6 +16,7 @@ module RegisterHelper
return unless user.valid?
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
result ={}
if interactor.success?
gitea_user = interactor.result
result = Gitea::User::GenerateTokenService.call(username, password)
@ -26,7 +27,7 @@ module RegisterHelper
result[:user] = {id: user.id, token: user.gitea_token}
end
else
result[:message] = interactor.error
result[:message] = interactor.result[:message]
end
result
end

View File

@ -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"
}
```

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,61 @@
<html>
<head>
<meta charset="utf-8">
<title>GitLink-验证码发送</title>
<style type="text/css">
/* 验证链接页面 */
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{ margin:0; padding:0;}
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体"; font-size:12px;line-height:1.5; background:#eaebec;}
div,img,tr,td,table{ border:0;}
table,tr,td{border:0;}
ol,ul,li{ list-style-type:none}
.new_content{ background:#fff; width: 100%;}
.email-page-link{ }
.email-link-top{ }
.c_white{ color:#fff;}
.email-link-con{ }
.email-link-line{ }
.email-link-footer{ padding:15px; color:#333; line-height: 1.9; }
.c_grey02{ color: #888;}
.fb{ font-weight: normal;}
.f14{ }
</style>
</head>
<body style="background:#fff;">
<div class="new_content">
<div style="width: 598px; background:#fff; margin:20px auto; font-size:14px; ">
<div style="height:50px; width: 578px; background:#46484c; padding:9px 10px 6px;border:1px solid #ddd; border-bottom:none;">
<a href="https://www.gitlink.org.cn">
<%= image_tag("logo.png", alt: "确实开源", width: '100', :style => "float:left; margin-top: 8px;") %>
</a>
<div style="clear:both; overflow:hidden;"></div>
</div>
<div style="width: 558px; border-left:1px solid #ddd;border-right:1px solid #ddd; background:#fff; padding:30px 20px; color:#333; line-height: 1.9;">
<p style="color:#333; font-size:16px; margin-bottom:15px;font-weight: bold">
您好!
</p>
<p style="color:#333;">
你正在进行GitLink邮箱更改操作如非本人操作请忽略。
</p>
<div style="text-align: center;">
<div style="display:block; height: 45px; line-height:45px;padding:0 30px; width:100px; font-size: 20px; font-weight: bold; background:#ffd9d9; color:#e72c37; margin:30px auto;">
<p><%= @code %></p>
</div>
<span style="font-weight: normal;color:#666;">
此邮件为系统所发,请勿直接回复。<br/>
要解决问题或了解您的帐户详情,您可以访问 <a href="https:///www.gitlink.org.cn/forums/1168/detail" style="font-weight: normal; color:#ff7500;">帮助中心</a>。
</span>
</div>
<p style="color:#666; margin-top:30px;">
如果您并未发过此请求,则可能是因为其他用户在注册时误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。
</p>
</div>
<div style="padding:20px; color:#333; line-height: 1.9;background:#46484c;border:1px solid #ddd; border-top:none; width: 558px;">
<a href="https:///www.gitlink.org.cn" style="font-weight: normal; color:#fff;">www.gitlink.org.cn</a>
</div>
</div>
</div>
</body>
</html>

View File

@ -6,6 +6,6 @@ gitea_config = config[:gitea].symbolize_keys!
$gitea_client = Gitea::Api::Client.new({
domain: gitea_config[:domain],
base_url: gitea_config[:base_url],
username: gitea_config[:username],
password: gitea_config[:password]
username: gitea_config[:access_key_id],
password: gitea_config[:access_key_secret]
})

View File

@ -2,7 +2,15 @@ defaults format: :json do
namespace :api do
namespace :v1 do
scope ':owner' do
resource :users, path: '/', only: [:show, :update, :edit, :destroy]
resource :users, path: '/', only: [:show, :update, :edit, :destroy] do
collection do
get :send_email_vefify_code
post :check_password
post :check_email
post :check_email_verify_code
patch :update_email
end
end
scope module: :users do
resources :projects, only: [:index]
end

View File

@ -423,6 +423,21 @@
<li>
<a href="#f2ee84ecf7" class="toc-h2 toc-link" data-title="用户拒绝申请">用户拒绝申请</a>
</li>
<li>
<a href="#887583578f" class="toc-h2 toc-link" data-title="用户发送邮件验证码">用户发送邮件验证码</a>
</li>
<li>
<a href="#e60d451c31" class="toc-h2 toc-link" data-title="用户验证邮件验证码">用户验证邮件验证码</a>
</li>
<li>
<a href="#0cea165d49" class="toc-h2 toc-link" data-title="用户验证密码">用户验证密码</a>
</li>
<li>
<a href="#d50324355e" class="toc-h2 toc-link" data-title="用户验证邮箱">用户验证邮箱</a>
</li>
<li>
<a href="#2e8c8a7bae" class="toc-h2 toc-link" data-title="用户更改邮箱">用户更改邮箱</a>
</li>
</ul>
</li>
<li>
@ -4728,6 +4743,230 @@ Success — a happy kitten is an authenticated kitten!
</span><span class="nl">"created_at"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2021-06-09 16:41"</span><span class="p">,</span><span class="w">
</span><span class="nl">"time_ago"</span><span class="p">:</span><span class="w"> </span><span class="s2">"7分钟前"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div><h2 id='887583578f'>用户发送邮件验证码</h2>
<p>用户发送邮件验证码</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/v1/yystopf/send_email_vefify_code.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">GET /api/v1/:login/send_email_vefify_code.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-28'>HTTP 请求</h3>
<p><code>GET /api/v1/:login/send_email_vefify_code.json</code></p>
<h3 id='aa883f5d52-23'>请求字段说明:</h3>
<table><thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>login</td>
<td>string</td>
<td>用户标识</td>
</tr>
<tr>
<td>code_type</td>
<td>int</td>
<td>10: 更新邮箱</td>
</tr>
<tr>
<td>email</td>
<td>string</td>
<td>邮箱</td>
</tr>
<tr>
<td>smscode</td>
<td>string</td>
<td>邮箱md5加密值</td>
</tr>
</tbody></table>
<h3 id='7447e4874e-21'>返回字段说明:</h3>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div><h2 id='e60d451c31'>用户验证邮件验证码</h2>
<p>用户验证邮件验证码</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/v1/yystopf/check_email_verify_code.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">POST /api/v1/:login/check_email_verify_code.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-29'>HTTP 请求</h3>
<p><code>POST /api/v1/:login/check_email_verify_code.json</code></p>
<h3 id='aa883f5d52-24'>请求字段说明:</h3>
<table><thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>login</td>
<td>string</td>
<td>用户标识</td>
</tr>
<tr>
<td>code_type</td>
<td>int</td>
<td>10: 更新邮箱</td>
</tr>
<tr>
<td>email</td>
<td>string</td>
<td>邮箱</td>
</tr>
<tr>
<td>code</td>
<td>string</td>
<td>邮箱验证码</td>
</tr>
</tbody></table>
<h3 id='7447e4874e-22'>返回字段说明:</h3>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div><h2 id='0cea165d49'>用户验证密码</h2>
<p>用户验证密码,检查是否和用户密码一致</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/v1/yystopf/check_password.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">POST /api/v1/:login/check_password.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-30'>HTTP 请求</h3>
<p><code>POST /api/v1/:login/check_password.json</code></p>
<h3 id='aa883f5d52-25'>请求字段说明:</h3>
<table><thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>login</td>
<td>string</td>
<td>用户标识</td>
</tr>
<tr>
<td>password</td>
<td>string</td>
<td>用户密码</td>
</tr>
</tbody></table>
<h3 id='7447e4874e-23'>返回字段说明:</h3>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div><h2 id='d50324355e'>用户验证邮箱</h2>
<p>用户验证邮箱是否符合规范以及是否已被使用</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/v1/yystopf/check_email.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">POST /api/v1/:login/check_email.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-31'>HTTP 请求</h3>
<p><code>POST /api/v1/:login/check_email.json</code></p>
<h3 id='aa883f5d52-26'>请求字段说明:</h3>
<table><thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>login</td>
<td>string</td>
<td>用户标识</td>
</tr>
<tr>
<td>email</td>
<td>string</td>
<td>邮箱地址</td>
</tr>
</tbody></table>
<h3 id='7447e4874e-24'>返回字段说明:</h3>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div><h2 id='2e8c8a7bae'>用户更改邮箱</h2>
<p>用户更改一个新的邮箱</p>
<blockquote>
<p>示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> PATCH http://localhost:3000/api/v1/yystopf/update_email.json
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="k">await</span> <span class="nx">octokit</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="dl">'</span><span class="s1">PATCH /api/v1/:login/update_email.json</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div><h3 id='http-32'>HTTP 请求</h3>
<p><code>PATCH /api/v1/:login/update_email.json</code></p>
<h3 id='aa883f5d52-27'>请求字段说明:</h3>
<table><thead>
<tr>
<th>参数</th>
<th>类型</th>
<th>字段说明</th>
</tr>
</thead><tbody>
<tr>
<td>login</td>
<td>string</td>
<td>用户标识</td>
</tr>
<tr>
<td>password</td>
<td>string</td>
<td>用户密码</td>
</tr>
<tr>
<td>email</td>
<td>string</td>
<td>邮箱地址</td>
</tr>
<tr>
<td>code</td>
<td>string</td>
<td>邮箱验证码</td>
</tr>
</tbody></table>
<blockquote>
<p>请求的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Aa19960425."</span><span class="p">,</span><span class="w">
</span><span class="nl">"code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"657134"</span><span class="p">,</span><span class="w">
</span><span class="nl">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"yystopf@163.com"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>
<blockquote>
<p>返回的JSON示例:</p>
</blockquote>
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div><h1 id='projects'>Projects</h1><h2 id='b57112e753'>获取项目邀请链接(项目管理员)</h2>
<p>当前登录管理员用户获取项目邀请链接的接口第一次请求会默认生成role类型为developer和is_apply为true的链接</p>