forked from Gitlink/forgeplus
Compare commits
54 Commits
standalone
...
featrue_lo
| Author | SHA1 | Date |
|---|---|---|
|
|
7a14949063 | |
|
|
8d3b674321 | |
|
|
2ece9908a6 | |
|
|
a549dc1e25 | |
|
|
6607758c25 | |
|
|
e02237a9e0 | |
|
|
59711b54bc | |
|
|
538d2113f1 | |
|
|
06cf52c384 | |
|
|
8d60b271f7 | |
|
|
be96e7e5eb | |
|
|
a033ddeeca | |
|
|
1008f17849 | |
|
|
6c67b92bb1 | |
|
|
ab2e1ffa0e | |
|
|
97ed641c63 | |
|
|
84ad7130d3 | |
|
|
83661dcf71 | |
|
|
0e9699885d | |
|
|
1533f40890 | |
|
|
c0df55c20f | |
|
|
a983ce5e8a | |
|
|
6efe9e7ec0 | |
|
|
4f53994470 | |
|
|
11d102f240 | |
|
|
8698829678 | |
|
|
81ab0b01c0 | |
|
|
3f690fd9a0 | |
|
|
2b6d5e694e | |
|
|
9aff90c03a | |
|
|
43dc966cf9 | |
|
|
cbf8f1fa67 | |
|
|
274e5090ce | |
|
|
cc0e01cc47 | |
|
|
4676b756e8 | |
|
|
f0580720e3 | |
|
|
91852d7957 | |
|
|
2719e60248 | |
|
|
0970a402c8 | |
|
|
a43f6714de | |
|
|
e5eb0d3d47 | |
|
|
01f99a2f12 | |
|
|
c019766df2 | |
|
|
9232a284d8 | |
|
|
e6c6e544fe | |
|
|
d0791ee653 | |
|
|
e1b0abbf31 | |
|
|
21fa609e05 | |
|
|
69c87fd5a4 | |
|
|
91f1f4090f | |
|
|
31676df86e | |
|
|
9cd54b0ccb | |
|
|
fa476732e5 | |
|
|
f9bb74aba4 |
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 9.8 KiB |
|
|
@ -99,3 +99,38 @@ $(document).on("turbolinks:before-cache", function () {
|
|||
|
||||
$(function () {
|
||||
});
|
||||
|
||||
$(document).on('turbolinks:load', function() {
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* @Description: Do not edit
|
||||
* @Date: 2021-08-31 11:16:45
|
||||
* @LastEditors: viletyy
|
||||
* @Author: viletyy
|
||||
* @LastEditTime: 2021-08-31 14:19:46
|
||||
* @FilePath: /forgeplus/app/assets/javascripts/admins/system_notifications/index.js
|
||||
*/
|
||||
$(document).on('turbolinks:load', function(){
|
||||
|
||||
var showSuccessNotify = function() {
|
||||
$.notify({
|
||||
message: '操作成功'
|
||||
},{
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
|
||||
// close user
|
||||
$('.project-list-container').on('click', '.recommend-action', function(){
|
||||
var $closeAction = $(this);
|
||||
var $uncloseAction = $closeAction.siblings('.unrecommend-action');
|
||||
var $editAction = $closeAction.siblings('.edit-recommend-action');
|
||||
|
||||
var keywordID = $closeAction.data('id');
|
||||
customConfirm({
|
||||
content: '确认将该项目设置为推荐项目吗?',
|
||||
ok: function(){
|
||||
$.ajax({
|
||||
url: '/admins/projects/' + keywordID,
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
project: {
|
||||
recommend: true,
|
||||
recommend_index: 1
|
||||
}
|
||||
},
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$closeAction.hide();
|
||||
$uncloseAction.show();
|
||||
$editAction.show();
|
||||
$(".project-item-"+keywordID).children('td').eq(5).text("√")
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// unclose user
|
||||
$('.project-list-container').on('click', '.unrecommend-action', function(){
|
||||
var $uncloseAction = $(this);
|
||||
var $closeAction = $uncloseAction.siblings('.recommend-action');
|
||||
var $editAction = $closeAction.siblings('.edit-recommend-action');
|
||||
|
||||
var keywordID = $uncloseAction.data('id');
|
||||
customConfirm({
|
||||
content: '确认取消该推荐项目吗?',
|
||||
ok: function () {
|
||||
$.ajax({
|
||||
url: '/admins/projects/' + keywordID,
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
project: {
|
||||
recommend: false,
|
||||
recommend_index: 0
|
||||
}
|
||||
},
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$closeAction.show();
|
||||
$uncloseAction.hide();
|
||||
$editAction.hide();
|
||||
$(".project-item-"+keywordID).children('td').eq(5).text("")
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// close user
|
||||
$('.project-list-container').on('click', '.pinned-action', function(){
|
||||
var $closeAction = $(this);
|
||||
var $uncloseAction = $closeAction.siblings('.unpinned-action');
|
||||
|
||||
var keywordID = $closeAction.data('id');
|
||||
customConfirm({
|
||||
content: '确认将该项目设置为精选项目吗?',
|
||||
ok: function(){
|
||||
$.ajax({
|
||||
url: '/admins/projects/' + keywordID,
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
project: {
|
||||
is_pinned: true,
|
||||
}
|
||||
},
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$closeAction.hide();
|
||||
$uncloseAction.show();
|
||||
$(".project-item-"+keywordID).children('td').eq(4).text("√")
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// unclose user
|
||||
$('.project-list-container').on('click', '.unpinned-action', function(){
|
||||
var $uncloseAction = $(this);
|
||||
var $closeAction = $uncloseAction.siblings('.pinned-action');
|
||||
|
||||
var keywordID = $uncloseAction.data('id');
|
||||
customConfirm({
|
||||
content: '确认取消该精选项目吗?',
|
||||
ok: function () {
|
||||
$.ajax({
|
||||
url: '/admins/projects/' + keywordID,
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
project: {
|
||||
is_pinned: false,
|
||||
}
|
||||
},
|
||||
success: function() {
|
||||
showSuccessNotify();
|
||||
$closeAction.show();
|
||||
$uncloseAction.hide();
|
||||
$(".project-item-"+keywordID).children('td').eq(4).text("")
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
|
|
@ -58,3 +58,149 @@ input.form-control {
|
|||
position: absolute;
|
||||
}
|
||||
|
||||
.logo-item {
|
||||
display: flex;
|
||||
|
||||
&-img {
|
||||
display: block;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
&-upload {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #e9ecef;
|
||||
border: 1px solid #ced4da;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 27px;
|
||||
left: 39px;
|
||||
width: 2px;
|
||||
height: 26px;
|
||||
background: #495057;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 39px;
|
||||
left: 27px;
|
||||
width: 26px;
|
||||
height: 2px;
|
||||
background: #495057;
|
||||
}
|
||||
}
|
||||
|
||||
&-left {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
|
||||
&.has-img {
|
||||
.logo-item-upload {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.logo-item-upload {
|
||||
display: block;
|
||||
background: rgba(145, 145, 145, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
color: #777777;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #23272B;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-item {
|
||||
display: flex;
|
||||
|
||||
&-img {
|
||||
display: block;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
&-upload {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
background: #e9ecef;
|
||||
border: 1px solid #ced4da;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 54px;
|
||||
left: 78px;
|
||||
width: 2px;
|
||||
height: 52px;
|
||||
background: #495057;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 78px;
|
||||
left: 54px;
|
||||
width: 52px;
|
||||
height: 2px;
|
||||
background: #495057;
|
||||
}
|
||||
}
|
||||
|
||||
&-left {
|
||||
position: relative;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
|
||||
&.has-img {
|
||||
.attachment-item-upload {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.attachment-item-upload {
|
||||
display: block;
|
||||
background: rgba(145, 145, 145, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-right {
|
||||
padding-top: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
color: #777777;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #23272B;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
class AccountsController < ApplicationController
|
||||
|
||||
#skip_before_action :check_account, :only => [:logout]
|
||||
include ApplicationHelper
|
||||
|
||||
def index
|
||||
render json: session
|
||||
|
|
@ -9,7 +8,7 @@ class AccountsController < ApplicationController
|
|||
# 其他平台同步注册的用户
|
||||
def remote_register
|
||||
username = params[:username]&.gsub(/\s+/, "")
|
||||
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.is_reversed(username).present?
|
||||
tip_exception("无法使用以下关键词:#{username},请重新命名") if ReversedKeyword.check_exists?(username)
|
||||
email = params[:email]&.gsub(/\s+/, "")
|
||||
password = params[:password]
|
||||
platform = (params[:platform] || 'forge')&.gsub(/\s+/, "")
|
||||
|
|
@ -109,60 +108,48 @@ 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_result(-2, e.message)
|
||||
rescue Register::BaseForm::LoginError => e
|
||||
render_result(-3, e.message)
|
||||
rescue Register::BaseForm::PhoneError => e
|
||||
render_result(-4, e.message)
|
||||
rescue Register::BaseForm::PasswordFormatError => e
|
||||
render_result(-5, e.message)
|
||||
rescue Register::BaseForm::PasswordConfirmationError => e
|
||||
render_result(-7, e.message)
|
||||
rescue Register::BaseForm::VerifiCodeError => e
|
||||
render_result(-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
|
||||
|
|
@ -170,7 +157,7 @@ class AccountsController < ApplicationController
|
|||
|
||||
# 用户登录
|
||||
def login
|
||||
Users::LoginForm.new(account_params).validate!
|
||||
Users::LoginForm.new(login_params).validate!
|
||||
@user = User.try_to_login(params[:login], params[:password])
|
||||
|
||||
return normal_status(-2, "错误的账号或密码") if @user.blank?
|
||||
|
|
@ -219,28 +206,27 @@ class AccountsController < ApplicationController
|
|||
# 忘记密码
|
||||
def reset_password
|
||||
begin
|
||||
code = params[:code]
|
||||
login_type = phone_mail_type(params[:login].strip)
|
||||
# 获取验证码
|
||||
if login_type == 1
|
||||
phone = params[:login]
|
||||
verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 2).last
|
||||
user = User.find_by_phone(phone)
|
||||
else
|
||||
email = params[:login]
|
||||
verifi_code = VerificationCode.where(email: email, code: code, code_type: 3).last
|
||||
user = User.find_by_mail(email) #这里有问题,应该是为email,而不是mail 6.13-hs
|
||||
end
|
||||
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
|
||||
return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
|
||||
return normal_status(-1, "8~16位密码,支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD
|
||||
Accounts::ResetPasswordForm.new(reset_password_params).validate!
|
||||
|
||||
user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation]
|
||||
ActiveRecord::Base.transaction do
|
||||
user.save!
|
||||
LimitForbidControl::UserLogin.new(user).clear
|
||||
end
|
||||
sucess_status
|
||||
user = find_user
|
||||
return render_error('未找到相关账号') if user.blank?
|
||||
|
||||
user = Accounts::ResetPasswordService.call(user, reset_password_params)
|
||||
LimitForbidControl::UserLogin.new(user).clear if user.save!
|
||||
|
||||
render_ok
|
||||
rescue Register::BaseForm::EmailError => e
|
||||
render_result(-2, e.message)
|
||||
rescue Register::BaseForm::PhoneError => e
|
||||
render_result(-4, e.message)
|
||||
rescue Register::BaseForm::PasswordFormatError => e
|
||||
render_result(-5, e.message)
|
||||
rescue Register::BaseForm::PasswordConfirmationError => e
|
||||
render_result(-7, e.message)
|
||||
rescue Register::BaseForm::VerifiCodeError => e
|
||||
render_result(-6, e.message)
|
||||
rescue ActiveRecord::Rollback => e
|
||||
render_result(-1, "服务器异常")
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
|
|
@ -297,7 +283,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 +297,22 @@ 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
|
||||
# check user's login or email or phone is used
|
||||
# params[:value] 手机号或者邮箱号或者登录名
|
||||
# params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3:phone(手机号)
|
||||
def check
|
||||
Register::CheckColumnsForm.new(check_params).validate!
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
# type 事件类型 1:用户注册 2:忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
|
||||
|
|
@ -366,7 +355,25 @@ class AccountsController < ApplicationController
|
|||
params.require(:user).permit(:login, :email, :phone)
|
||||
end
|
||||
|
||||
def account_params
|
||||
def login_params
|
||||
params.require(:account).permit(:login, :password)
|
||||
end
|
||||
|
||||
def check_params
|
||||
params.permit(:type, :value)
|
||||
end
|
||||
|
||||
def register_params
|
||||
params.permit(:login, :namespace, :password, :password_confirmation, :code)
|
||||
end
|
||||
|
||||
def reset_password_params
|
||||
params.permit(:login, :password, :password_confirmation, :code)
|
||||
end
|
||||
|
||||
def find_user
|
||||
phone_or_mail = strip(reset_password_params[:login])
|
||||
User.where("phone = :search OR mail = :search", search: phone_or_mail).last
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
|
|||
def index
|
||||
sort_by = ProjectCategory.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
q = ProjectCategory.ransack(name_cont: params[:name])
|
||||
q = ProjectCategory.includes(:projects).ransack(name_cont: params[:name])
|
||||
project_categories = q.result(distinct: true).order("#{sort_by} #{sort_direction}")
|
||||
@project_categories = paginate(project_categories)
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
|
|||
max_position_items = ProjectCategory.select(:id, :position).pluck(:position).reject!(&:blank?)
|
||||
max_position = max_position_items.present? ? max_position_items.max.to_i : 0
|
||||
|
||||
@project_category = ProjectCategory.new(name: @name,position: max_position)
|
||||
@project_category = ProjectCategory.new(name: @name,position: max_position, pinned_index: params[:project_category][:pinned_index].to_i)
|
||||
if @project_category.save
|
||||
redirect_to admins_project_categories_path
|
||||
flash[:success] = '创建成功'
|
||||
|
|
@ -33,7 +33,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
|
|||
end
|
||||
|
||||
def update
|
||||
if @project_category.update_attribute(:name, @name)
|
||||
if @project_category.update_attributes({name: @name, pinned_index: params[:project_category][:pinned_index].to_i}) && save_image_file(params[:logo], 'logo')
|
||||
redirect_to admins_project_categories_path
|
||||
flash[:success] = '更新成功'
|
||||
else
|
||||
|
|
@ -43,7 +43,7 @@ class Admins::ProjectCategoriesController < Admins::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
if @project_language.destroy
|
||||
if @project_category.destroy
|
||||
redirect_to admins_project_categories_path
|
||||
flash[:success] = "删除成功"
|
||||
else
|
||||
|
|
@ -80,4 +80,12 @@ class Admins::ProjectCategoriesController < Admins::BaseController
|
|||
flash[:danger] = '分类已存在'
|
||||
end
|
||||
end
|
||||
|
||||
def save_image_file(file, type)
|
||||
return unless file.present? && file.is_a?(ActionDispatch::Http::UploadedFile)
|
||||
|
||||
file_path = Util::FileManage.source_disk_filename(@project_category, type)
|
||||
File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
|
||||
Util.write_file(file, file_path)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
class Admins::ProjectsController < Admins::BaseController
|
||||
before_action :find_project, only: [:edit, :update]
|
||||
|
||||
def index
|
||||
sort_by = Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_on'
|
||||
|
|
@ -8,6 +9,26 @@ class Admins::ProjectsController < Admins::BaseController
|
|||
@projects = paginate projects.includes(:owner, :members, :issues, :versions, :attachments, :project_score)
|
||||
end
|
||||
|
||||
def edit ;end
|
||||
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @project.update_attributes(project_update_params)
|
||||
format.html do
|
||||
redirect_to admins_projects_path
|
||||
flash[:sucess] = "更新成功"
|
||||
end
|
||||
format.js {render_ok}
|
||||
else
|
||||
format.html do
|
||||
redirect_to admins_projects_path
|
||||
flash[:danger] = "更新失败"
|
||||
end
|
||||
format.js {render_js_error}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
project = Project.find_by!(id: params[:id])
|
||||
ActiveRecord::Base.transaction do
|
||||
|
|
@ -21,4 +42,13 @@ class Admins::ProjectsController < Admins::BaseController
|
|||
redirect_to admins_projects_path
|
||||
flash[:danger] = "删除失败"
|
||||
end
|
||||
|
||||
private
|
||||
def find_project
|
||||
@project = Project.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def project_update_params
|
||||
params.require(:project).permit(:is_pinned, :recommend, :recommend_index)
|
||||
end
|
||||
end
|
||||
|
|
@ -10,6 +10,10 @@ class Admins::SystemNotificationsController < Admins::BaseController
|
|||
@notifications = paginate(notifications)
|
||||
end
|
||||
|
||||
def history
|
||||
@users = @notification.users
|
||||
end
|
||||
|
||||
def new
|
||||
@notification = SystemNotification.new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
|
||||
OPENKEY = "79e33abd4b6588941ab7622aed1e67e8"
|
||||
OPENKEY = Rails.application.config_for(:configuration)['sign_key'] || "79e33abd4b6588941ab7622aed1e67e8"
|
||||
|
||||
|
||||
helper_method :current_user, :base_url
|
||||
|
||||
|
|
@ -70,49 +71,11 @@ class ApplicationController < ActionController::Base
|
|||
(current_user.professional_certification && (ue.teacher? || ue.professional?))
|
||||
end
|
||||
|
||||
def shixun_marker
|
||||
unless current_user.is_shixun_marker? || current_user.admin_or_business?
|
||||
tip_exception(403, "..")
|
||||
end
|
||||
end
|
||||
|
||||
# 实训的访问权限
|
||||
def shixun_access_allowed
|
||||
if !current_user.shixun_permission(@shixun)
|
||||
tip_exception(403, "..")
|
||||
end
|
||||
end
|
||||
|
||||
def admin_or_business?
|
||||
User.current.admin? || User.current.business?
|
||||
end
|
||||
|
||||
# 访问课堂时没权限直接弹加入课堂的弹框 :409
|
||||
def user_course_identity
|
||||
@user_course_identity = current_user.course_identity(@course)
|
||||
if @user_course_identity > Course::STUDENT && @course.is_public == 0
|
||||
tip_exception(401, "..") unless User.current.logged?
|
||||
check_account
|
||||
tip_exception(@course.excellent ? 410 : 409, "您没有权限进入")
|
||||
end
|
||||
if @user_course_identity > Course::CREATOR && @user_course_identity <= Course::STUDENT && @course.tea_id != current_user.id
|
||||
# 实名认证和职业认证的身份判断
|
||||
tip_exception(411, "你的实名认证和职业认证审核未通过") if @course.authentication &&
|
||||
@course.professional_certification && (!current_user.authentication && !current_user.professional_certification)
|
||||
tip_exception(411, "你的实名认证审核未通过") if @course.authentication && !current_user.authentication
|
||||
tip_exception(411, "你的职业认证审核未通过") if @course.professional_certification && !current_user.professional_certification
|
||||
end
|
||||
uid_logger("###############user_course_identity:#{@user_course_identity}")
|
||||
end
|
||||
|
||||
# 题库的访问权限
|
||||
def bank_visit_auth
|
||||
tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public
|
||||
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? ||
|
||||
(current_user.certification_teacher? && @bank.is_public)
|
||||
end
|
||||
|
||||
|
||||
# 判断用户的邮箱或者手机是否可用
|
||||
# params[:type] 1: 注册;2:忘记密码;3:绑定
|
||||
def check_mail_and_phone_valid login, type
|
||||
|
|
@ -120,16 +83,16 @@ class ApplicationController < ActionController::Base
|
|||
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
|
||||
tip_exception(-2, "请输入正确的手机号或邮箱")
|
||||
end
|
||||
# 考虑到安全参数问题,多一次查询,去掉Union
|
||||
user = User.where(phone: login).first || User.where(mail: login).first
|
||||
if type.to_i == 1 && !user.nil?
|
||||
|
||||
user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login)
|
||||
if user_exist && type.to_i == 1
|
||||
tip_exception(-2, "该手机号码或邮箱已被注册")
|
||||
elsif type.to_i == 2 && user.nil?
|
||||
elsif type.to_i == 2 && !user_exist
|
||||
tip_exception(-2, "该手机号码或邮箱未注册")
|
||||
elsif type.to_i == 3 && user.present?
|
||||
elsif type.to_i == 3 && user_exist
|
||||
tip_exception(-2, "该手机号码或邮箱已绑定")
|
||||
end
|
||||
sucess_status
|
||||
render_ok
|
||||
end
|
||||
|
||||
# 发送及记录激活码
|
||||
|
|
@ -186,26 +149,6 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def find_course
|
||||
return normal_status(2, '缺少course_id参数!') if params[:course_id].blank?
|
||||
@course = Course.find(params[:course_id])
|
||||
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
|
||||
rescue Exception => e
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def course_manager
|
||||
return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR
|
||||
end
|
||||
|
||||
def find_board
|
||||
return normal_status(2, "缺少board_id参数") if params[:board_id].blank?
|
||||
@board = Board.find(params[:board_id])
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
|
||||
def validate_type(object_type)
|
||||
normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
|
||||
end
|
||||
|
|
@ -215,21 +158,6 @@ class ApplicationController < ActionController::Base
|
|||
@page_size = params[:page_size] || 15
|
||||
end
|
||||
|
||||
# 课堂教师权限
|
||||
def teacher_allowed
|
||||
logger.info("#####identity: #{current_user.course_identity(@course)}")
|
||||
unless current_user.course_identity(@course) < Course::STUDENT
|
||||
normal_status(403, "")
|
||||
end
|
||||
end
|
||||
|
||||
# 课堂教师、课堂管理员、超级管理员的权限(不包含助教)
|
||||
def teacher_or_admin_allowed
|
||||
unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR
|
||||
normal_status(403, "")
|
||||
end
|
||||
end
|
||||
|
||||
def require_admin
|
||||
normal_status(403, "") unless User.current.admin?
|
||||
end
|
||||
|
|
@ -409,11 +337,6 @@ class ApplicationController < ActionController::Base
|
|||
@message = message
|
||||
end
|
||||
|
||||
# 实训等对应的仓库地址
|
||||
def repo_ip_url(repo_path)
|
||||
"#{edu_setting('git_address_ip')}/#{repo_path}"
|
||||
end
|
||||
|
||||
def repo_url(repo_path)
|
||||
"#{edu_setting('git_address_domain')}/#{repo_path}"
|
||||
end
|
||||
|
|
@ -815,37 +738,10 @@ class ApplicationController < ActionController::Base
|
|||
render json: exception.tip_json
|
||||
end
|
||||
|
||||
def render_parameter_missing
|
||||
render json: { status: -1, message: '参数缺失' }
|
||||
end
|
||||
|
||||
def set_export_cookies
|
||||
cookies[:fileDownload] = true
|
||||
end
|
||||
|
||||
# 149课程的评审用户数据创建(包含创建课堂学生)
|
||||
def open_class_user
|
||||
user = User.find_by(login: "OpenClassUser")
|
||||
unless user
|
||||
ActiveRecord::Base.transaction do
|
||||
user_params = {status: 1, login: "OpenClassUser", lastname: "开放课程",
|
||||
nickname: "开放课程", professional_certification: 1, certification: 1, grade: 0,
|
||||
password: "12345678", phone: "11122223333", profile_completed: 1}
|
||||
user = User.create!(user_params)
|
||||
|
||||
UserExtension.create!(user_id: user.id, gender: 0, school_id: 3396, :identity => 1, :student_id => "openclassuser") # 3396
|
||||
|
||||
subject = Subject.find_by(id: 149)
|
||||
if subject
|
||||
subject.courses.each do |course|
|
||||
CourseMember.create!(course_id: course.id, role: 3, user_id: user.id) if !course.course_members.exists?(user_id: user.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
user
|
||||
end
|
||||
|
||||
# 记录热门搜索关键字
|
||||
def record_search_keyword
|
||||
keyword = params[:keyword].to_s.strip
|
||||
|
|
|
|||
|
|
@ -28,4 +28,8 @@ module RenderHelper
|
|||
def render_result(status=1, message='success')
|
||||
render json: { status: status, message: message }
|
||||
end
|
||||
|
||||
def render_parameter_missing
|
||||
render json: { status: -1, message: '参数缺失' }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,11 +22,12 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
@can_create_project = @organization.can_create_project?(current_user.id)
|
||||
@is_admin = can_edit_org?
|
||||
@is_member = @organization.is_member?(current_user.id)
|
||||
Cache::V2::OwnerCommonService.new(@organization.login, @organization.mail).read
|
||||
end
|
||||
|
||||
def create
|
||||
ActiveRecord::Base.transaction do
|
||||
tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.is_reversed(organization_params[:name]).present?
|
||||
tip_exception("无法使用以下关键词:#{organization_params[:name]},请重新命名") if ReversedKeyword.check_exists?(organization_params[:name])
|
||||
Organizations::CreateForm.new(organization_params).validate!
|
||||
@organization = Organizations::CreateService.call(current_user, organization_params)
|
||||
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
||||
|
|
@ -68,8 +69,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
def recommend
|
||||
recommend = %W(xuos Huawei_Technology openatom_foundation pkecosystem TensorLayer)
|
||||
|
||||
@organizations = Organization.with_visibility(%w(common))
|
||||
.where(login: recommend).select(:id, :login, :firstname, :lastname, :nickname)
|
||||
@organizations = Organization.includes(:organization_extension).where(organization_extensions: {recommend: true}).to_a.each_slice(group_size).to_a
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -80,6 +80,10 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
:max_repo_creation, :nickname)
|
||||
end
|
||||
|
||||
def group_size
|
||||
params.fetch(:group_size, 4).to_i
|
||||
end
|
||||
|
||||
def password
|
||||
params.fetch(:password, "")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ class ProjectCategoriesController < ApplicationController
|
|||
@project_categories = q.result(distinct: true)
|
||||
end
|
||||
|
||||
def pinned_index
|
||||
@project_categories = ProjectCategory.where.not(pinned_index: 0).order(pinned_index: :desc)
|
||||
end
|
||||
|
||||
def group_list
|
||||
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc)
|
||||
# projects = Project.no_anomory_projects.visible
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
class ProjectRankController < ApplicationController
|
||||
# 根据时间获取热门项目
|
||||
def index
|
||||
$redis_cache.zunionstore("recent-days-project-rank", get_timeable_key_names)
|
||||
@project_rank = $redis_cache.zrevrange("recent-days-project-rank", 0, 4, withscores: true)
|
||||
rescue Exception => e
|
||||
@project_rack = []
|
||||
end
|
||||
|
||||
private
|
||||
# 默认显示7天的
|
||||
def time
|
||||
params.fetch(:time, 7).to_i
|
||||
end
|
||||
|
||||
def get_timeable_key_names
|
||||
names_array = []
|
||||
(0...time).to_a.each do |i|
|
||||
date_time_string = (Date.today - i.days).to_s
|
||||
names_array << "v2-project-rank-#{date_time_string}"
|
||||
end
|
||||
names_array
|
||||
end
|
||||
end
|
||||
|
|
@ -4,9 +4,9 @@ class ProjectsController < ApplicationController
|
|||
include ProjectsHelper
|
||||
include Acceleratorable
|
||||
|
||||
before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend about menu_list]
|
||||
before_action :require_login, except: %i[index branches branches_slice group_type_list simple show fork_users praise_users watch_users recommend banner_recommend about menu_list]
|
||||
before_action :require_profile_completed, only: [:create, :migrate]
|
||||
before_action :load_repository, except: %i[index group_type_list migrate create recommend]
|
||||
before_action :load_repository, except: %i[index group_type_list migrate create recommend banner_recommend]
|
||||
before_action :authorizate_user_can_edit_project!, only: %i[update]
|
||||
before_action :project_public?, only: %i[fork_users praise_users watch_users]
|
||||
|
||||
|
|
@ -30,8 +30,8 @@ class ProjectsController < ApplicationController
|
|||
def index
|
||||
scope = current_user.logged? ? Projects::ListQuery.call(params, current_user.id) : Projects::ListQuery.call(params)
|
||||
|
||||
# @projects = kaminari_paginate(scope)
|
||||
@projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)
|
||||
@projects = kaminari_paginate(scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units))
|
||||
# @projects = paginate scope.includes(:project_category, :project_language, :repository, :project_educoder, :owner, :project_units)
|
||||
|
||||
category_id = params[:category_id]
|
||||
@total_count =
|
||||
|
|
@ -190,6 +190,8 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def simple
|
||||
# 为了缓存活跃项目的基本信息,后续删除
|
||||
Cache::V2::ProjectCommonService.new(@project.id).reset
|
||||
json_response(@project, current_user)
|
||||
end
|
||||
|
||||
|
|
@ -197,6 +199,10 @@ class ProjectsController < ApplicationController
|
|||
@projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc)
|
||||
end
|
||||
|
||||
def banner_recommend
|
||||
@projects = Project.recommend.where.not(recommend_index: 0).includes(:project_category, :owner, :project_language).order(recommend_index: :desc)
|
||||
end
|
||||
|
||||
def about
|
||||
@project_detail = @project.project_detail
|
||||
@attachments = Array(@project_detail&.attachments) if request.get?
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class RepositoriesController < ApplicationController
|
|||
|
||||
def entries
|
||||
@project.increment!(:visits)
|
||||
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
|
||||
if @project.educoder?
|
||||
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
class UserRankController < ApplicationController
|
||||
# 根据时间获取热门开发者
|
||||
def index
|
||||
$redis_cache.zunionstore("recent-days-user-rank", get_timeable_key_names)
|
||||
@user_rank = $redis_cache.zrevrange("recent-days-user-rank", 0, 3, withscores: true)
|
||||
rescue Exception => e
|
||||
@user_rank = []
|
||||
end
|
||||
|
||||
private
|
||||
# 默认显示7天的
|
||||
def time
|
||||
params.fetch(:time, 7).to_i
|
||||
end
|
||||
|
||||
def get_timeable_key_names
|
||||
names_array = []
|
||||
(0...time).to_a.each do |i|
|
||||
date_time_string = (Date.today - i.days).to_s
|
||||
names_array << "v2-user-rank-#{date_time_string}"
|
||||
end
|
||||
names_array
|
||||
end
|
||||
end
|
||||
|
|
@ -188,30 +188,32 @@ class Users::StatisticsController < Users::BaseController
|
|||
@project_languages_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count
|
||||
@platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count
|
||||
else
|
||||
@platform_result = Cache::V2::PlatformStatisticService.new.read
|
||||
@user_result = Cache::V2::UserStatisticService.new(observed_user.id).read
|
||||
# 用户被follow数量
|
||||
@follow_count = Cache::UserFollowCountService.call(observed_user)
|
||||
@platform_follow_count = Cache::PlatformFollowCountService.call
|
||||
@follow_count = @user_result["follow-count"].to_i
|
||||
@platform_follow_count = @platform_result["follow-count"].to_i
|
||||
# 用户pr数量
|
||||
@pullrequest_count = Cache::UserPullrequestCountService.call(observed_user)
|
||||
@platform_pullrequest_count = Cache::PlatformPullrequestCountService.call
|
||||
@pullrequest_count = @user_result["pullrequest-count"].to_i
|
||||
@platform_pullrequest_count = @platform_result["pullrequest-count"].to_i
|
||||
# 用户issue数量
|
||||
@issues_count = Cache::UserIssueCountService.call(observed_user)
|
||||
@platform_issues_count = Cache::PlatformIssueCountService.call
|
||||
@issues_count = @user_result["issue-count"].to_i
|
||||
@platform_issues_count = @platform_result["issue-count"].to_i
|
||||
# 用户总项目数
|
||||
@project_count = Cache::UserProjectCountService.call(observed_user)
|
||||
@platform_project_count = Cache::PlatformProjectCountService.call
|
||||
@project_count = @user_result["project-count"].to_i
|
||||
@platform_project_count = @platform_result["project-count"].to_i
|
||||
# 用户项目被fork数量
|
||||
@fork_count = Cache::UserProjectForkCountService.call(observed_user)
|
||||
@platform_fork_count = Cache::PlatformProjectForkCountService.call
|
||||
@fork_count = @user_result["fork-count"].to_i
|
||||
@platform_fork_count = @platform_result["fork-count"].to_i
|
||||
# 用户项目关注数
|
||||
@project_watchers_count = Cache::UserProjectWatchersCountService.call(observed_user)
|
||||
@platform_project_watchers_count = Cache::PlatformProjectWatchersCountService.call
|
||||
@project_watchers_count = @user_result["project-watcher-count"].to_i
|
||||
@platform_project_watchers_count = @platform_result["project-watcher-count"].to_i
|
||||
# 用户项目点赞数
|
||||
@project_praises_count = Cache::UserProjectPraisesCountService.call(observed_user)
|
||||
@platform_project_praises_count = Cache::PlatformProjectPraisesCountService.call
|
||||
@project_praises_count = @user_result["project-praise-count"].to_i
|
||||
@platform_project_praises_count = @platform_result["project-praise-count"].to_i
|
||||
# 用户不同语言项目数量
|
||||
@project_languages_count = Cache::UserProjectLanguagesCountService.call(observed_user)
|
||||
@platform_project_languages_count = Cache::PlatformProjectLanguagesCountService.call
|
||||
@project_languages_count = JSON.parse(@user_result["project-language"])
|
||||
@platform_project_languages_count = JSON.parse(@platform_result["project-language"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
class Users::SystemNotificationHistoriesController < Users::BaseController
|
||||
before_action :private_user_resources!, only: [:create]
|
||||
def create
|
||||
@history = observed_user.system_notification_histories.new(system_notification_id: params[:system_notification_id])
|
||||
if @history.save
|
||||
render_ok
|
||||
else
|
||||
Rails.logger.info @history.errors.as_json
|
||||
render_error(@history.errors.full_messages.join(","))
|
||||
end
|
||||
rescue Exception => e
|
||||
uid_logger_error(e.message)
|
||||
tip_exception(e.message)
|
||||
end
|
||||
end
|
||||
|
|
@ -51,6 +51,8 @@ class UsersController < ApplicationController
|
|||
@projects_common_count = user_projects.common.size
|
||||
@projects_mirrior_count = user_projects.mirror.size
|
||||
@projects_sync_mirrior_count = user_projects.sync_mirror.size
|
||||
# 为了缓存活跃用户的基本信息,后续删除
|
||||
Cache::V2::OwnerCommonService.new(@user.login, @user.mail).read
|
||||
end
|
||||
|
||||
def watch_users
|
||||
|
|
@ -191,7 +193,7 @@ class UsersController < ApplicationController
|
|||
def trustie_related_projects
|
||||
projects = Project.includes(:owner, :members, :project_score).where(id: params[:ids]).order("updated_on desc")
|
||||
projects_json = []
|
||||
domain_url = EduSetting.get('host_name') + '/projects'
|
||||
domain_url = EduSetting.get('host_name')
|
||||
if projects.present?
|
||||
projects.each do |p|
|
||||
project_url = "/#{p.owner.login}/#{p.identifier}"
|
||||
|
|
|
|||
|
|
@ -199,6 +199,36 @@ await octokit.request('GET /api/users/:login/messages.json')
|
|||
Success Data.
|
||||
</aside>
|
||||
|
||||
## 用户阅读系统通知
|
||||
用户阅读系统通知
|
||||
|
||||
> 示例:
|
||||
|
||||
```shell
|
||||
curl -X POST http://localhost:3000/api/users/yystopf/system_notification_histories.json
|
||||
```
|
||||
|
||||
```javascript
|
||||
await octokit.request('GET /api/users/:login/system_notification_histories.json')
|
||||
```
|
||||
|
||||
### HTTP 请求
|
||||
`POST /api/users/:login/system_notification_histories.json`
|
||||
|
||||
### 请求字段说明:
|
||||
参数 | 类型 | 字段说明
|
||||
--------- | ----------- | -----------
|
||||
|system_notification_id |integer |阅读的系统通知id |
|
||||
|
||||
> 返回的JSON示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 0,
|
||||
"message": "success"
|
||||
}
|
||||
```
|
||||
|
||||
## 发送消息
|
||||
发送消息, 目前只支持atme
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
module Accounts
|
||||
class ResetPasswordForm < ::BaseForm
|
||||
# login 邮箱、手机号
|
||||
# code 验证码
|
||||
# type: 1:手机号注册;2:邮箱注册
|
||||
attr_accessor :login, :password, :password_confirmation, :code
|
||||
|
||||
validates :login, :code, :password, :password_confirmation, presence: true, allow_blank: false
|
||||
validate :check!
|
||||
|
||||
def check!
|
||||
Rails.logger.info "ResetPasswordForm params: code: #{code} login: #{login}
|
||||
password: #{password} password_confirmation: #{password_confirmation}"
|
||||
|
||||
type = phone_mail_type(login)
|
||||
|
||||
db_verifi_code =
|
||||
if type == 1
|
||||
check_phone_format(login)
|
||||
VerificationCode.where(phone: login, code: code, code_type: 2).last
|
||||
elsif type == 0
|
||||
check_email_format(login)
|
||||
VerificationCode.where(email: login, code: code, code_type: 3).last
|
||||
end
|
||||
|
||||
check_password(password)
|
||||
check_password_confirmation(password, password_confirmation)
|
||||
check_verifi_code(db_verifi_code, code)
|
||||
end
|
||||
|
||||
def check_phone_format(phone)
|
||||
phone = strip(phone)
|
||||
raise LoginError, "登录名格式有误" unless phone =~ CustomRegexp::LOGIN
|
||||
end
|
||||
|
||||
def check_email_format(mail)
|
||||
mail = strip(mail)
|
||||
raise EmailError, "邮件格式有误" unless mail =~ CustomRegexp::EMAIL
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,6 +1,14 @@
|
|||
class 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)
|
||||
PasswordConfirmationError = Class.new(Error)
|
||||
|
||||
def check_project_category(project_category_id)
|
||||
unless project_category_id == ''
|
||||
raise "project_category_id参数值无效." if project_category_id && !ProjectCategory.exists?(project_category_id)
|
||||
|
|
@ -23,7 +31,38 @@ class BaseForm
|
|||
end
|
||||
|
||||
def check_reversed_keyword(repository_name)
|
||||
raise "项目标识已被占用." if ReversedKeyword.is_reversed(repository_name).exists?
|
||||
raise "项目标识已被占用." if ReversedKeyword.check_exists?(repository_name)
|
||||
end
|
||||
|
||||
def check_password(password)
|
||||
password = strip(password)
|
||||
raise PasswordFormatError, "密码8~16位密码,支持字母数字和符号" unless password =~ CustomRegexp::PASSWORD
|
||||
end
|
||||
|
||||
def check_password_confirmation(password, password_confirmation)
|
||||
password = strip(password)
|
||||
password_confirmation = strip(password_confirmation)
|
||||
|
||||
raise PasswordFormatError, "确认密码为8~16位密码,支持字母数字和符号" unless password_confirmation =~ CustomRegexp::PASSWORD
|
||||
raise PasswordConfirmationError, "两次输入的密码不一致" unless password == password_confirmation
|
||||
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
|
||||
|
||||
private
|
||||
def strip(str)
|
||||
str.to_s.strip.presence
|
||||
end
|
||||
|
||||
# 1 手机类型;0 邮箱类型
|
||||
# 注意新版的login是自动名生成的
|
||||
def phone_mail_type value
|
||||
value =~ /^1\d{10}$/ ? 1 : 0
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
module Register
|
||||
class BaseForm < ::BaseForm
|
||||
include ActiveModel::Model
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
module Register
|
||||
class CheckColumnsForm < Register::BaseForm
|
||||
attr_accessor :type, :value
|
||||
|
||||
validates :type, presence: true, numericality: true
|
||||
validates :value, presence: true
|
||||
validate :check!
|
||||
|
||||
def check!
|
||||
# params[:type] 为事件类型 1:登录名(login) 2:email(邮箱) 3: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
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
module Register
|
||||
class Form < Register::BaseForm
|
||||
# login 登陆方式,支持邮箱、登陆、手机号等
|
||||
# namespace 用户空间地址
|
||||
# type: 1:手机号注册;2:邮箱注册
|
||||
attr_accessor :login, :namespace, :password, :password_confirmation, :code, :type
|
||||
|
||||
validates :login, :code, :password, :password_confirmation, :namespace, presence: true, allow_blank: false
|
||||
validate :check!
|
||||
|
||||
def check!
|
||||
Rails.logger.info "Register::Form params: code: #{code}; login: #{login};
|
||||
namespace: #{namespace}; password: #{password}; password_confirmation: #{password_confirmation}"
|
||||
|
||||
type = phone_mail_type(strip(login))
|
||||
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)
|
||||
check_password_confirmation(password, password_confirmation)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -455,5 +455,15 @@ 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
|
||||
|
||||
def strip(str)
|
||||
str.to_s.strip.presence
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
module AvatarHelper
|
||||
def relative_path
|
||||
"avatars"
|
||||
end
|
||||
|
||||
def storage_path
|
||||
File.join(Rails.root, "public", "images", relative_path)
|
||||
end
|
||||
|
||||
def disk_filename(source_type,source_id,image_file=nil)
|
||||
File.join(storage_path, "#{source_type}", "#{source_id}")
|
||||
end
|
||||
|
||||
def url_to_avatar(source)
|
||||
if File.exist?(disk_filename(source&.class, source&.id))
|
||||
ctime = File.ctime(disk_filename(source.class, source.id)).to_i
|
||||
if %w(User Organization).include?(source.class.to_s)
|
||||
File.join("images", relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}"
|
||||
else
|
||||
File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}"
|
||||
end
|
||||
elsif source.class.to_s == 'User'
|
||||
source.get_letter_avatar_url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
class CacheAsyncResetJob < ApplicationJob
|
||||
queue_as :cache
|
||||
|
||||
def perform(type, id=nil)
|
||||
case type
|
||||
when "platform_statistic_service"
|
||||
Cache::V2::PlatformStatisticService.new.reset
|
||||
when "project_common_service"
|
||||
Cache::V2::ProjectCommonService.new(id).reset
|
||||
when "user_statistic_service"
|
||||
Cache::V2::UserStatisticService.new(id).reset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
class CacheAsyncSetJob < ApplicationJob
|
||||
queue_as :cache
|
||||
|
||||
def perform(type, params={}, id=nil)
|
||||
case type
|
||||
when "platform_statistic_service"
|
||||
Cache::V2::PlatformStatisticService.new(params).call
|
||||
when "project_common_service"
|
||||
Cache::V2::ProjectCommonService.new(id, params).call
|
||||
when "user_statistic_service"
|
||||
Cache::V2::UserStatisticService.new(id, params).call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
module CustomRegexp
|
||||
PHONE = /1\d{10}/
|
||||
EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
|
||||
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
|
||||
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
|
||||
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
|
||||
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
|
||||
|
|
|
|||
|
|
@ -1,17 +1,11 @@
|
|||
class UserMailer < ApplicationMailer
|
||||
# 注意:这个地方一定要和你的邮箱服务域名一致
|
||||
default from: 'educoder@trustie.org'
|
||||
default from: 'notification@trustie.org'
|
||||
|
||||
# 用户注册验证码
|
||||
def register_email(mail, code)
|
||||
@code = code
|
||||
mail(to: mail, subject: '验证你的电子邮件')
|
||||
mail(to: mail, subject: 'Gitink | 注册验证码')
|
||||
end
|
||||
|
||||
# 课堂讨论区的邮件通知
|
||||
def course_message_email(mail, message_id)
|
||||
@message = Message.find_by(id: message_id)
|
||||
@course = @message&.board&.course
|
||||
mail(to: mail, subject: '课堂发布了新的帖子') if @message.present? && @course.present?
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,14 +17,6 @@ class ApplicationRecord < ActiveRecord::Base
|
|||
Rails.env.production? && EduSetting.get('host_name') == 'https://www.educoder.net'
|
||||
end
|
||||
|
||||
def reset_user_cache_async_job(user)
|
||||
ResetUserCacheJob.perform_later(user)
|
||||
end
|
||||
|
||||
def reset_platform_cache_async_job
|
||||
ResetPlatformCacheJob.perform_later
|
||||
end
|
||||
|
||||
def self.strip_param(key)
|
||||
key.to_s.strip.presence
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,12 +20,30 @@ class ForkUser < ApplicationRecord
|
|||
belongs_to :user
|
||||
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
|
||||
|
||||
after_save :reset_cache_data
|
||||
after_destroy :reset_cache_data
|
||||
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
|
||||
|
||||
def reset_cache_data
|
||||
self.reset_platform_cache_async_job
|
||||
self.reset_user_cache_async_job(self.project.owner)
|
||||
def incre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {forks: 1}, self.project_id)
|
||||
end
|
||||
|
||||
def decre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {forks: -1}, self.project_id)
|
||||
end
|
||||
|
||||
def incre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {fork_count: 1}, self.project&.user_id)
|
||||
end
|
||||
|
||||
def decre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {fork_count: -1}, self.project&.user_id)
|
||||
end
|
||||
|
||||
def incre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {fork_count: 1})
|
||||
end
|
||||
|
||||
def decre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {fork_count: -1})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -74,13 +74,32 @@ class Issue < ApplicationRecord
|
|||
scope :issue_pull_request, ->{where(issue_classify: "pull_request")}
|
||||
scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)}
|
||||
scope :closed, ->{where(status_id: 5)}
|
||||
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
after_update :change_versions_count
|
||||
after_save :reset_cache_data
|
||||
after_destroy :update_closed_issues_count_in_project!, :reset_cache_data
|
||||
after_destroy :update_closed_issues_count_in_project!, :decre_project_common, :decre_user_statistic, :decre_platform_statistic
|
||||
|
||||
def reset_cache_data
|
||||
self.reset_platform_cache_async_job
|
||||
self.reset_user_cache_async_job(self.user)
|
||||
def incre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {issues: 1}, self.project_id)
|
||||
end
|
||||
|
||||
def decre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {issues: -1}, self.project_id)
|
||||
end
|
||||
|
||||
def incre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: 1}, self.author_id)
|
||||
end
|
||||
|
||||
def decre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {issue_count: -1}, self.author_id)
|
||||
end
|
||||
|
||||
def incre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: 1})
|
||||
end
|
||||
|
||||
def decre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {issue_count: -1})
|
||||
end
|
||||
|
||||
def get_assign_user
|
||||
|
|
|
|||
|
|
@ -76,11 +76,17 @@ class Organization < Owner
|
|||
validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false
|
||||
validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
|
||||
|
||||
delegate :description, :website, :location, :repo_admin_change_team_access,
|
||||
delegate :description, :website, :location, :repo_admin_change_team_access, :recommend,
|
||||
:visibility, :max_repo_creation, :num_projects, :num_users, :num_teams, to: :organization_extension, allow_nil: true
|
||||
|
||||
scope :with_visibility, ->(visibility) { joins(:organization_extension).where(organization_extensions: {visibility: visibility}) if visibility.present? }
|
||||
|
||||
after_save :reset_cache_data
|
||||
|
||||
def reset_cache_data
|
||||
Cache::V2::OwnerCommonService.new(self.login, self.mail).reset
|
||||
end
|
||||
|
||||
def self.build(name, nickname, gitea_token=nil)
|
||||
self.create!(login: name, nickname: nickname, gitea_token: gitea_token)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
# num_projects :integer default("0")
|
||||
# num_users :integer default("0")
|
||||
# num_teams :integer default("0")
|
||||
# recommend :boolean default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
@ -30,6 +31,8 @@ class OrganizationExtension < ApplicationRecord
|
|||
|
||||
enum visibility: {common: 0, limited: 1, privacy: 2}
|
||||
|
||||
before_save :set_recommend
|
||||
|
||||
def self.build(organization_id, description, website, location, repo_admin_change_team_access, visibility, max_repo_creation)
|
||||
self.create!(organization_id: organization_id,
|
||||
description: description,
|
||||
|
|
@ -39,4 +42,9 @@ class OrganizationExtension < ApplicationRecord
|
|||
visibility: visibility,
|
||||
max_repo_creation: max_repo_creation)
|
||||
end
|
||||
|
||||
private
|
||||
def set_recommend
|
||||
self.recommend = false unless self.common?
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,35 +1,51 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: praise_treads
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer not null
|
||||
# praise_tread_object_id :integer
|
||||
# praise_tread_object_type :string(255)
|
||||
# praise_or_tread :integer default("1")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# praise_tread (praise_tread_object_id,praise_tread_object_type)
|
||||
#
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: praise_treads
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer not null
|
||||
# praise_tread_object_id :integer
|
||||
# praise_tread_object_type :string(255)
|
||||
# praise_or_tread :integer default("1")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# praise_tread (praise_tread_object_id,praise_tread_object_type)
|
||||
#
|
||||
|
||||
|
||||
class PraiseTread < ApplicationRecord
|
||||
belongs_to :user
|
||||
belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count
|
||||
has_many :tidings, :as => :container, :dependent => :destroy
|
||||
|
||||
after_create :send_tiding
|
||||
after_save :reset_cache_data
|
||||
after_destroy :reset_cache_data
|
||||
after_create :send_tiding, :incre_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
|
||||
|
||||
def reset_cache_data
|
||||
self.reset_platform_cache_async_job
|
||||
if self.praise_tread_object.is_a?(Project)
|
||||
self.reset_user_cache_async_job(self.praise_tread_object&.owner)
|
||||
end
|
||||
def incre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {praises: 1}, self.praise_tread_object_id) if self.praise_tread_object_type == "Project"
|
||||
end
|
||||
|
||||
def decre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {praises: -1}, self.praise_tread_object_id) if self.praise_tread_object_type == "Project"
|
||||
end
|
||||
|
||||
def incre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_praise_count: 1}, self.praise_tread_object&.user_id) if self.praise_tread_object_type == "Project"
|
||||
end
|
||||
|
||||
def decre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_praise_count: -1}, self.praise_tread_object&.user_id) if self.praise_tread_object_type == "Project"
|
||||
end
|
||||
|
||||
def incre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_praise_count: 1}) if self.praise_tread_object_type == "Project"
|
||||
end
|
||||
|
||||
def decre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_praise_count: -1}) if self.praise_tread_object_type == "Project"
|
||||
end
|
||||
|
||||
def send_tiding
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@
|
|||
# platform :integer default("0")
|
||||
# default_branch :string(255) default("master")
|
||||
# website :string(255)
|
||||
# order_index :integer default("0")
|
||||
# lesson_url :string(255)
|
||||
# is_pinned :boolean default("0")
|
||||
# recommend_index :integer default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
@ -79,6 +80,7 @@
|
|||
|
||||
|
||||
|
||||
|
||||
class Project < ApplicationRecord
|
||||
include Matchable
|
||||
include Publicable
|
||||
|
|
@ -126,13 +128,15 @@ class Project < ApplicationRecord
|
|||
has_many :pinned_projects, dependent: :destroy
|
||||
has_many :has_pinned_users, through: :pinned_projects, source: :user
|
||||
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
|
||||
|
||||
after_save :check_project_members
|
||||
before_save :set_invite_code, :reset_cache_data, :reset_unmember_followed
|
||||
after_destroy :reset_cache_data
|
||||
scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
|
||||
after_create :init_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
after_save :check_project_members, :reset_cache_data
|
||||
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned
|
||||
before_destroy :decre_project_common
|
||||
after_destroy :decre_user_statistic, :decre_platform_statistic
|
||||
scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :description, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
|
||||
scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)}
|
||||
scope :recommend, -> { visible.project_statics_select.where(recommend: true) }
|
||||
scope :pinned, -> {where(is_pinned: true)}
|
||||
|
||||
delegate :content, to: :project_detail, allow_nil: true
|
||||
delegate :name, to: :license, prefix: true, allow_nil: true
|
||||
|
|
@ -150,12 +154,52 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def reset_cache_data
|
||||
CacheAsyncResetJob.perform_later("project_common_service", self.id)
|
||||
if changes[:user_id].present?
|
||||
first_owner = Owner.find_by_id(changes[:user_id].first)
|
||||
self.reset_user_cache_async_job(first_owner)
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1}, changes[:user_id].first)
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1}, changes[:user_id].last)
|
||||
end
|
||||
if changes[:project_language_id].present?
|
||||
first_language = ProjectLanguage.find_by_id(changes[:project_language_id].first)
|
||||
last_language = ProjectLanguage.find_by_id(changes[:project_language_id].last)
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1}, self.user_id)
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1}, self.user_id)
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: first_language&.name, project_language_count: -1})
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_language_count_key: last_language&.name, project_language_count: 1})
|
||||
end
|
||||
end
|
||||
|
||||
def init_project_common
|
||||
CacheAsyncResetJob.perform_later("project_common_service", self.id)
|
||||
end
|
||||
|
||||
def decre_project_common
|
||||
$redis_cache.del("v2-project-common:#{self.id}")
|
||||
end
|
||||
|
||||
def incre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1}, self.user_id)
|
||||
end
|
||||
|
||||
def decre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1}, self.user_id)
|
||||
end
|
||||
|
||||
def incre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: 1, project_language_count_key: self.project_language&.name, project_language_count: 1})
|
||||
end
|
||||
|
||||
def decre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_count: -1, project_language_count_key: self.project_language&.name, project_language_count: -1})
|
||||
end
|
||||
|
||||
def is_full_public
|
||||
owner = self.owner
|
||||
if owner.is_a?(Organization)
|
||||
return self.is_public && owner&.visibility == "common"
|
||||
else
|
||||
return self.is_public
|
||||
end
|
||||
self.reset_platform_cache_async_job
|
||||
self.reset_user_cache_async_job(self.owner)
|
||||
end
|
||||
|
||||
def reset_unmember_followed
|
||||
|
|
@ -170,6 +214,16 @@ class Project < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def set_recommend_and_is_pinned
|
||||
self.recommend = self.recommend_index.zero? ? false : true
|
||||
# 私有项目不允许设置精选和推荐
|
||||
unless self.is_public
|
||||
self.recommend = false
|
||||
self.recommend_index = 0
|
||||
self.is_pinned = false
|
||||
end
|
||||
end
|
||||
|
||||
def self.search_project(search)
|
||||
ransack(name_or_identifier_cont: search)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,10 +8,27 @@
|
|||
# projects_count :integer default("0")
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# ancestry :string(255)
|
||||
# pinned_index :integer default("0")
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_project_categories_on_ancestry (ancestry)
|
||||
#
|
||||
|
||||
class ProjectCategory < ApplicationRecord
|
||||
include Projectable
|
||||
has_ancestry
|
||||
|
||||
def logo_url
|
||||
image_url('logo')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def image_url(type)
|
||||
return nil unless Util::FileManage.exists?(self, type)
|
||||
Util::FileManage.source_disk_file_url(self, type)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -42,12 +42,31 @@ class PullRequest < ApplicationRecord
|
|||
scope :merged_and_closed, ->{where.not(status: 0)}
|
||||
scope :opening, -> {where(status: 0)}
|
||||
|
||||
after_save :reset_cache_data
|
||||
after_destroy :reset_cache_data
|
||||
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
|
||||
|
||||
def reset_cache_data
|
||||
self.reset_platform_cache_async_job
|
||||
self.reset_user_cache_async_job(self.user)
|
||||
def incre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {pullrequests: 1}, self.project_id)
|
||||
end
|
||||
|
||||
def decre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {pullrequests: -1}, self.project_id)
|
||||
end
|
||||
|
||||
def incre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {pullrequest_count: 1}, self.user_id)
|
||||
end
|
||||
|
||||
def decre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {pullrequest_count: -1}, self.user_id)
|
||||
end
|
||||
|
||||
def incre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {pullrequest_count: 1})
|
||||
end
|
||||
|
||||
def decre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {pullrequest_count: -1})
|
||||
end
|
||||
|
||||
def fork_project
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ class ReversedKeyword < ApplicationRecord
|
|||
|
||||
before_validation :set_identifier
|
||||
|
||||
def self.check_exists?(identifier)
|
||||
self.is_reversed(identifier).exists?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_identifier
|
||||
|
|
|
|||
|
|
@ -15,6 +15,13 @@ class SystemNotification < ApplicationRecord
|
|||
|
||||
default_scope { order(created_at: :desc)}
|
||||
|
||||
has_many :system_notification_histories
|
||||
has_many :users, through: :system_notification_histories
|
||||
|
||||
scope :is_top, lambda { where(is_top: true) }
|
||||
|
||||
def read_member?(user_id)
|
||||
self.system_notification_histories.where(user_id: user_id).present? ? true : false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: system_notification_histories
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# system_message_id :integer
|
||||
# user_id :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_system_notification_histories_on_system_message_id (system_message_id)
|
||||
# index_system_notification_histories_on_user_id (user_id)
|
||||
#
|
||||
|
||||
class SystemNotificationHistory < ApplicationRecord
|
||||
|
||||
belongs_to :system_notification
|
||||
belongs_to :user
|
||||
|
||||
validates :system_notification_id, uniqueness: { scope: :user_id, message: '只能阅读一次'}
|
||||
end
|
||||
|
|
@ -173,6 +173,9 @@ class User < Owner
|
|||
|
||||
has_one :user_template_message_setting, dependent: :destroy
|
||||
|
||||
has_many :system_notification_histories
|
||||
has_many :system_notifications, through: :system_notification_histories
|
||||
|
||||
# Groups and active users
|
||||
scope :active, lambda { where(status: STATUS_ACTIVE) }
|
||||
scope :like, lambda { |keywords|
|
||||
|
|
@ -189,6 +192,7 @@ class User < Owner
|
|||
:technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true
|
||||
|
||||
before_save :update_hashed_password, :set_lastname
|
||||
after_save :reset_cache_data
|
||||
after_create do
|
||||
SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie?
|
||||
end
|
||||
|
|
@ -205,6 +209,10 @@ class User < Owner
|
|||
validate :validate_sensitive_string
|
||||
validate :validate_password_length
|
||||
|
||||
def reset_cache_data
|
||||
Cache::V2::OwnerCommonService.new(self.login, self.mail).reset
|
||||
end
|
||||
|
||||
# 用户参与的所有项目
|
||||
def full_member_projects
|
||||
normal_projects = Project.members_projects(self.id).to_sql
|
||||
|
|
|
|||
|
|
@ -22,18 +22,36 @@ class Watcher < ApplicationRecord
|
|||
|
||||
scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)}
|
||||
|
||||
after_save :reset_cache_data
|
||||
after_destroy :reset_cache_data
|
||||
after_create :send_create_message_to_notice_system
|
||||
after_create :send_create_message_to_notice_system, :incre_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
after_destroy :decre_project_common, :decre_user_statistic, :decre_platform_statistic
|
||||
|
||||
def reset_cache_data
|
||||
if self.watchable.is_a?(User)
|
||||
self.reset_user_cache_async_job(self.watchable)
|
||||
end
|
||||
if self.watchable.is_a?(Project)
|
||||
self.reset_user_cache_async_job(self.watchable&.owner)
|
||||
end
|
||||
self.reset_platform_cache_async_job
|
||||
|
||||
def incre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {watchers: 1}, self.watchable_id) if self.watchable_type == "Project"
|
||||
end
|
||||
|
||||
def decre_project_common
|
||||
CacheAsyncSetJob.perform_later("project_common_service", {watchers: -1}, self.watchable_id) if self.watchable_type == "Project"
|
||||
end
|
||||
|
||||
def incre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {follow_count: 1}, self.watchable_id) if self.watchable_type == "User"
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_watcher_count: 1}, self.watchable&.user_id) if self.watchable_type == "Project"
|
||||
end
|
||||
|
||||
def decre_user_statistic
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {follow_count: -1}, self.watchable_id) if self.watchable_type == "User"
|
||||
CacheAsyncSetJob.perform_later("user_statistic_service", {project_watcher_count: -1}, self.watchable&.user_id) if self.watchable_type == "Project"
|
||||
end
|
||||
|
||||
def incre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {follow_count: 1}) if self.watchable_type == "User"
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_watcher_count: 1}) if self.watchable_type == "Project"
|
||||
end
|
||||
|
||||
def decre_platform_statistic
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {follow_count: -1}) if self.watchable_type == "User"
|
||||
CacheAsyncSetJob.perform_later("platform_statistic_service", {project_watcher_count: -1}) if self.watchable_type == "Project"
|
||||
end
|
||||
|
||||
def send_create_message_to_notice_system
|
||||
|
|
|
|||
|
|
@ -11,19 +11,45 @@ class Projects::ListQuery < ApplicationQuery
|
|||
end
|
||||
|
||||
def call
|
||||
q = Project.visible.by_name_or_identifier(params[:search])
|
||||
|
||||
scope = q
|
||||
.with_project_type(params[:project_type])
|
||||
.with_project_category(params[:category_id])
|
||||
.with_project_language(params[:language_id])
|
||||
collection = Project.all
|
||||
collection = filter_projects(collection)
|
||||
|
||||
sort = params[:sort_by] || "updated_on"
|
||||
sort_direction = params[:sort_direction] || "desc"
|
||||
|
||||
custom_sort(scope, sort, sort_direction)
|
||||
custom_sort(collection, sort, sort_direction)
|
||||
|
||||
# scope = scope.reorder("projects.#{sort} #{sort_direction}")
|
||||
# scope
|
||||
end
|
||||
|
||||
def filter_projects(collection)
|
||||
collection = by_pinned(collection)
|
||||
collection = by_search(collection)
|
||||
collection = by_project_type(collection)
|
||||
collection = by_project_category(collection)
|
||||
collection = by_project_language(collection)
|
||||
collection
|
||||
end
|
||||
|
||||
def by_search(items)
|
||||
items.visible.by_name_or_identifier(params[:search])
|
||||
end
|
||||
|
||||
def by_project_type(items)
|
||||
items.with_project_type(params[:project_type])
|
||||
end
|
||||
|
||||
def by_project_category(items)
|
||||
items.with_project_category(params[:category_id])
|
||||
end
|
||||
|
||||
def by_project_language(items)
|
||||
items.with_project_language(params[:language_id])
|
||||
end
|
||||
|
||||
def by_pinned(items)
|
||||
(params[:pinned].present? && params[:category_id].present?) ? items.pinned : items
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
module Accounts
|
||||
class ResetPasswordService < ApplicationService
|
||||
# login、code、password、password_confirmation
|
||||
def initialize(user, params)
|
||||
@user = user
|
||||
@password = params[:password]
|
||||
@password_confirmation = params[:password_confirmation]
|
||||
end
|
||||
|
||||
def call
|
||||
return if @user.blank?
|
||||
password = strip(@password)
|
||||
password_confirmation = strip(@password_confirmation)
|
||||
|
||||
Rails.logger.info "Accounts::ResetPasswordService params:
|
||||
##### password: #{@password} password_confirmation: #{@password_confirmation}"
|
||||
|
||||
@user.password, @user.password_confirmation = password, password_confirmation
|
||||
|
||||
sync_params = {
|
||||
password: password,
|
||||
email: @user.mail
|
||||
}
|
||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||
raise ActiveRecord::Rollback unless interactor.success?
|
||||
|
||||
@user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -18,4 +18,9 @@ class ApplicationService
|
|||
def str_to_boolean str
|
||||
ActiveModel::Type::Boolean.new.cast str
|
||||
end
|
||||
|
||||
def phone_mail_type value
|
||||
value =~ /^1\d{10}$/ ? 1 : 0
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
class Cache::V2::OwnerCommonService < ApplicationService
|
||||
include AvatarHelper
|
||||
attr_reader :owner_id, :login, :name, :avatar_url, :email
|
||||
attr_accessor :owner
|
||||
|
||||
def initialize(login, email, params={})
|
||||
@login = login
|
||||
@email = email
|
||||
@name = params[:name]
|
||||
end
|
||||
|
||||
def read
|
||||
owner_common
|
||||
end
|
||||
|
||||
def call
|
||||
load_owner
|
||||
set_owner_common
|
||||
end
|
||||
|
||||
def reset
|
||||
reset_owner_common
|
||||
end
|
||||
|
||||
private
|
||||
def load_owner
|
||||
@owner = Owner.find_by(login: @login)
|
||||
end
|
||||
|
||||
def owner_common_key
|
||||
"v2-owner-common:#{@login}-#{@email.to_s}"
|
||||
end
|
||||
|
||||
def owner_common_key_by_id
|
||||
"v2-owner-common:#{@owner.id}"
|
||||
end
|
||||
|
||||
def owner_common
|
||||
$redis_cache.hgetall(owner_common_key).blank? ? reset_owner_common : $redis_cache.hgetall(owner_common_key)
|
||||
end
|
||||
|
||||
def set_owner_common
|
||||
if $redis_cache.hgetall(owner_common_key).blank?
|
||||
reset_owner_common
|
||||
return
|
||||
end
|
||||
if @name.present?
|
||||
if $redis_cache.hget(owner_common_key, "name").nil?
|
||||
reset_owner_name
|
||||
else
|
||||
$redis_cache.hset(owner_common_key, "name", @name)
|
||||
$redis_cache.hset(owner_common_key, "avatar_url", url_to_avatar(owner))
|
||||
|
||||
$redis_cache.hset(owner_common_key_by_id, "name", @name)
|
||||
$redis_cache.hset(owner_common_key_by_id, "avatar_url", url_to_avatar(owner))
|
||||
end
|
||||
end
|
||||
if @email.present?
|
||||
if $redis_cache.hget(owner_common_key, "email").nil?
|
||||
reset_owner_email
|
||||
else
|
||||
$redis_cache.hset(owner_common_key, "email", @email)
|
||||
$redis_cache.hset(owner_common_key_by_id, "email", @email)
|
||||
end
|
||||
end
|
||||
|
||||
$redis_cache.hgetall(owner_common_key)
|
||||
end
|
||||
def reset_owner_id
|
||||
$redis_cache.hset(owner_common_key, "id", owner&.id)
|
||||
$redis_cache.hset(owner_common_key_by_id, "id", owner&.id)
|
||||
end
|
||||
|
||||
def reset_owner_type
|
||||
$redis_cache.hset(owner_common_key, "type", owner&.type)
|
||||
$redis_cache.hset(owner_common_key_by_id, "type", owner&.type)
|
||||
end
|
||||
|
||||
def reset_owner_login
|
||||
$redis_cache.hset(owner_common_key, "login", owner&.login)
|
||||
$redis_cache.hset(owner_common_key_by_id, "login", owner&.login)
|
||||
end
|
||||
|
||||
def reset_owner_email
|
||||
$redis_cache.hset(owner_common_key, "email", owner&.mail)
|
||||
$redis_cache.hset(owner_common_key_by_id, "email", owner&.mail)
|
||||
end
|
||||
|
||||
def reset_owner_name
|
||||
$redis_cache.hset(owner_common_key, "name", owner&.real_name)
|
||||
$redis_cache.hset(owner_common_key, "avatar_url", url_to_avatar(owner))
|
||||
$redis_cache.hset(owner_common_key_by_id, "name", owner&.real_name)
|
||||
$redis_cache.hset(owner_common_key_by_id, "avatar_url", url_to_avatar(owner))
|
||||
end
|
||||
|
||||
def reset_owner_common
|
||||
load_owner
|
||||
$redis_cache.del(owner_common_key)
|
||||
reset_owner_id
|
||||
reset_owner_type
|
||||
reset_owner_login
|
||||
reset_owner_email
|
||||
reset_owner_name
|
||||
|
||||
$redis_cache.hgetall(owner_common_key)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
class Cache::V2::PlatformStatisticService < ApplicationService
|
||||
attr_reader :follow_count, :fork_count, :issue_count, :project_count, :project_language_count_key, :project_language_count, :project_praise_count, :project_watcher_count, :pullrequest_count
|
||||
|
||||
def initialize(params={})
|
||||
@follow_count = params[:follow_count]
|
||||
@fork_count = params[:fork_count]
|
||||
@issue_count = params[:issue_count]
|
||||
@project_count = params[:project_count]
|
||||
@project_language_count_key = params[:project_language_count_key]
|
||||
@project_language_count = params[:project_language_count]
|
||||
@project_praise_count = params[:project_praise_count]
|
||||
@project_watcher_count = params[:project_watcher_count]
|
||||
@pullrequest_count = params[:pullrequest_count]
|
||||
end
|
||||
|
||||
def read
|
||||
platform_statistic
|
||||
end
|
||||
|
||||
def call
|
||||
set_platform_statistic
|
||||
end
|
||||
|
||||
def reset
|
||||
reset_platform_statistic
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def platform_statistic_key
|
||||
"v2-platform-statistic"
|
||||
end
|
||||
|
||||
def follow_count_key
|
||||
"follow-count"
|
||||
end
|
||||
|
||||
def fork_count_key
|
||||
"fork-count"
|
||||
end
|
||||
|
||||
def issue_count_key
|
||||
"issue-count"
|
||||
end
|
||||
|
||||
def project_count_key
|
||||
"project-count"
|
||||
end
|
||||
|
||||
def project_language_key
|
||||
"project-language"
|
||||
end
|
||||
|
||||
def project_praise_count_key
|
||||
"project-praise-count"
|
||||
end
|
||||
|
||||
def project_watcher_count_key
|
||||
"project-watcher-count"
|
||||
end
|
||||
|
||||
def pullrequest_count_key
|
||||
"pullrequest-count"
|
||||
end
|
||||
|
||||
def platform_statistic
|
||||
$redis_cache.hgetall(platform_statistic_key).blank? ? reset_platform_statistic : $redis_cache.hgetall(platform_statistic_key)
|
||||
end
|
||||
|
||||
def set_platform_statistic
|
||||
if $redis_cache.hgetall(platform_statistic_key).blank?
|
||||
reset_platform_statistic
|
||||
return
|
||||
end
|
||||
if @follow_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, follow_count_key).nil?
|
||||
reset_platform_follow_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, follow_count_key, @follow_count)
|
||||
end
|
||||
end
|
||||
if @fork_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, fork_count_key).nil?
|
||||
reset_platform_fork_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, fork_count_key, @fork_count)
|
||||
end
|
||||
end
|
||||
if @issue_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, issue_count_key).nil?
|
||||
reset_platform_issue_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, issue_count_key, @issue_count)
|
||||
end
|
||||
end
|
||||
if @project_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, project_count_key).nil?
|
||||
reset_platform_project_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, project_count_key, @project_count)
|
||||
end
|
||||
end
|
||||
if @project_language_count_key.present? && project_language_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, project_language_key).nil?
|
||||
reset_platform_project_language
|
||||
else
|
||||
result = JSON.parse($redis_cache.hget(platform_statistic_key, project_language_key))
|
||||
result[@project_language_count_key] ||= 0
|
||||
result[@project_language_count_key] += project_language_count.to_i
|
||||
$redis_cache.hset(platform_statistic_key, project_language_key, result.to_json)
|
||||
end
|
||||
end
|
||||
if @project_praise_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, project_praise_count_key).nil?
|
||||
reset_platform_project_praise_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, project_praise_count_key, @project_praise_count)
|
||||
end
|
||||
end
|
||||
if @project_watcher_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, project_watcher_count_key).nil?
|
||||
reset_platform_project_watcher_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, project_watcher_count_key, @project_watcher_count)
|
||||
end
|
||||
end
|
||||
if @pullrequest_count.present?
|
||||
if $redis_cache.hget(platform_statistic_key, pullrequest_count_key).nil?
|
||||
reset_platform_pullrequest_count
|
||||
else
|
||||
$redis_cache.hincrby(platform_statistic_key, pullrequest_count_key, @pullrequest_count)
|
||||
end
|
||||
end
|
||||
$redis_cache.hgetall(platform_statistic_key)
|
||||
end
|
||||
|
||||
def reset_platform_follow_count
|
||||
$redis_cache.hset(platform_statistic_key, follow_count_key, Watcher.where(watchable_type: 'User').count)
|
||||
end
|
||||
|
||||
def reset_platform_fork_count
|
||||
$redis_cache.hset(platform_statistic_key, fork_count_key, ForkUser.count)
|
||||
end
|
||||
|
||||
def reset_platform_issue_count
|
||||
$redis_cache.hset(platform_statistic_key, issue_count_key, Issue.count)
|
||||
end
|
||||
|
||||
def reset_platform_project_count
|
||||
$redis_cache.hset(platform_statistic_key, project_count_key, Project.count)
|
||||
end
|
||||
|
||||
def reset_platform_project_language
|
||||
$redis_cache.hset(platform_statistic_key, project_language_key, ProjectLanguage.where.not(projects_count: 0).group("project_languages.name").sum(:projects_count).to_json)
|
||||
end
|
||||
|
||||
def reset_platform_project_praise_count
|
||||
$redis_cache.hset(platform_statistic_key, project_praise_count_key, PraiseTread.where(praise_tread_object_type: "Project").count)
|
||||
end
|
||||
|
||||
def reset_platform_project_watcher_count
|
||||
$redis_cache.hset(platform_statistic_key, project_watcher_count_key, Watcher.where(watchable_type: 'Project').count)
|
||||
end
|
||||
|
||||
def reset_platform_pullrequest_count
|
||||
$redis_cache.hset(platform_statistic_key, pullrequest_count_key, PullRequest.count)
|
||||
end
|
||||
|
||||
def reset_platform_statistic
|
||||
$redis_cache.del(platform_statistic_key)
|
||||
reset_platform_follow_count
|
||||
reset_platform_fork_count
|
||||
reset_platform_issue_count
|
||||
reset_platform_project_count
|
||||
reset_platform_project_language
|
||||
reset_platform_project_praise_count
|
||||
reset_platform_project_watcher_count
|
||||
reset_platform_pullrequest_count
|
||||
|
||||
$redis_cache.hgetall(platform_statistic_key)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
class Cache::V2::ProjectCommonService < ApplicationService
|
||||
attr_reader :project_id, :owner_id, :name, :identifier, :description, :visits, :watchers, :praises, :forks, :issues, :pullrequests
|
||||
attr_accessor :project
|
||||
|
||||
def initialize(project_id, params={})
|
||||
@project_id = project_id
|
||||
@owner_id = params[:owner_id]
|
||||
@name = params[:name]
|
||||
@identifier = params[:identifier]
|
||||
@description = params[:description]
|
||||
@visits = params[:visits]
|
||||
@watchers = params[:watchers]
|
||||
@praises = params[:praises]
|
||||
@forks = params[:forks]
|
||||
@issues = params[:issues]
|
||||
@pullrequests = params[:pullrequests]
|
||||
end
|
||||
|
||||
def read
|
||||
project_common
|
||||
end
|
||||
|
||||
def call
|
||||
set_project_common
|
||||
end
|
||||
|
||||
def reset
|
||||
reset_project_common
|
||||
end
|
||||
|
||||
private
|
||||
def load_project
|
||||
@project = Project.find_by_id(project_id)
|
||||
end
|
||||
|
||||
def project_common_key
|
||||
"v2-project-common:#{@project_id}"
|
||||
end
|
||||
|
||||
def owner_id_key
|
||||
"owner_id"
|
||||
end
|
||||
|
||||
def name_key
|
||||
"name"
|
||||
end
|
||||
|
||||
def identifier_key
|
||||
"identifier"
|
||||
end
|
||||
|
||||
def description_key
|
||||
"description"
|
||||
end
|
||||
|
||||
def visits_key
|
||||
"visits"
|
||||
end
|
||||
|
||||
def watchers_key
|
||||
"watchers"
|
||||
end
|
||||
|
||||
def praises_key
|
||||
"praises"
|
||||
end
|
||||
|
||||
def forks_key
|
||||
"forks"
|
||||
end
|
||||
|
||||
def issues_key
|
||||
"issues"
|
||||
end
|
||||
|
||||
def pullrequests_key
|
||||
"pullrequests"
|
||||
end
|
||||
|
||||
def project_common
|
||||
$redis_cache.hgetall(project_common_key).blank? ? reset_project_common : $redis_cache.hgetall(project_common_key)
|
||||
end
|
||||
|
||||
def set_project_common
|
||||
if $redis_cache.hgetall(project_common_key).blank?
|
||||
reset_project_common
|
||||
return
|
||||
end
|
||||
load_project
|
||||
return unless @project.is_full_public
|
||||
if @owner_id.present?
|
||||
if $redis_cache.hget(project_common_key, owner_id_key).nil?
|
||||
reset_project_owner_id
|
||||
else
|
||||
$redis_cache.hset(project_common_key, owner_id_key, @owner_id)
|
||||
end
|
||||
end
|
||||
if @name.present?
|
||||
if $redis_cache.hget(project_common_key, name_key).nil?
|
||||
reset_project_name
|
||||
else
|
||||
$redis_cache.hset(project_common_key, name_key, @name)
|
||||
end
|
||||
end
|
||||
if @identifier.present?
|
||||
if $redis_cache.hget(project_common_key, identifier_key).nil?
|
||||
reset_project_identifier
|
||||
else
|
||||
$redis_cache.hset(project_common_key, identifier_key, @identifier)
|
||||
end
|
||||
end
|
||||
if @description.present?
|
||||
if $redis_cache.hget(project_common_key, description_key).nil?
|
||||
reset_project_description
|
||||
else
|
||||
$redis_cache.hset(project_common_key, description_key, @description)
|
||||
end
|
||||
end
|
||||
if @visits.present?
|
||||
if $redis_cache.hget(project_common_key, visits_key).nil?
|
||||
reset_project_visits
|
||||
Cache::V2::ProjectRankService.call(@project_id, {visits: @visits})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {visits: @visits})
|
||||
else
|
||||
puts project_common_key
|
||||
puts visits_key
|
||||
puts @visits
|
||||
$redis_cache.hincrby(project_common_key, visits_key, @visits.to_s)
|
||||
Cache::V2::ProjectRankService.call(@project_id, {visits: @visits})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {visits: @visits})
|
||||
end
|
||||
end
|
||||
if @watchers.present?
|
||||
if $redis_cache.hget(project_common_key, watchers_key).nil?
|
||||
reset_project_watchers
|
||||
else
|
||||
$redis_cache.hincrby(project_common_key, watchers_key, @watchers)
|
||||
end
|
||||
end
|
||||
if @praises.present?
|
||||
if $redis_cache.hget(project_common_key, praises_key).nil?
|
||||
reset_project_praises
|
||||
Cache::V2::ProjectRankService.call(@project_id, {praises: @praises})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {praises: @praises})
|
||||
else
|
||||
$redis_cache.hincrby(project_common_key, praises_key, @praises)
|
||||
Cache::V2::ProjectRankService.call(@project_id, {praises: @praises})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {praises: @praises})
|
||||
end
|
||||
end
|
||||
if @forks.present?
|
||||
if $redis_cache.hget(project_common_key, forks_key).nil?
|
||||
reset_project_forks
|
||||
Cache::V2::ProjectRankService.call(@project_id, {forks: @forks})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {forks: @forks})
|
||||
else
|
||||
$redis_cache.hincrby(project_common_key, forks_key, @forks)
|
||||
Cache::V2::ProjectRankService.call(@project_id, {forks: @forks})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {forks: @forks})
|
||||
end
|
||||
end
|
||||
if @issues.present?
|
||||
if $redis_cache.hget(project_common_key, issues_key).nil?
|
||||
reset_project_issues
|
||||
Cache::V2::ProjectRankService.call(@project_id, {issues: @issues})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {issues: @issues})
|
||||
else
|
||||
$redis_cache.hincrby(project_common_key, issues_key, @issues)
|
||||
Cache::V2::ProjectRankService.call(@project_id, {issues: @issues})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {issues: @issues})
|
||||
end
|
||||
end
|
||||
if @pullrequests.present?
|
||||
if $redis_cache.hget(project_common_key, pullrequests_key).nil?
|
||||
reset_project_pullrequests
|
||||
Cache::V2::ProjectRankService.call(@project_id, {pullrequests: @pullrequests})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {pullrequests: @pullrequests})
|
||||
else
|
||||
$redis_cache.hincrby(project_common_key, pullrequests_key, @pullrequests)
|
||||
Cache::V2::ProjectRankService.call(@project_id, {pullrequests: @pullrequests})
|
||||
Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {pullrequests: @pullrequests})
|
||||
end
|
||||
end
|
||||
$redis_cache.hgetall(project_common_key)
|
||||
end
|
||||
|
||||
def reset_project_owner_id
|
||||
$redis_cache.hset(project_common_key, owner_id_key, @project&.user_id)
|
||||
end
|
||||
|
||||
def reset_project_name
|
||||
$redis_cache.hset(project_common_key, name_key, @project&.name)
|
||||
end
|
||||
|
||||
def reset_project_identifier
|
||||
$redis_cache.hset(project_common_key, identifier_key, @project&.identifier)
|
||||
end
|
||||
|
||||
def reset_project_description
|
||||
$redis_cache.hset(project_common_key, description_key, @project&.description)
|
||||
end
|
||||
|
||||
def reset_project_visits
|
||||
$redis_cache.hset(project_common_key, visits_key, @project&.visits || 0)
|
||||
end
|
||||
|
||||
def reset_project_watchers
|
||||
$redis_cache.hset(project_common_key, watchers_key, Watcher.where(watchable_type: 'Project', watchable_id: @project_id).count)
|
||||
end
|
||||
|
||||
def reset_project_praises
|
||||
$redis_cache.hset(project_common_key, praises_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: @project_id).count)
|
||||
end
|
||||
|
||||
def reset_project_forks
|
||||
$redis_cache.hset(project_common_key, forks_key, ForkUser.where(project_id: @project_id).count)
|
||||
end
|
||||
|
||||
def reset_project_issues
|
||||
$redis_cache.hset(project_common_key, issues_key, Issue.issue_issue.where(project_id: @project_id).count)
|
||||
end
|
||||
|
||||
def reset_project_pullrequests
|
||||
$redis_cache.hset(project_common_key, pullrequests_key, PullRequest.where(project_id: @project_id).count)
|
||||
end
|
||||
|
||||
def reset_project_common
|
||||
load_project
|
||||
return unless @project.is_full_public
|
||||
$redis_cache.del(project_common_key)
|
||||
reset_project_owner_id
|
||||
reset_project_name
|
||||
reset_project_identifier
|
||||
reset_project_description
|
||||
reset_project_visits
|
||||
reset_project_watchers
|
||||
reset_project_praises
|
||||
reset_project_forks
|
||||
reset_project_issues
|
||||
reset_project_pullrequests
|
||||
|
||||
$redis_cache.hgetall(project_common_key)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
class Cache::V2::ProjectDateRankService < ApplicationService
|
||||
attr_reader :project_id, :rank_date, :visits, :praises, :forks, :issues, :pullrequests
|
||||
attr_accessor :project_common
|
||||
|
||||
def initialize(project_id, rank_date=Date.today, params={})
|
||||
@project_id = project_id
|
||||
@rank_date = rank_date
|
||||
@visits = params[:visits]
|
||||
@praises = params[:praises]
|
||||
@forks = params[:forks]
|
||||
@issues = params[:issues]
|
||||
@pullrequests = params[:pullrequests]
|
||||
end
|
||||
|
||||
def read
|
||||
project_rank
|
||||
end
|
||||
|
||||
def call
|
||||
set_project_rank
|
||||
end
|
||||
|
||||
private
|
||||
def project_rank_key
|
||||
"v2-project-rank-#{@rank_date.to_s}"
|
||||
end
|
||||
|
||||
def project_rank
|
||||
$redis_cache.zscore(project_rank_key, @project_id)
|
||||
end
|
||||
|
||||
def set_project_rank
|
||||
if @visits.present?
|
||||
$redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id)
|
||||
end
|
||||
if @praises.present?
|
||||
$redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id)
|
||||
end
|
||||
if @forks.present?
|
||||
$redis_cache.zincrby(project_rank_key, @forks.to_i * 5, @project_id)
|
||||
end
|
||||
if @issues.present?
|
||||
$redis_cache.zincrby(project_rank_key, @issues.to_i * 10, @project_id)
|
||||
end
|
||||
if @pullrequests.present?
|
||||
$redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id)
|
||||
end
|
||||
|
||||
$redis_cache.zscore(project_rank_key, @project_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
class Cache::V2::ProjectRankService < ApplicationService
|
||||
attr_reader :project_id, :visits, :praises, :forks, :issues, :pullrequests
|
||||
attr_accessor :project_common
|
||||
|
||||
def initialize(project_id, params={})
|
||||
@project_id = project_id
|
||||
@visits = params[:visits]
|
||||
@praises = params[:praises]
|
||||
@forks = params[:forks]
|
||||
@issues = params[:issues]
|
||||
@pullrequests = params[:pullrequests]
|
||||
end
|
||||
|
||||
def read
|
||||
project_rank
|
||||
end
|
||||
|
||||
def call
|
||||
set_project_rank
|
||||
end
|
||||
|
||||
def reset
|
||||
reset_project_rank
|
||||
end
|
||||
|
||||
private
|
||||
def load_project_common
|
||||
@project_common = Cache::V2::ProjectCommonService.new(@project_id).read
|
||||
end
|
||||
|
||||
def project_rank_key
|
||||
"v2-project-rank"
|
||||
end
|
||||
|
||||
def project_rank
|
||||
$redis_cache.zscore(project_rank_key, @project_id).blank? ? reset_project_rank : $redis_cache.zscore(project_rank_key, @project_id)
|
||||
end
|
||||
|
||||
def set_project_rank
|
||||
load_project_common
|
||||
if $redis_cache.zscore(project_rank_key, @project_id).blank?
|
||||
reset_project_rank
|
||||
return
|
||||
end
|
||||
if @visits.present?
|
||||
$redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id)
|
||||
end
|
||||
if @praises.present?
|
||||
$redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id)
|
||||
end
|
||||
if @forks.present?
|
||||
$redis_cache.zincrby(project_rank_key, @forks.to_i * 5, @project_id)
|
||||
end
|
||||
if @issues.present?
|
||||
$redis_cache.zincrby(project_rank_key, @issues.to_i * 10, @project_id)
|
||||
end
|
||||
if @pullrequests.present?
|
||||
$redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id)
|
||||
end
|
||||
reset_user_project_rank
|
||||
|
||||
$redis_cache.zscore(project_rank_key, @project_id)
|
||||
end
|
||||
|
||||
def reset_project_rank
|
||||
load_project_common
|
||||
score = @project_common["visits"].to_i * 1 + @project_common["praises"].to_i * 5 + @project_common["forks"].to_i * 5 + @project_common["issues"].to_i * 10 + @project_common["pullrequests"].to_i * 10
|
||||
$redis_cache.zadd(project_rank_key, score, @project_id)
|
||||
reset_user_project_rank
|
||||
|
||||
$redis_cache.zscore(project_rank_key, @project_id)
|
||||
end
|
||||
|
||||
def reset_user_project_rank
|
||||
$redis_cache.zadd("v2-user-project-rank:#{@project_common["owner_id"]}", $redis_cache.zscore(project_rank_key, @project_id), @project_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
class Cache::V2::UserDateRankService < ApplicationService
|
||||
attr_reader :user_id, :rank_date, :follow_count, :fork_count, :issue_count, :project_count, :project_language_count_key, :project_language_count, :project_praise_count, :project_watcher_count, :pullrequest_count
|
||||
|
||||
def initialize(user_id, rank_date=Date.today, params={})
|
||||
@user_id = user_id
|
||||
@rank_date = rank_date
|
||||
@follow_count = params[:follow_count]
|
||||
@fork_count = params[:fork_count]
|
||||
@issue_count = params[:issue_count]
|
||||
@project_count = params[:project_count]
|
||||
@project_language_count_key = params[:project_language_count_key]
|
||||
@project_language_count = params[:project_language_count]
|
||||
@project_praise_count = params[:project_praise_count]
|
||||
@project_watcher_count = params[:project_watcher_count]
|
||||
@pullrequest_count = params[:pullrequest_count]
|
||||
end
|
||||
|
||||
def read_rank
|
||||
user_rank
|
||||
end
|
||||
|
||||
def read_statistic
|
||||
user_statistic
|
||||
end
|
||||
|
||||
def call
|
||||
set_user_rank
|
||||
end
|
||||
|
||||
private
|
||||
def user_rank_key
|
||||
"v2-user-rank-#{@rank_date.to_s}"
|
||||
end
|
||||
|
||||
def user_date_statistic_key
|
||||
"v2-user-statistic:#{@user_id}-#{@rank_date.to_s}"
|
||||
end
|
||||
|
||||
def user_rank
|
||||
$redis_cache.zscore(user_rank_key, @user_id)
|
||||
end
|
||||
|
||||
def user_statistic
|
||||
$redis_cache.hgetall(user_date_statistic_key)
|
||||
end
|
||||
|
||||
def set_user_statistic
|
||||
if @follow_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "follow-count", @follow_count.to_i)
|
||||
end
|
||||
if @fork_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "fork-count", @fork_count.to_i)
|
||||
end
|
||||
if @issue_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "issue-count", @issue_count.to_i)
|
||||
end
|
||||
if @project_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "project-count", @project_count.to_i)
|
||||
end
|
||||
if project_language_count_key.present? && project_language_count.present?
|
||||
if $redis_cache.hget(user_date_statistic_key, "project-language").nil?
|
||||
result = {}
|
||||
result[@project_language_count_key] = project_language_count.to_i
|
||||
result.delete(@project_language_count_key) if result[@project_language_count_key] == 0
|
||||
$redis_cache.hset(user_date_statistic_key, "project-language", result.to_json)
|
||||
else
|
||||
result = JSON.parse($redis_cache.hget(user_date_statistic_key, "project-language"))
|
||||
result[@project_language_count_key] ||= 0
|
||||
result[@project_language_count_key] += project_language_count.to_i
|
||||
result.delete(@project_language_count_key) if result[@project_language_count_key] == 0
|
||||
$redis_cache.hset(user_date_statistic_key, "project-language", result.to_json)
|
||||
end
|
||||
end
|
||||
if @project_praise_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "project-praise-count", @project_praise_count.to_i)
|
||||
end
|
||||
if @project_watcher_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "project-watcher-count", @project_watcher_count.to_i)
|
||||
end
|
||||
if @pullrequest_count.present?
|
||||
$redis_cache.hincrby(user_date_statistic_key, "pullrequest-count", @pullrequest_count.to_i)
|
||||
end
|
||||
|
||||
$redis_cache.hgetall(user_date_statistic_key)
|
||||
end
|
||||
|
||||
def set_user_rank
|
||||
set_user_statistic
|
||||
follow_count = $redis_cache.hget(user_date_statistic_key, "follow-count") || 0
|
||||
pullrequest_count = $redis_cache.hget(user_date_statistic_key, "pullrequest-count") || 0
|
||||
issues_count = $redis_cache.hget(user_date_statistic_key, "issue-count") || 0
|
||||
project_count = $redis_cache.hget(user_date_statistic_key, "project-count") || 0
|
||||
fork_count = $redis_cache.hget(user_date_statistic_key, "fork-count") || 0
|
||||
project_watchers_count = $redis_cache.hget(user_date_statistic_key, "project-watcher-count") || 0
|
||||
project_praises_count = $redis_cache.hget(user_date_statistic_key, "project-praise-count") || 0
|
||||
project_language = $redis_cache.hget(user_date_statistic_key, "project-language")
|
||||
project_languages_count = project_language.nil? || project_language == "{}" ? 0 : JSON.parse(project_language).length
|
||||
# 影响力
|
||||
influence = (60.0 + follow_count.to_i / (follow_count.to_i + 20.0) * 40.0).to_i
|
||||
|
||||
# 贡献度
|
||||
contribution = (60.0 + pullrequest_count.to_i / (pullrequest_count.to_i + 20.0) * 40.0).to_i
|
||||
|
||||
# 活跃度
|
||||
activity = (60.0 + issues_count.to_i / (issues_count.to_i + 80.0) * 40.0).to_i
|
||||
|
||||
# 项目经验
|
||||
experience = 10 * project_count.to_i + 5 * fork_count.to_i + project_watchers_count.to_i + project_praises_count.to_i
|
||||
experience = (60.0 + experience / (experience + 100.0) * 40.0).to_i
|
||||
# 语言能力
|
||||
language = (60.0 + project_languages_count.to_i / (project_languages_count.to_i + 5.0) * 40.0).to_i
|
||||
|
||||
score = influence+ contribution + activity + experience + language
|
||||
$redis_cache.zrem(user_rank_key, @user_id)
|
||||
$redis_cache.zadd(user_rank_key, score-300, @user_id) if score > 300
|
||||
|
||||
$redis_cache.zscore(user_rank_key, @user_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
class Cache::V2::UserStatisticService < ApplicationService
|
||||
attr_reader :user_id, :follow_count, :fork_count, :issue_count, :project_count, :project_language_count_key, :project_language_count, :project_praise_count, :project_watcher_count, :pullrequest_count
|
||||
|
||||
def initialize(user_id, params={})
|
||||
@user_id = user_id
|
||||
@follow_count = params[:follow_count]
|
||||
@fork_count = params[:fork_count]
|
||||
@issue_count = params[:issue_count]
|
||||
@project_count = params[:project_count]
|
||||
@project_language_count_key = params[:project_language_count_key]
|
||||
@project_language_count = params[:project_language_count]
|
||||
@project_praise_count = params[:project_praise_count]
|
||||
@project_watcher_count = params[:project_watcher_count]
|
||||
@pullrequest_count = params[:pullrequest_count]
|
||||
end
|
||||
|
||||
def read
|
||||
user_statistic
|
||||
end
|
||||
|
||||
def call
|
||||
set_user_statistic
|
||||
end
|
||||
|
||||
def reset
|
||||
reset_user_statistic
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_statistic_key
|
||||
"v2-user-statistic:#{@user_id}"
|
||||
end
|
||||
|
||||
def follow_count_key
|
||||
"follow-count"
|
||||
end
|
||||
|
||||
def fork_count_key
|
||||
"fork-count"
|
||||
end
|
||||
|
||||
def issue_count_key
|
||||
"issue-count"
|
||||
end
|
||||
|
||||
def project_count_key
|
||||
"project-count"
|
||||
end
|
||||
|
||||
def project_language_key
|
||||
"project-language"
|
||||
end
|
||||
|
||||
def project_praise_count_key
|
||||
"project-praise-count"
|
||||
end
|
||||
|
||||
def project_watcher_count_key
|
||||
"project-watcher-count"
|
||||
end
|
||||
|
||||
def pullrequest_count_key
|
||||
"pullrequest-count"
|
||||
end
|
||||
|
||||
def user_statistic
|
||||
$redis_cache.hgetall(user_statistic_key).blank? ? reset_user_statistic : $redis_cache.hgetall(user_statistic_key)
|
||||
end
|
||||
|
||||
def set_user_statistic
|
||||
if $redis_cache.hgetall(user_statistic_key).blank?
|
||||
reset_user_statistic
|
||||
return
|
||||
end
|
||||
if @follow_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, follow_count_key).nil?
|
||||
reset_user_follow_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {follow_count: @follow_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, follow_count_key, @follow_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {follow_count: @follow_count})
|
||||
end
|
||||
end
|
||||
if @fork_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, fork_count_key).nil?
|
||||
reset_user_fork_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {fork_count: @fork_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, fork_count_key, @fork_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {fork_count: @fork_count})
|
||||
end
|
||||
end
|
||||
if @issue_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, issue_count_key).nil?
|
||||
reset_user_issue_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {issue_count: @issue_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, issue_count_key, @issue_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {issue_count: @issue_count})
|
||||
end
|
||||
end
|
||||
if @project_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, project_count_key).nil?
|
||||
reset_user_project_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_count: @project_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, project_count_key, @project_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_count: @project_count})
|
||||
end
|
||||
end
|
||||
if @project_language_count_key.present? && project_language_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, project_language_key).nil?
|
||||
reset_user_project_language
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_language_count_key: @project_language_count_key, project_language_count: @project_language_count})
|
||||
else
|
||||
result = JSON.parse($redis_cache.hget(user_statistic_key, project_language_key))
|
||||
result[@project_language_count_key] ||= 0
|
||||
result[@project_language_count_key] += project_language_count.to_i
|
||||
result.delete(@project_language_count_key) if result[@project_language_count_key] == 0
|
||||
$redis_cache.hset(user_statistic_key, project_language_key, result.to_json)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_language_count_key: @project_language_count_key, project_language_count: @project_language_count})
|
||||
end
|
||||
end
|
||||
if @project_praise_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, project_praise_count_key).nil?
|
||||
reset_user_project_praise_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_praise_count: @project_praise_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, project_praise_count_key, @project_praise_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_praise_count: @project_praise_count})
|
||||
end
|
||||
end
|
||||
if @project_watcher_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, project_watcher_count_key).nil?
|
||||
reset_user_project_watcher_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_watcher_count: @project_watcher_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, project_watcher_count_key, @project_watcher_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {project_watcher_count: @project_watcher_count})
|
||||
end
|
||||
end
|
||||
if @pullrequest_count.present?
|
||||
if $redis_cache.hget(user_statistic_key, pullrequest_count_key).nil?
|
||||
reset_user_pullrequest_count
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {pullrequest_count: @pullrequest_count})
|
||||
else
|
||||
$redis_cache.hincrby(user_statistic_key, pullrequest_count_key, @pullrequest_count)
|
||||
Cache::V2::UserDateRankService.call(@user_id, Date.today, {pullrequest_count: @pullrequest_count})
|
||||
end
|
||||
end
|
||||
$redis_cache.hgetall(user_statistic_key)
|
||||
end
|
||||
|
||||
def reset_user_follow_count
|
||||
$redis_cache.hset(user_statistic_key, follow_count_key, Watcher.where(watchable_type: 'User', watchable_id: @user_id).count)
|
||||
end
|
||||
|
||||
def reset_user_fork_count
|
||||
$redis_cache.hset(user_statistic_key, fork_count_key, ForkUser.joins(:project).where(projects: {user_id: @user_id}).count)
|
||||
end
|
||||
|
||||
def reset_user_issue_count
|
||||
$redis_cache.hset(user_statistic_key, issue_count_key, Issue.where(author_id: @user_id).count)
|
||||
end
|
||||
|
||||
def reset_user_project_count
|
||||
$redis_cache.hset(user_statistic_key, project_count_key, Project.where(user_id: @user_id).count)
|
||||
end
|
||||
|
||||
def reset_user_project_language
|
||||
$redis_cache.hset(user_statistic_key, project_language_key, Project.where(user_id: @user_id).joins(:project_language).group("project_languages.name").count.to_json)
|
||||
end
|
||||
|
||||
def reset_user_project_praise_count
|
||||
$redis_cache.hset(user_statistic_key, project_praise_count_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: Project.where(user_id: @user_id)).count)
|
||||
end
|
||||
|
||||
def reset_user_project_watcher_count
|
||||
$redis_cache.hset(user_statistic_key, project_watcher_count_key, Watcher.where(watchable_type: 'Project', watchable_id: Project.where(user_id: @user_id)).count)
|
||||
end
|
||||
|
||||
def reset_user_pullrequest_count
|
||||
$redis_cache.hset(user_statistic_key, pullrequest_count_key, PullRequest.where(user_id: @user_id).count)
|
||||
end
|
||||
|
||||
def reset_user_statistic
|
||||
$redis_cache.del(user_statistic_key)
|
||||
reset_user_follow_count
|
||||
reset_user_fork_count
|
||||
reset_user_issue_count
|
||||
reset_user_project_count
|
||||
reset_user_project_language
|
||||
reset_user_project_praise_count
|
||||
reset_user_project_watcher_count
|
||||
reset_user_pullrequest_count
|
||||
|
||||
$redis_cache.hgetall(user_statistic_key)
|
||||
end
|
||||
end
|
||||
|
|
@ -82,6 +82,8 @@ class Gitea::ClientService < ApplicationService
|
|||
req.headers['Content-Type'] = 'application/json'
|
||||
req.response :logger # 显示日志
|
||||
req.adapter Faraday.default_adapter
|
||||
req.options.timeout = 100 # open/read timeout in seconds
|
||||
req.options.open_timeout = 10 # connection open timeout in seconds
|
||||
if token.blank?
|
||||
req.basic_auth(username, secret)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
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:
|
||||
##### code: #{code} login: #{login} namespace: #{namespace} password: #{password} "
|
||||
|
||||
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
|
||||
end
|
||||
|
|
@ -7,9 +7,33 @@
|
|||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<%= form_for @project_category, url: {controller: "project_categories", action: "#{type}"} do |p| %>
|
||||
<%= form_for @project_category, url: {controller: "project_categories", action: "#{type}"}, html: { enctype: 'multipart/form-data' } do |p| %>
|
||||
<div class="modal-body">
|
||||
<%= p.text_field :name,class: "form-control input-lg",placeholder: "分类名称",required: true, maxlength: 64%>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
分类名称 <span class="ml10 color-orange mr20">*</span>
|
||||
</label>
|
||||
<%= p.text_field :name,class: "form-control input-lg",placeholder: "分类名称",required: true, maxlength: 64%>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
精选等级
|
||||
</label>
|
||||
<%= p.number_field :pinned_index,class: "form-control input-lg",placeholder: "精选等级",required: true%>
|
||||
</div>
|
||||
<div class="logo-item">
|
||||
<% logo_img = @project_category.logo_url %>
|
||||
<div class="logo-item-left mr-3 <%= logo_img ? 'has-img' : '' %>">
|
||||
<img class="logo-item-img nav-logo-img" src="<%= logo_img %>" style="<%= logo_img.present? ? '' : 'display: none' %>"/>
|
||||
<%= file_field_tag(:logo, accept: 'image/png,image/jpg,image/jpeg',style: "display: none", value: params[:logo]) %>
|
||||
<label for="logo" class="logo-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
|
||||
</div>
|
||||
<div class="logo-item-right">
|
||||
<div class="logo-item-title flex-1">logo</div>
|
||||
<div>格式:PNG、JPG</div>
|
||||
<div>尺寸:高度38px以内,宽等比例缩放</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
<tr>
|
||||
<th width="5%">序号</th>
|
||||
<th width="30%">名称</th>
|
||||
<th width="20%"><%= sort_tag('精选', name: 'pinned_index', path: admins_project_categories_path) %></th>
|
||||
<th width="20%"><%= sort_tag('项目数', name: 'projects_count', path: admins_project_categories_path) %></th>
|
||||
<th width="20%">精选项目数</th>
|
||||
<th width="20%"><%= sort_tag('创建时间', name: 'created_at', path: admins_project_categories_path) %></th>
|
||||
<th width="25%">操作</th>
|
||||
</tr>
|
||||
|
|
@ -16,7 +18,9 @@
|
|||
<td>
|
||||
<%= link_to(project_category.name, "/projects?category_id=#{project_category.id}", target: '_blank') %>
|
||||
</td>
|
||||
<td><%= project_category.pinned_index == 0 ? "" : "√" %></td>
|
||||
<td><%= project_category.projects_count %></td>
|
||||
<td><%= project_category.projects.where(is_pinned: true).size %></td>
|
||||
<td><%= project_category.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<%= link_to "编辑", edit_admins_project_category_path(project_category), remote: true, class: "action" %>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,19 @@
|
|||
$("#project-category-modals").html("<%= j render(partial: 'admins/project_categories/form_modal', locals: {type: 'update'}) %>")
|
||||
$(".project-category-change-modal").modal('show');
|
||||
$(".project-category-change-modal").modal('show');
|
||||
|
||||
|
||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||
var $fileInput = $(this);
|
||||
var file = this.files[0];
|
||||
var imageType = /image.*/;
|
||||
if (file && file.type.match(imageType)) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
var $box = $fileInput.parent();
|
||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||
$box.addClass('has-img');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
$("#projects-modals").html("<%= j render(partial: 'admins/projects/shared/form_modal', locals: {type: 'update'}) %>")
|
||||
$(".project-change-modal").modal('show');
|
||||
|
|
@ -12,4 +12,7 @@
|
|||
|
||||
<div class="box admin-list-container project-list-container">
|
||||
<%= render partial: 'admins/projects/shared/list', locals: { projects: @projects } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="projects-modals">
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<div class="modal fade project-change-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><%= type == "create" ? "新增" : "编辑" %></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<%= form_for @project, url: {controller: "projects", action: "#{type}"} do |p| %>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>
|
||||
推荐等级
|
||||
</label>
|
||||
<%= p.number_field :recommend_index,class: "form-control input-lg",required: true%>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
|
||||
<%= p.submit "确认", class: "btn btn-primary submit-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
<table class="table table-hover text-center subject-list-table">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th width="4%">序号</th>
|
||||
<th width="4%">ID</th>
|
||||
<th width="15%" class="text-left">项目名称</th>
|
||||
<th width="6%">序号</th>
|
||||
<th width="6%">ID</th>
|
||||
<th width="20%" class="text-left">项目名称</th>
|
||||
<th width="6%">公开</th>
|
||||
<th width="6%">精选</th>
|
||||
<th width="6%">推荐</th>
|
||||
<th width="5%">issue</th>
|
||||
<th width="5%">资源</th>
|
||||
<th width="6%">版本库</th>
|
||||
|
|
@ -12,8 +14,8 @@
|
|||
<th width="6%">里程碑</th>
|
||||
<th width="10%">成员</th>
|
||||
<th width="10%">管理员</th>
|
||||
<th width="11%"><%= sort_tag('创建时间', name: 'created_on', path: admins_projects_path) %></th>
|
||||
<th width="10%">操作</th>
|
||||
<th width="15%"><%= sort_tag('创建时间', name: 'created_on', path: admins_projects_path) %></th>
|
||||
<th width="25%">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -26,6 +28,8 @@
|
|||
<%= link_to(project.name, "/projects/#{project&.owner&.login}/#{project.identifier}", target: '_blank') %>
|
||||
</td>
|
||||
<td><%= project.is_public ? '√' : '' %></td>
|
||||
<td><%= project.is_pinned ? '√' : '' %></td>
|
||||
<td><%= project.recommend ? '√' : '' %></td>
|
||||
<td><%= project.issues.size %></td>
|
||||
<td><%= project.attachments.size %></td>
|
||||
<td><%= project&.project_score.try(:changeset_num).to_i %></td>
|
||||
|
|
@ -37,8 +41,15 @@
|
|||
</td>
|
||||
<td><%= project.created_on&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<% 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;' %>
|
||||
<% end %>
|
||||
<%= link_to "删除", admins_project_path(project.id), method: :delete, data:{confirm: "确认删除的吗?"}, class: "delete-project-action" %>
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% else %>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
json.organizations @organizations do |organization|
|
||||
json.id organization.id
|
||||
json.name organization.login
|
||||
json.nickname organization.nickname.blank? ? organization.name : organization.nickname
|
||||
json.avatar_url url_to_avatar(organization)
|
||||
json.organizations do
|
||||
|
||||
json.array! @organizations.each do |group|
|
||||
json.array! group.each do |organization|
|
||||
json.id organization.id
|
||||
json.name organization.login
|
||||
json.nickname organization.real_name
|
||||
json.avatar_url url_to_avatar(organization)
|
||||
json.website organization.website
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
json.project_categories @project_categories, :id, :name, :logo_url
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
project_common = $redis_cache.hgetall("v2-project-common:#{item[0]}")
|
||||
owner_common = $redis_cache.hgetall("v2-owner-common:#{project_common["owner_id"]}")
|
||||
json.id item[0]
|
||||
json.score item[1]
|
||||
json.name project_common["name"]
|
||||
json.identifier project_common["identifier"]
|
||||
json.description project_common["description"]
|
||||
json.owner do
|
||||
json.id project_common["owner_id"]
|
||||
json.type owner_common["type"]
|
||||
json.name owner_common["name"]
|
||||
json.login owner_common["login"]
|
||||
json.avatar_url owner_common["avatar_url"]
|
||||
end
|
||||
json.visits project_common["visits"]
|
||||
json.forks project_common["forks"]
|
||||
json.watchers project_common["watchers"]
|
||||
json.praises project_common["praises"]
|
||||
json.issues project_common["issues"]
|
||||
json.pulls project_common["pullrequests"]
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
json.partial! "commons/success"
|
||||
json.projects do
|
||||
|
||||
json.array! @project_rank.each do |item|
|
||||
json.partial! "detail", locals: {item: item}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
json.partial! "commons/success"
|
||||
json.projects do
|
||||
json.array! @projects do |project|
|
||||
owner = project.owner
|
||||
json.id project.id
|
||||
json.identifier project.identifier
|
||||
json.name project.name
|
||||
json.description project.description
|
||||
json.visits project.visits
|
||||
json.author do
|
||||
json.name owner.try(:show_real_name)
|
||||
json.type owner.type
|
||||
json.login owner.login
|
||||
json.image_url url_to_avatar(owner)
|
||||
end
|
||||
|
||||
json.category do
|
||||
if project.project_category.blank?
|
||||
json.nil!
|
||||
else
|
||||
json.id project.project_category.id
|
||||
json.name project.project_category.name
|
||||
end
|
||||
end
|
||||
|
||||
json.language do
|
||||
if project.project_language.blank?
|
||||
json.nil!
|
||||
else
|
||||
json.id project.project_language.id
|
||||
json.name project.project_language.name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
json.total_count @total_count
|
||||
json.total_count @projects.total_count
|
||||
json.projects @projects do |project|
|
||||
# json.partial! "/projects/project_detail", project: project
|
||||
json.id project.id
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ json.setting do
|
|||
if @top_system_notification.present?
|
||||
json.system_notification do
|
||||
json.(@top_system_notification, :id, :subject, :sub_subject, :content)
|
||||
json.is_read @top_system_notification.read_member?(current_user&.id)
|
||||
end
|
||||
else
|
||||
json.system_notification nil
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>验证码发送</title>
|
||||
<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;}
|
||||
|
|
@ -27,8 +27,8 @@
|
|||
<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.educoder.net">
|
||||
<img src="https://www.educoder.net/images/educoder/headNavLogo.png" width="36" style="float:left; margin-top: 8px;" >
|
||||
<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>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
您好!
|
||||
</p>
|
||||
<p style="color:#333;">
|
||||
您正在注册Educoder,请在10分钟内在注册页输入此验证码,并进行下一步操作。
|
||||
您正在注册GitLink,请在10分钟内在注册页输入此验证码,并进行下一步操作。
|
||||
如非你本人操作,请忽略此邮件。
|
||||
</p>
|
||||
<div style="text-align: center;">
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
</div>
|
||||
<span style="font-weight: normal;color:#666;">
|
||||
此邮件为系统所发,请勿直接回复。<br/>
|
||||
要解决问题或了解您的帐户详情,您可以访问 <a href="https://www.educoder.net/help?index=5" style="font-weight: normal; color:#ff7500;">帮助中心</a>。
|
||||
要解决问题或了解您的帐户详情,您可以访问 <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;">
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
</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.educoder.net/" style="font-weight: normal; color:#fff;">www.educoder.net</a>
|
||||
<a href="https:///www.gitlink.org.cn" style="font-weight: normal; color:#fff;">www.gitlink.org.cn</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
owner_common = $redis_cache.hgetall("v2-owner-common:#{item[0]}")
|
||||
popular_project = $redis_cache.zrevrange("v2-user-project-rank:#{item[0]}", 0, 1, withscores: true)[0]
|
||||
popular_project_common = $redis_cache.hgetall("v2-project-common:#{popular_project[0]}")
|
||||
json.id item[0]
|
||||
json.score item[1]
|
||||
json.name owner_common["name"]
|
||||
json.type owner_common["type"]
|
||||
json.login owner_common["login"]
|
||||
json.avatar_url owner_common["avatar_url"]
|
||||
json.project do
|
||||
json.id popular_project[0]
|
||||
json.name popular_project_common["name"]
|
||||
json.identifier popular_project_common["identifier"]
|
||||
json.description popular_project_common["description"]
|
||||
end
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
json.partial! "commons/success"
|
||||
json.users do
|
||||
|
||||
json.array! @user_rank.each do |item|
|
||||
json.partial! "detail", locals: {item: item}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
user = $redis_cache.hgetall("v2-owner-common:#{name}-#{email}")
|
||||
if user.blank?
|
||||
json.id nil
|
||||
json.type nil
|
||||
json.login name
|
||||
json.name name
|
||||
json.email email
|
||||
json.image_url User::Avatar.get_letter_avatar_url(name)
|
||||
else
|
||||
json.id user["id"]
|
||||
json.type user["type"]
|
||||
json.login user["login"]
|
||||
json.name user["name"]
|
||||
json.email user["email"]
|
||||
json.image_url user["avatar_url"]
|
||||
end
|
||||
|
|
@ -2,7 +2,7 @@ default: &default
|
|||
# 用户登入的时候设置/登出的时候清空
|
||||
autologin_cookie_name: 'autologin_trustie'
|
||||
platform_url: 'http://localhost:3000'
|
||||
|
||||
sign_key: ''
|
||||
|
||||
#附件上传路径
|
||||
attachment_folder: '/tmp'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
zh-CN:
|
||||
activerecord:
|
||||
attributes:
|
||||
system_notification_history:
|
||||
system_notification: "系统通知"
|
||||
system_notification_id: "系统通知"
|
||||
|
|
@ -73,6 +73,9 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :public_keys, only: [:index, :create, :destroy]
|
||||
|
||||
resources :project_rank, only: [:index]
|
||||
resources :user_rank, only: [:index]
|
||||
|
||||
resources :statistic, only: [:index] do
|
||||
collection do
|
||||
get :platform_profile
|
||||
|
|
@ -156,6 +159,7 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :project_categories, only: [:index, :show] do
|
||||
get :group_list, on: :collection
|
||||
get :pinned_index, on: :collection
|
||||
end
|
||||
resources :project_languages, only: [:index, :show]
|
||||
resources :ignores, only: [:index, :show]
|
||||
|
|
@ -181,6 +185,7 @@ Rails.application.routes.draw do
|
|||
post :migrate
|
||||
get :group_type_list
|
||||
get :recommend
|
||||
get :banner_recommend
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -197,6 +202,7 @@ Rails.application.routes.draw do
|
|||
post :remote_login
|
||||
post :remote_password
|
||||
post :change_password
|
||||
post :check
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -267,6 +273,7 @@ Rails.application.routes.draw do
|
|||
scope module: :users do
|
||||
get 'template_message_settings', to: 'template_message_settings#current_setting'
|
||||
post 'template_message_settings/update_setting', to: 'template_message_settings#update_setting'
|
||||
resources :system_notification_histories, only: [:create]
|
||||
resources :applied_messages, only: [:index]
|
||||
resources :applied_transfer_projects, only: [:index] do
|
||||
member do
|
||||
|
|
@ -674,7 +681,11 @@ Rails.application.routes.draw do
|
|||
resources :project_licenses
|
||||
resources :project_ignores
|
||||
resources :reversed_keywords
|
||||
resources :system_notifications
|
||||
resources :system_notifications do
|
||||
member do
|
||||
get :history
|
||||
end
|
||||
end
|
||||
resources :message_templates, only: [:index, :edit, :update] do
|
||||
collection do
|
||||
get :init_data
|
||||
|
|
@ -904,7 +915,7 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :courses, only: [:index, :destroy, :update]
|
||||
|
||||
resources :projects, only: [:index, :destroy]
|
||||
resources :projects, only: [:index, :edit, :update, :destroy]
|
||||
|
||||
resources :disciplines, only: [:index, :create, :edit, :update, :destroy] do
|
||||
post :adjust_position, on: :member
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
class CreateSystemNotificationHistories < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :system_notification_histories do |t|
|
||||
t.references :system_notification
|
||||
t.references :user
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
class AddSomeColumnsToProjectDetailFeature < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :project_categories, :pinned_index, :integer, default: 0
|
||||
add_column :projects, :is_pinned, :boolean, default: false
|
||||
add_column :projects, :recommend_index, :integer, default: 0
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class AddRecommendToOrganizationExtensions < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :organization_extensions, :recommend, :boolean, default: false
|
||||
end
|
||||
end
|
||||
|
|
@ -348,6 +348,9 @@
|
|||
<li>
|
||||
<a href="#5b752913ae" class="toc-h2 toc-link" data-title="用户消息列表">用户消息列表</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#6087e717ed" class="toc-h2 toc-link" data-title="用户阅读系统通知">用户阅读系统通知</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#94306b2fc3" class="toc-h2 toc-link" data-title="发送消息">发送消息</a>
|
||||
</li>
|
||||
|
|
@ -1337,7 +1340,39 @@ Success — a happy kitten is an authenticated kitten!
|
|||
<aside class="success">
|
||||
Success Data.
|
||||
</aside>
|
||||
<h2 id='94306b2fc3'>发送消息</h2>
|
||||
<h2 id='6087e717ed'>用户阅读系统通知</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/users/yystopf/system_notification_histories.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/users/:login/system_notification_histories.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-3'>HTTP 请求</h3>
|
||||
<p><code>POST /api/users/:login/system_notification_histories.json</code></p>
|
||||
<h3 id='aa883f5d52-2'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
<th>类型</th>
|
||||
<th>字段说明</th>
|
||||
</tr>
|
||||
</thead><tbody>
|
||||
<tr>
|
||||
<td>system_notification_id</td>
|
||||
<td>integer</td>
|
||||
<td>阅读的系统通知id</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">"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='94306b2fc3'>发送消息</h2>
|
||||
<p>发送消息, 目前只支持atme</p>
|
||||
|
||||
<blockquote>
|
||||
|
|
@ -1345,9 +1380,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/:login/messages.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/users/:login/messages.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-3'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-4'>HTTP 请求</h3>
|
||||
<p><code>POST api/users/yystopf/messages.json</code></p>
|
||||
<h3 id='aa883f5d52-2'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-3'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -1406,9 +1441,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/:login/messages/read.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/users/:login/messages/read.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-4'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-5'>HTTP 请求</h3>
|
||||
<p><code>POST api/users/yystopf/messages/read.json</code></p>
|
||||
<h3 id='aa883f5d52-3'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-4'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -1447,9 +1482,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> DELETE http://localhost:3000/api/users/:login/messages.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">DELETE /api/users/:login/messages.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-5'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-6'>HTTP 请求</h3>
|
||||
<p><code>DELETE api/users/yystopf/messages.json</code></p>
|
||||
<h3 id='aa883f5d52-4'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-5'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -1488,9 +1523,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> PATCH/PUT http://localhost:3000/api/users/yystopf.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/PUT /api/users/:login.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-6'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-7'>HTTP 请求</h3>
|
||||
<p><code>PATCH/PUT /api/users/:login.json</code></p>
|
||||
<h3 id='aa883f5d52-5'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-6'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -1586,7 +1621,7 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/template_message_settings.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/template_message_settings.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-7'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-8'>HTTP 请求</h3>
|
||||
<p><code>GET /api/template_message_settings.json</code></p>
|
||||
<h3 id='7447e4874e-3'>返回字段说明:</h3>
|
||||
<table><thead>
|
||||
|
|
@ -1729,7 +1764,7 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/template_message_settings.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/uses/yystopf/template_message_settings.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-8'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-9'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:user_id/template_message_settings.json</code></p>
|
||||
<h3 id='7447e4874e-4'>返回字段说明:</h3>
|
||||
<table><thead>
|
||||
|
|
@ -1799,9 +1834,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/yystopf/template_message_settings/update_setting.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/uses/yystopf/template_message_settings/update_setting.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-9'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-10'>HTTP 请求</h3>
|
||||
<p><code>POST /api/users/:user_id/template_message_settings/update_setting.json</code></p>
|
||||
<h3 id='aa883f5d52-6'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-7'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -1918,7 +1953,7 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/is_pinned_projects.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/users/:login/is_pinned_projects.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-10'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-11'>HTTP 请求</h3>
|
||||
<p><code>GET api/users/:login/is_pinned_projects.json</code></p>
|
||||
<h3 id='7447e4874e-6'>返回字段说明:</h3>
|
||||
<table><thead>
|
||||
|
|
@ -2105,9 +2140,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.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/users/:login/is_pinned_projects/pin.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-11'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-12'>HTTP 请求</h3>
|
||||
<p><code>POST /api/users/:login/is_pinned_projects/pin.json</code></p>
|
||||
<h3 id='aa883f5d52-7'>请求字段说明:</h3><h4 id='0ca7f0efb8'>同时设定多个星标项目</h4>
|
||||
<h3 id='aa883f5d52-8'>请求字段说明:</h3><h4 id='0ca7f0efb8'>同时设定多个星标项目</h4>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -2151,9 +2186,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.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/PUT /api/users/:login/is_pinned_projects/:id.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-12'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-13'>HTTP 请求</h3>
|
||||
<p><code>PATCH/PUT /api/users/:login/is_pinned_projects/:id.json</code></p>
|
||||
<h3 id='aa883f5d52-8'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-9'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -2192,7 +2227,7 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/statistics/activity.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/users/:login/statistics/activity.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-13'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-14'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/statistics/activity.json</code></p>
|
||||
<h3 id='7447e4874e-7'>返回字段说明:</h3>
|
||||
<table><thead>
|
||||
|
|
@ -2281,9 +2316,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/headmaps.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/users/:login/headmaps.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-14'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-15'>HTTP 请求</h3>
|
||||
<p><code>GET api/users/:login/headmaps.json</code></p>
|
||||
<h3 id='aa883f5d52-9'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-10'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -2426,9 +2461,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/project_trends.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/users/:login/project_trends.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-15'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-16'>HTTP 请求</h3>
|
||||
<p><code>GET api/users/:login/project_trends.json</code></p>
|
||||
<h3 id='aa883f5d52-10'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-11'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -2743,9 +2778,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/statistics/develop.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/users/:login/statistics/develop.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-16'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-17'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/statistics/develop.json</code></p>
|
||||
<h3 id='aa883f5d52-11'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-12'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -2886,9 +2921,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/statistics/role.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/users/:login/statistics/role.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-17'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-18'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/statistics/role.json</code></p>
|
||||
<h3 id='aa883f5d52-12'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-13'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -2968,9 +3003,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/statistics/major.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/users/:login/statistics/major.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-18'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-19'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/statistics/major.json</code></p>
|
||||
<h3 id='aa883f5d52-13'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-14'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -3029,9 +3064,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/applied_messages.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/users/:login/applied_messages.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-19'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-20'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_messages.json</code></p>
|
||||
<h3 id='aa883f5d52-14'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-15'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -3308,9 +3343,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.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/users/:login/applied_transfer_projects.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-20'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-21'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_transfer_projects.json</code></p>
|
||||
<h3 id='aa883f5d52-15'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-16'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -3500,9 +3535,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.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/users/:login/applied_transfer_projects/:id/accept.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-21'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-22'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_transfer_projects/:id/accept.json</code></p>
|
||||
<h3 id='aa883f5d52-16'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-17'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -3691,9 +3726,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.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/users/:login/applied_transfer_projects/:id/refuse.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-22'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-23'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_transfer_projects/:id/refuse.json</code></p>
|
||||
<h3 id='aa883f5d52-17'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-18'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -3882,9 +3917,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> GET http://localhost:3000/api/users/yystopf/applied_projects.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/users/:login/applied_projects.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-23'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-24'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_projects.json</code></p>
|
||||
<h3 id='aa883f5d52-18'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-19'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -4042,9 +4077,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/yystopf/applied_projects/2/accept.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/users/:login/applied_projects/:id/accept.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-24'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-25'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_projects/:id/accept.json</code></p>
|
||||
<h3 id='aa883f5d52-19'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-20'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
@ -4201,9 +4236,9 @@ Success — a happy kitten is an authenticated kitten!
|
|||
</blockquote>
|
||||
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">-X</span> POST http://localhost:3000/api/users/yystopf/applied_projects/2/refuse.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/users/:login/applied_projects/:id/refuse.json</span><span class="dl">'</span><span class="p">)</span>
|
||||
</code></pre></div><h3 id='http-25'>HTTP 请求</h3>
|
||||
</code></pre></div><h3 id='http-26'>HTTP 请求</h3>
|
||||
<p><code>GET /api/users/:login/applied_projects/:id/refuse.json</code></p>
|
||||
<h3 id='aa883f5d52-20'>请求字段说明:</h3>
|
||||
<h3 id='aa883f5d52-21'>请求字段说明:</h3>
|
||||
<table><thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
|
|
|
|||
Loading…
Reference in New Issue