Merge pull request 'nanda版本' (#318) from qyzh1996/forgeplus:sponsor into dev_nanda

This commit is contained in:
xxq250 2023-01-12 17:40:18 +08:00
commit 3612c8aa60
303 changed files with 2601 additions and 1655 deletions

2
.gitignore vendored
View File

@ -73,7 +73,7 @@ vendor/bundle/
/public/admin /public/admin
/mysql_data /mysql_data
/public/repo/ /public/repo/
/coverage
.generators .generators
.rakeTasks .rakeTasks

View File

@ -59,6 +59,7 @@ gem 'ransack'
group :development, :test do group :development, :test do
gem 'rspec-rails', '~> 3.8' gem 'rspec-rails', '~> 3.8'
gem 'rails-controller-testing'
end end
group :development do group :development do
@ -77,6 +78,7 @@ group :test do
gem 'capybara', '>= 2.15', '< 4.0' gem 'capybara', '>= 2.15', '< 4.0'
gem 'selenium-webdriver' gem 'selenium-webdriver'
gem 'chromedriver-helper' gem 'chromedriver-helper'
gem 'simplecov', '~>0.12.0', require: false
end end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
@ -101,6 +103,7 @@ gem 'rails-i18n', '~> 5.1'
gem 'sidekiq',"5.2.8" gem 'sidekiq',"5.2.8"
gem 'sinatra' gem 'sinatra'
gem "sidekiq-cron", "1.2.0" gem "sidekiq-cron", "1.2.0"
gem 'whenever'
# batch insert # batch insert
gem 'bulk_insert' gem 'bulk_insert'
@ -131,6 +134,9 @@ gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1' gem 'parallel', '~> 1.19', '>= 1.19.1'
# log
gem 'multi_logger'
gem 'letter_avatar' gem 'letter_avatar'
gem 'jwt' gem 'jwt'

View File

@ -121,4 +121,4 @@ You may obtain a copy of Mulan PSL v2 at:
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. See the Mulan PSL v2 for more details.

View File

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

View File

@ -0,0 +1,3 @@
// Place all the styles related to the log controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -0,0 +1,84 @@
body {
background-color: #fff;
color: #333;
margin: 33px;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}
a {
color: #000;
&:visited {
color: #666;
}
&:hover {
color: #fff;
background-color: #000;
}
}
th {
padding-bottom: 5px;
}
td {
padding: 0 5px 7px;
}
div {
&.field, &.actions {
margin-bottom: 10px;
}
}
#notice {
color: green;
}
.field_with_errors {
padding: 2px;
background-color: red;
display: table;
}
#error_explanation {
width: 450px;
border: 2px solid red;
padding: 7px 7px 0;
margin-bottom: 20px;
background-color: #f0f0f0;
h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px -7px 0;
background-color: #c00;
color: #fff;
}
ul li {
font-size: 12px;
list-style: square;
}
}
label {
display: block;
}

View File

@ -0,0 +1,3 @@
// Place all the styles related to the SponsorTiers controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -0,0 +1,3 @@
// Place all the styles related to the Sponsorships controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -0,0 +1,3 @@
// Place all the styles related to the Wallets controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -4,13 +4,13 @@ class AccountsController < ApplicationController
#skip_before_action :check_account, :only => [:logout] #skip_before_action :check_account, :only => [:logout]
def simple_update def simple_update
simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, "")) simple_update_params.merge!(username: params[:username]&.gsub(/\s+/, ""))
simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, "")) simple_update_params.merge!(email: params[:email]&.gsub(/\s+/, ""))
simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, "")) simple_update_params.merge!(platform: (params[:platform] || 'forge')&.gsub(/\s+/, ""))
Register::RemoteForm.new(simple_update_params).validate! Register::RemoteForm.new(simple_update_params).validate!
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
result = auto_update(current_user, simple_update_params) result = auto_update(current_user, simple_update_params)
if result[:message].blank? if result[:message].blank?
render_ok render_ok
@ -270,6 +270,7 @@ class AccountsController < ApplicationController
set_autologin_cookie(user) set_autologin_cookie(user)
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
# user.daily_reward
user.update_column(:last_login_on, Time.now) user.update_column(:last_login_on, Time.now)
session[:"#{default_yun_session}"] = user.id session[:"#{default_yun_session}"] = user.id
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}") Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
@ -342,11 +343,11 @@ class AccountsController < ApplicationController
render_ok render_ok
end end
def login_check def login_check
Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate! Register::LoginCheckColumnsForm.new(check_params.merge(user: current_user)).validate!
render_ok render_ok
end end
private private
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加 # type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
@ -389,7 +390,7 @@ class AccountsController < ApplicationController
params.require(:user).permit(:login, :email, :phone) params.require(:user).permit(:login, :email, :phone)
end end
def login_params def login_params
params.require(:account).permit(:login, :password) params.require(:account).permit(:login, :password)
end end
@ -404,7 +405,7 @@ class AccountsController < ApplicationController
def reset_password_params def reset_password_params
params.permit(:login, :password, :password_confirmation, :code) params.permit(:login, :password, :password_confirmation, :code)
end end
def find_user def find_user
phone_or_mail = strip(reset_password_params[:login]) phone_or_mail = strip(reset_password_params[:login])
User.where("phone = :search OR mail = :search", search: phone_or_mail).last User.where("phone = :search OR mail = :search", search: phone_or_mail).last
@ -413,7 +414,7 @@ class AccountsController < ApplicationController
def remote_register_params def remote_register_params
params.permit(:username, :email, :password, :platform) params.permit(:username, :email, :password, :platform)
end end
def simple_update_params def simple_update_params
params.permit(:username, :email, :password, :platform) params.permit(:username, :email, :password, :platform)
end end

View File

@ -10,12 +10,14 @@ class ApplicationController < ActionController::Base
include LoggerHelper include LoggerHelper
include LoginHelper include LoginHelper
include RegisterHelper include RegisterHelper
include UpdateHelper
protect_from_forgery prepend: true, unless: -> { request.format.json? } protect_from_forgery prepend: true, unless: -> { request.format.json? }
before_action :check_sign before_action :check_sign
before_action :user_setup before_action :user_setup
#before_action :check_account #before_action :check_account
after_action :user_trace_log
# TODO # TODO
# check sql query time # check sql query time
@ -25,6 +27,8 @@ class ApplicationController < ActionController::Base
# end # end
end end
before_action :update_last_login_on
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) 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 = Rails.application.config_for(:configuration)['sign_key'] || "79e33abd4b6588941ab7622aed1e67e8" OPENKEY = Rails.application.config_for(:configuration)['sign_key'] || "79e33abd4b6588941ab7622aed1e67e8"
@ -82,7 +86,7 @@ class ApplicationController < ActionController::Base
unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/
tip_exception(-2, "请输入正确的手机号或邮箱") tip_exception(-2, "请输入正确的手机号或邮箱")
end end
user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login) user_exist = Owner.exists?(phone: login) || Owner.exists?(mail: login)
if user_exist && type.to_i == 1 if user_exist && type.to_i == 1
tip_exception(-2, "该手机号码或邮箱已被注册") tip_exception(-2, "该手机号码或邮箱已被注册")
@ -305,7 +309,7 @@ class ApplicationController < ActionController::Base
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id) User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
end end
end end
else else
User.current = find_current_user User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
@ -363,7 +367,19 @@ class ApplicationController < ActionController::Base
# RSS key authentication does not start a session # RSS key authentication does not start a session
User.find_by_rss_key(params[:key]) User.find_by_rss_key(params[:key])
end end
end end
def user_trace_log
user = current_user
# print("*********************url:", request.url, "****routes", request.request_method)
Rails.logger.user_trace.info("{id: #{user.id}, login: #{user.login}, url: #{request.url}, method: #{request.method}, params: #{params}, response_code: #{response.code}, time: #{Time.now}}")
end
def user_trace_update_log(old_value_hash)
user = current_user
str = "{id: #{user.id}, login: #{user.login}, url: #{request.url}, method: #{request.method}, params: #{params.merge(old_value: old_value_hash)}, response_code: #{response.code}, time: #{Time.now}}"
Rails.logger.user_trace.info(str)
end
def try_to_autologin def try_to_autologin
if cookies[autologin_cookie_name] if cookies[autologin_cookie_name]
@ -389,12 +405,17 @@ class ApplicationController < ActionController::Base
respond_to do |format| respond_to do |format|
format.json format.json
end end
end end
## 输出错误信息 ## 输出错误信息
def error_status(message = nil) def error_status(message = nil)
@status = -1 @status = -1
@message = message @message = message
end
# 实训等对应的仓库地址
def repo_ip_url(repo_path)
"#{edu_setting('git_address_ip')}/#{repo_path}"
end end
def repo_url(repo_path) def repo_url(repo_path)
@ -633,6 +654,23 @@ class ApplicationController < ActionController::Base
ss ss
end end
def strip_html(text, len=0, endss="...")
ss = ""
if !text.nil? && text.length>0
ss=text.gsub(/<\/?.*?>/, '').strip
ss = ss.gsub(/&nbsp;*/, '')
ss = ss.gsub(/\r\n/,'') #新增
ss = ss.gsub(/\n/,'') #新增
if len > 0 && ss.length > len
ss = ss[0, len] + endss
elsif len > 0 && ss.length <= len
ss = ss
#ss = truncate(ss, :length => len)
end
end
ss
end
# Returns a string that can be used as filename value in Content-Disposition header # Returns a string that can be used as filename value in Content-Disposition header
def filename_for_content_disposition(name) def filename_for_content_disposition(name)
request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name
@ -644,8 +682,8 @@ class ApplicationController < ActionController::Base
# 获取Oauth Client # 获取Oauth Client
def get_client(site) def get_client(site)
client_id = Rails.configuration.Gitlink['client_id'] client_id = Rails.configuration.educoder['client_id']
client_secret = Rails.configuration.Gitlink['client_secret'] client_secret = Rails.configuration.educoder['client_secret']
OAuth2::Client.new(client_id, client_secret, site: site) OAuth2::Client.new(client_id, client_secret, site: site)
end end
@ -665,7 +703,7 @@ class ApplicationController < ActionController::Base
def kaminari_paginate(relation) def kaminari_paginate(relation)
limit = params[:limit] || params[:per_page] limit = params[:limit] || params[:per_page]
limit = (limit.to_i.zero? || limit.to_i > 50) ? 50 : limit.to_i limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i
page = params[:page].to_i.zero? ? 1 : params[:page].to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i
relation.page(page).per(limit) relation.page(page).per(limit)
@ -750,11 +788,11 @@ class ApplicationController < ActionController::Base
# @project = nil if !@project.is_public? # @project = nil if !@project.is_public?
# render_forbidden and return # render_forbidden and return
else else
if @project.present? if @project.present?
logger.info "########### has project and but can't read project" logger.info "########### has project and but can't read project"
@project = nil @project = nil
render_forbidden and return render_forbidden and return
else else
logger.info "###########project not found" logger.info "###########project not found"
@project = nil @project = nil
render_not_found and return render_not_found and return
@ -799,21 +837,54 @@ class ApplicationController < ActionController::Base
end end
private private
def object_not_found def update_last_login_on
uid_logger("Missing template or cant't find record, responding with 404") if current_user.logged?
render json: {message: "您访问的页面不存在或已被删除", status: 404} current_user.update_column(:last_login_on, Time.now)
false end
end end
def object_not_found
uid_logger("Missing template or cant't find record, responding with 404")
render json: {message: "您访问的页面不存在或已被删除", status: 404}
false
end
def tip_show(exception) def tip_show(exception)
uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") uid_logger("Tip show status is #{exception.status}, message is #{exception.message}")
render json: exception.tip_json render json: exception.tip_json
end end
def render_parameter_missing
render json: { status: -1, message: '参数缺失' }
end
def set_export_cookies def set_export_cookies
cookies[:fileDownload] = true cookies[:fileDownload] = true
end 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 def record_search_keyword
keyword = params[:keyword].to_s.strip keyword = params[:keyword].to_s.strip

View File

@ -6,10 +6,10 @@ class CompareController < ApplicationController
end end
def show def show
if params[:type] == "sha" if params[:type] == "sha"
load_compare_params load_compare_params
@compare_result ||= gitea_compare(@base, @head) @compare_result ||= gitea_compare(@base, @head)
else else
load_compare_params load_compare_params
compare compare
@merge_status, @merge_message = get_merge_message @merge_status, @merge_message = get_merge_message
@ -63,7 +63,7 @@ class CompareController < ApplicationController
Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token) Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, Addressable::URI.escape(base), Addressable::URI.escape(head), current_user.gitea_token)
end end
def page_size def page_size
params.fetch(:page, 1).to_i params.fetch(:page, 1).to_i
end end

View File

@ -44,6 +44,7 @@ module LoginHelper
set_autologin_cookie(user) set_autologin_cookie(user)
UserAction.create(action_id: user&.id, action_type: 'Login', user_id: user&.id, ip: request.remote_ip) UserAction.create(action_id: user&.id, action_type: 'Login', user_id: user&.id, ip: request.remote_ip)
# user.daily_reward
user.update_column(:last_login_on, Time.now) user.update_column(:last_login_on, Time.now)
# 注册完成后有一天的试用申请(先去掉) # 注册完成后有一天的试用申请(先去掉)
# UserDayCertification.create(user_id: user.id, status: 1) # UserDayCertification.create(user_id: user.id, status: 1)

View File

@ -3,9 +3,12 @@ class ForksController < ApplicationController
before_action :require_profile_completed, only: [:create] before_action :require_profile_completed, only: [:create]
before_action :load_project before_action :load_project
before_action :authenticate_project!, :authenticate_user! before_action :authenticate_project!, :authenticate_user!
skip_after_action :user_trace_log, only: [:create]
def create def create
@new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call @new_project = Projects::ForkService.new(current_user, @project, params[:organization]).call
user = current_user
Rails.logger.user_trace.info("{id: #{user.id}, login: #{user.login}, url: #{request.url}, method: #{request.method}, params: #{params.merge(forkee: @new_project.id)}, response_code: #{response.code}, time: #{Time.now}}")
end end
private private

View File

@ -11,6 +11,8 @@ class IssuesController < ApplicationController
before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue] before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue]
before_action :check_token_enough, :find_atme_receivers, only: [:create, :update] before_action :check_token_enough, :find_atme_receivers, only: [:create, :update]
skip_after_action :user_trace_log, only: [:update]
include ApplicationHelper include ApplicationHelper
include TagChosenHelper include TagChosenHelper
@ -218,6 +220,7 @@ class IssuesController < ApplicationController
# end # end
# end # end
# end # end
issue_hash = old_value_to_hash(@issue, params)
if @issue.issue_type.to_s == "2" && params[:status_id].to_i == 5 && @issue.author_id != current_user.try(:id) if @issue.issue_type.to_s == "2" && params[:status_id].to_i == 5 && @issue.author_id != current_user.try(:id)
normal_status(-1, "不允许修改为关闭状态") normal_status(-1, "不允许修改为关闭状态")
@ -225,6 +228,9 @@ class IssuesController < ApplicationController
issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id)
Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate! Issues::UpdateForm.new({subject: issue_params[:subject], description: issue_params[:description].blank? ? issue_params[:description] : issue_params[:description].b}).validate!
if @issue.update_attributes(issue_params) if @issue.update_attributes(issue_params)
user_trace_update_log(issue_hash)
if @issue&.pull_request.present? if @issue&.pull_request.present?
SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('PullRequestChanged', current_user.id, @issue&.pull_request&.id, @issue.previous_changes.slice(:assigned_to_id, :priority_id, :fixed_version_id, :issue_tags_value)) if Site.has_notice_menu?
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @issue&.pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu? SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @issue&.pull_request&.id ) if @issue.previous_changes[:assigned_to_id].present? && Site.has_notice_menu?

View File

@ -4,6 +4,7 @@ class JournalsController < ApplicationController
before_action :set_issue before_action :set_issue
before_action :check_issue_permission before_action :check_issue_permission
before_action :set_journal, only: [:destroy, :edit, :update] before_action :set_journal, only: [:destroy, :edit, :update]
skip_after_action :user_trace_log, only: [:update]
def index def index
@page = params[:page] || 1 @page = params[:page] || 1
@ -74,9 +75,11 @@ class JournalsController < ApplicationController
def update def update
content = params[:content] content = params[:content]
if content.present? if content.present?
old_value = old_value_to_hash(@journal, params)
Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate! Journals::UpdateForm.new({notes: notes.to_s.strip.blank? ? notes.to_s.strip : notes.to_s.strip.b}).validate!
if @journal.update_attribute(:notes, content) if @journal.update_attribute(:notes, content)
user_trace_update_log(old_value)
normal_status(0, "更新成功") normal_status(0, "更新成功")
else else
normal_status(-1, "更新失败") normal_status(-1, "更新失败")

View File

@ -0,0 +1,19 @@
class LogController < ApplicationController
def list
path = "#{Rails.root}/log"
@file_list = []
Dir.foreach(path) do |file|
@file_list << file
end
@file_list = @file_list.sort
end
def download
path = "#{Rails.root}/log/#{params[:filename]}"
if params[:filename] && File.exist?(path) && File.file?(path)
send_file(path, filename: params[:filename])
else
render json: { message: 'no such file!' }
end
end
end

View File

@ -6,6 +6,7 @@ class MembersController < ApplicationController
before_action :operate! before_action :operate!
before_action :check_member_exists!, only: %i[create] before_action :check_member_exists!, only: %i[create]
before_action :check_member_not_exists!, only: %i[remove change_role] before_action :check_member_not_exists!, only: %i[remove change_role]
skip_after_action :user_trace_log, only: [:change_role]
def create def create
interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user) interactor = Projects::AddMemberInteractor.call(@project.owner, @project, @user)
@ -42,7 +43,9 @@ class MembersController < ApplicationController
end end
def change_role def change_role
old_value = @project.members.where(user_id: params[:user_id])[0].roles.last.name
interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role]) interactor = Projects::ChangeMemberRoleInteractor.call(@project.owner, @project, @user, params[:role])
user_trace_update_log(old_value)
SendTemplateMessageJob.perform_later('ProjectRole', current_user.id, @user.id, @project.id, message_role_name) if Site.has_notice_menu? SendTemplateMessageJob.perform_later('ProjectRole', current_user.id, @user.id, @project.id, message_role_name) if Site.has_notice_menu?
render_response(interactor) render_response(interactor)
rescue Exception => e rescue Exception => e

View File

@ -6,6 +6,8 @@ class PullRequestsController < ApplicationController
before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits] before_action :find_pull_request, except: [:index, :new, :create, :check_can_merge,:get_branches,:create_merge_infos, :files, :commits]
before_action :load_pull_request, only: [:files, :commits] before_action :load_pull_request, only: [:files, :commits]
before_action :find_atme_receivers, only: [:create, :update] before_action :find_atme_receivers, only: [:create, :update]
skip_after_action :user_trace_log, only: [:update]
include TagChosenHelper include TagChosenHelper
include ApplicationHelper include ApplicationHelper
@ -103,8 +105,13 @@ class PullRequestsController < ApplicationController
reviewers = User.where(id: params[:reviewer_ids]) reviewers = User.where(id: params[:reviewer_ids])
@pull_request.reviewers = reviewers @pull_request.reviewers = reviewers
old_issue_value = old_value_to_hash(@issue, @issue_params)
old_pr_value = old_value_to_hash(@pull_request, @local_params.compact)
old_value = {issue: old_issue_value, pull_request: old_pr_value}
if @issue.update_attributes(@issue_params) if @issue.update_attributes(@issue_params)
if @pull_request.update_attributes(@local_params.compact) if @pull_request.update_attributes(@local_params.compact)
user_trace_update_log(old_value)
gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier, gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier,
@pull_request.gitea_number, @requests_params, current_user.gitea_token) @pull_request.gitea_number, @requests_params, current_user.gitea_token)
@ -119,7 +126,7 @@ class PullRequestsController < ApplicationController
end end
else else
return normal_status(-1, "请输入正确的标记。") return normal_status(-1, "请输入正确的标记。")
end end
end end
if params[:status_id].to_i == 5 if params[:status_id].to_i == 5
@issue.issue_times.update_all(end_time: Time.now) @issue.issue_times.update_all(end_time: Time.now)

View File

@ -1,6 +1,7 @@
class SettingsController < ApplicationController class SettingsController < ApplicationController
def show def show
@old_projects_url = nil @old_projects_url = nil
@old_projects_url = "https://www.trustie.net/users/#{current_user.try(:login)}/projects" if User.current.logged?
get_navbar get_navbar
get_add_menu get_add_menu
get_common_menu get_common_menu
@ -12,14 +13,14 @@ class SettingsController < ApplicationController
end end
private private
def get_navbar def get_navbar
@navbar = default_laboratory.navbar @navbar = default_laboratory.navbar
if User.current.logged? if User.current.logged?
pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false} pernal_index = {"name"=>"个人主页", "link"=>get_site_url("url", "#{Rails.application.config_for(:configuration)['platform_url']}/current_user"), "hidden"=>false}
@navbar << pernal_index @navbar << pernal_index
end end
end end
def get_add_menu def get_add_menu
@add = [] @add = []
Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site| Site.add.select(:id, :name, :url, :key).to_a.map(&:serializable_hash).each do |site|
@ -86,7 +87,7 @@ class SettingsController < ApplicationController
} }
end end
end end
def get_top_system_notification def get_top_system_notification
@top_system_notification = SystemNotification.is_top.first @top_system_notification = SystemNotification.is_top.first
end end

View File

@ -0,0 +1,90 @@
class SponsorTiersController < ApplicationController
before_action :set_sponsor_tier, only: [:show, :edit, :update, :destroy]
before_action :check_sponsor, only: [:show]
before_action :require_login, only: [:create, :update, :destroy]
# GET /sponsor_tiers
# GET /sponsor_tiers.json
def index
# @sponsor_tiers = SponsorTier.all
user = User.find_by_login(params[:login])
@sponsor_tiers = user.sponsor_tier
end
# GET /sponsor_tiers/1
# GET /sponsor_tiers/1.json
def show
end
# POST /sponsor_tiers
# POST /sponsor_tiers.json
def create
# print("------------\n", sponsor_tier_params, "\n------------\n")
@check_sponsorship = nil
@sponsor_tier = SponsorTier.new(sponsor_tier_params)
respond_to do |format|
if @sponsor_tier.user_id == User.current.id && @sponsor_tier.save
format.html { redirect_to @sponsor_tier, notice: 'Sponsor tier was successfully created.' }
format.json { render :show, status: :created, location: @sponsor_tier }
# render json: {status: 1, message: '创建成功' }
else
format.html { render :new }
format.json { render json: @sponsor_tier.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sponsor_tiers/1
# PATCH/PUT /sponsor_tiers/1.json
def update
@check_sponsorship = nil
old_value = old_value_to_hash(@sponsor_tier, params)
respond_to do |format|
if User.current.id == @sponsor_tier.user_id && @sponsor_tier.update(sponsor_tier_update_params)
user_trace_update_log(old_value)
format.html { redirect_to @sponsor_tier, notice: 'Sponsor tier was successfully updated.' }
format.json { render :show, status: :ok, location: @sponsor_tier }
# render json: {status: 1, message: '修改成功' }
else
format.html { render :edit }
format.json { render json: @sponsor_tier.errors, status: :unprocessable_entity }
# format.json { render status: :unprocessable_entity }
# render json: {status: -1, message: '修改失败' }
end
end
end
# DELETE /sponsor_tiers/1
# DELETE /sponsor_tiers/1.json
def destroy
if User.current.id == @sponsor_tier.user_id
@sponsor_tier.destroy
respond_to do |format|
format.html { redirect_to sponsor_tiers_url, notice: 'Sponsor tier was successfully destroyed.' }
format.json { head :no_content }
end
else
format.json { render json: @sponsor_tier.errors, status: :unprocessable_entity }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def check_sponsor
@check_sponsorship = Sponsorship.where("sponsor_id=? AND developer_id=?", current_user.id, @sponsor_tier.user.id)
end
def set_sponsor_tier
@sponsor_tier = SponsorTier.find(params[:id])
end
def sponsor_tier_update_params
params.require(:sponsor_tier).permit(:tier, :description)
end
# Only allow a list of trusted parameters through.
def sponsor_tier_params
params.require(:sponsor_tier).permit(:tier, :user_id, :description)
end
end

View File

@ -0,0 +1,212 @@
class SponsorshipsController < ApplicationController
before_action :set_sponsorship, only: [:show, :edit, :update, :destroy]
# before_action :require_login, except: [:index, :stopped, :sponsored, :sponsoring, :stopped_sponsored, :stopped_sponsoring]
before_action :require_login, only: [:create, :edit, :update, :destroy]
skip_after_action :user_trace_log, only: [:update]
# GET /sponsorships
# GET /sponsorships.json
def index
@sponsorships = Sponsorship.all
end
def stopped
@stopped_sponsorships = StoppedSponsorship.all
end
def sponsored
if User.current.id == Integer(params[:id])
@sponsorships = Sponsorship.where('developer_id=?', params[:id])
else
@sponsorships = Sponsorship.where('developer_id=? AND visible=1', params[:id])
end
sort = params[:sort_by] || 'created_at'
sort_direction = params[:sort_direction] || 'desc'
@sponsorships = @sponsorships.reorder("#{sort} #{sort_direction}")
@total = @sponsorships.length
@sponsorships = kaminari_paginate(@sponsorships)
end
def sponsoring
if User.current.id == Integer(params[:id])
@sponsorships = Sponsorship.where('sponsor_id=?', params[:id])
else
@sponsorships = Sponsorship.where('sponsor_id=? AND visible=1', params[:id])
end
sort = params[:sort_by] || 'created_at'
sort_direction = params[:sort_direction] || 'desc'
@sponsorships = @sponsorships.reorder("#{sort} #{sort_direction}")
@total = @sponsorships.length
@sponsorships = kaminari_paginate(@sponsorships)
end
def stopped_sponsored
if User.current.id == Integer(params[:id])
@stopped_sponsorships = StoppedSponsorship.where('developer_id=?', params[:id])
else
@stopped_sponsorships = StoppedSponsorship.where('developer_id=? AND visible=1', params[:id])
end
sort = params[:sort_by] || 'created_at'
sort_direction = params[:sort_direction] || 'desc'
@stopped_sponsorships = @stopped_sponsorships.reorder("#{sort} #{sort_direction}")
@total = @stopped_sponsorships.length
@stopped_sponsorships = kaminari_paginate(@stopped_sponsorships)
end
def stopped_sponsoring
if User.current.id == Integer(params[:id])
@stopped_sponsorships = StoppedSponsorship.where('sponsor_id=?', params[:id])
else
@stopped_sponsorships = StoppedSponsorship.where('sponsor_id=? AND visible=1', params[:id])
end
sort = params[:sort_by] || 'created_at'
sort_direction = params[:sort_direction] || 'desc'
@stopped_sponsorships = @stopped_sponsorships.reorder("#{sort} #{sort_direction}")
@total = @stopped_sponsorships.length
@stopped_sponsorships = kaminari_paginate(@stopped_sponsorships)
end
# GET /sponsorships/1
# GET /sponsorships/1.json
def show; end
# POST /sponsorships
# POST /sponsorships.json
def create
sponsor_id = User.current.id
check_sponsorship = Sponsorship.where('sponsor_id=? AND developer_id=?', sponsor_id, params[:developer_id])
@sponsorship = Sponsorship.new(sponsorship_params.merge({sponsor_id: sponsor_id}))
unless check_sponsorship.length.zero?
return render json: {status: -1, message: '您已经赞助了TA' }
end
if @sponsorship.pay && @sponsorship.save
if params[:single] && @sponsorship.stop
return render json: { status: 1, message: '赞助成功' }
elsif !params[:single]
User.current.update(sponsor_num: User.current.sponsor_num+1)
@sponsorship.developer.update(sponsored_num: @sponsorship.developer.sponsored_num + 1)
return render json: { status: 1, message: '赞助成功' }
else
return render json: { status: -1, message: '赞助失败' }
end
else
return render json: { status: -1, message: '赞助失败' }
end
# return render_result message: '赞助成功' if @sponsorship.save
# respond_to do |format|
# if check_sponsorship.length.zero? && @sponsorship.save
# format.html { redirect_to @sponsorship, notice: 'Sponsorship was successfully created.' }
# format.json { render :show, status: :created, location: @sponsorship }
# # render_result status=0, message="赞助成功"
# else
# format.html { render :new }
# format.json { render json: @sponsorship.errors, status: :unprocessable_entity }
# end
# end
end
# PATCH/PUT /sponsorships/1
# PATCH/PUT /sponsorships/1.json
def update
# respond_to do |format|
# if @sponsorship.update(sponsorship_params)
# format.html { redirect_to @sponsorship, notice: 'Sponsorship was successfully updated.' }
# format.json { render :show, status: :ok, location: @sponsorship }
# else
# format.html { render :edit }
# format.json { render json: @sponsorship.errors, status: :unprocessable_entity }
# end
# end
if @sponsorship.sponsor.id != current_user.id
return render json: {status: 401, message: '没有权限' }
end
old_value = old_value_to_hash(@sponsorship, params)
if @sponsorship.update(sponsorship_params)
user_trace_update_log(old_value)
render json: {status: 1, message: '修改成功' }
else
render json: {status: -1, message: '修改失败' }
end
end
# DELETE /sponsorships/1
# DELETE /sponsorships/1.json
def destroy
# @sponsorship.destroy
# respond_to do |format|
# format.html { redirect_to sponsorships_url, notice: 'Sponsorship was successfully destroyed.' }
# format.json { head :no_content }
# end
developer = @sponsorship.developer
sponsor = @sponsorship.sponsor
if (User.current.id == developer.id || User.current.id == sponsor.id) && developer.update(sponsored_num: developer.sponsored_num-1) && sponsor.update(sponsor_num: sponsor.sponsor_num-1) && @sponsorship.stop
render json: {status: 1, message: '终止成功'}
else
render json: {status: -1, message: '失败'}
end
end
def community_data
@sponsorships = Sponsorship.all
t1 = Time.now
t2 = Time.new(t1.year, t1.month, t1.day - 6)
@stopped_sponsorships = StoppedSponsorship.where('created_at >= ?', t2)
@community_data_array = to_array(@sponsorships, @stopped_sponsorships)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_sponsorship
@sponsorship = Sponsorship.find(params[:id])
end
# Only allow a list of trusted parameters through.
def sponsorship_params
params.require(:sponsorship).permit(:amount, :visible, :sponsor_id, :developer_id, :single, :page, :limit, :sort_by, :search)
end
def to_array(sponsorships, stopped_sponsorships)
t1 = Time.now
start_time = Time.new(t1.year, t1.month, t1.day - 6)
sponsor = Array.new(7)
sponsored = Array.new(7)
date = Array.new(7)
# date[0] = Time.new(start_time.year, start_time.month, start_time.day)
index = 0
(0..6).each do |i|
# 更新日期date[i]表示第i天0点
date[i] = Time.new(start_time.year, start_time.month, start_time.day + i)
end_time = Time.new(start_time.year, start_time.month, start_time.day + i+1)
sponsor_set = Set.new
sponsored_set = Set.new
# 所有创建时间早于今天23:59的sponsorship
today_sponsor = sponsorships.where('created_at < ?', end_time)
# 所有结束时间晚于今天0:00的stopped_sponsorship
today_stopped_sponsor = stopped_sponsorships.where('created_at <= ?', date[i])
today_sponsor.each do |s|
sponsor_set.add s.sponsor_id
sponsored_set.add s.developer_id
end
today_stopped_sponsor.each do |s|
sponsor_set.add s.sponsor_id
sponsored_set.add s.developer_id
end
sponsor[i] = sponsor_set.size
sponsored[i] = sponsored_set.size
end
Array[sponsor, sponsored, date]
end
end

View File

@ -94,11 +94,11 @@ class UsersController < ApplicationController
end end
end end
def update_image def update_image
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id]) return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id) return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
Util.write_file(@image, avatar_path(@user)) Util.write_file(@image, avatar_path(@user))
return render_ok({message: '头像修改成功'}) return render_ok({message: '头像修改成功'})
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
@ -141,6 +141,10 @@ class UsersController < ApplicationController
end end
# TODO 等消息上线再打开注释 # TODO 等消息上线再打开注释
#@tidding_count = unviewed_tiddings(current_user) if current_user.present? #@tidding_count = unviewed_tiddings(current_user) if current_user.present?
#
if(@user.logged?)
@user.daily_reward
end
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
missing_template missing_template
@ -302,6 +306,21 @@ class UsersController < ApplicationController
render_ok render_ok
end end
def update_sponsor_description
@user = User.find params[:id]
if @user.id == User.current.id
# @user.update(description: params[:description])
@user.sponsor_description = params[:sponsor_description]
if @user.save!
render_ok
else
render_error
end
else
render_error
end
end
def sync_user_info def sync_user_info
user = User.find_by_login params[:login] user = User.find_by_login params[:login]
return render_forbidden unless user === current_user return render_forbidden unless user === current_user
@ -322,7 +341,7 @@ class UsersController < ApplicationController
end end
end end
def email_search def email_search
return render_error('请输入email') if params[:email].blank? return render_error('请输入email') if params[:email].blank?
@user = User.find_by(mail: params[:email]) @user = User.find_by(mail: params[:email])
end end
@ -339,7 +358,7 @@ class UsersController < ApplicationController
:occupation, :technical_title, :occupation, :technical_title,
:school_id, :department_id, :province, :city, :school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description, :custom_department, :identity, :student_id, :description,
:show_super_description, :super_description, :show_super_description, :super_description,:sponsor_description,
:show_email, :show_location, :show_department] :show_email, :show_location, :show_department]
) )
end end

View File

@ -4,6 +4,7 @@ class VersionReleasesController < ApplicationController
before_action :require_login, except: [:index, :show] before_action :require_login, except: [:index, :show]
before_action :check_release_authorize, except: [:index, :show] before_action :check_release_authorize, except: [:index, :show]
before_action :find_version , only: [:show, :edit, :update, :destroy] before_action :find_version , only: [:show, :edit, :update, :destroy]
skip_after_action :user_trace_log, only: [:update]
def index def index
@version_releases = kaminari_paginate(@repository.version_releases.order(created_at: :desc)) @version_releases = kaminari_paginate(@repository.version_releases.order(created_at: :desc))
@ -22,7 +23,7 @@ class VersionReleasesController < ApplicationController
end end
end end
def show def show
# @release = Gitea::Versions::GetService.call(current_user.gitea_token, @user&.login, @repository&.identifier, @version&.version_gid) # @release = Gitea::Versions::GetService.call(current_user.gitea_token, @user&.login, @repository&.identifier, @version&.version_gid)
end end
@ -83,14 +84,14 @@ class VersionReleasesController < ApplicationController
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
begin begin
version_params = releases_params version_params = releases_params
old_value = old_value_to_hash(@version, version_params)
if @version.update_attributes!(version_params) if @version.update_attributes!(version_params)
create_attachments(params[:attachment_ids], @version) if params[:attachment_ids].present? create_attachments(params[:attachment_ids], @version) if params[:attachment_ids].present?
git_version_release = Gitea::Versions::UpdateService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params, @version.try(:version_gid)).call git_version_release = Gitea::Versions::UpdateService.new(current_user.gitea_token, @user.try(:login), @repository.try(:identifier), version_params, @version.try(:version_gid)).call
unless git_version_release unless git_version_release
raise Error, "更新失败" raise Error, "更新失败"
end end
user_trace_update_log(old_value)
normal_status(0, "更新成功") normal_status(0, "更新成功")
else else
normal_status(-1, "更新失败") normal_status(-1, "更新失败")

View File

@ -0,0 +1,113 @@
class WalletsController < ApplicationController
before_action :require_login, except: :community_data
def balance
user = User.find_by_id(params[:id])
@wallet = user.get_wallet
end
def coin_changes
user = User.find_by_id(params[:id])
@wallet = user.get_wallet
if params[:category] == 'all'
scope = CoinChange.where('to_wallet_id = ? OR from_wallet_id = ?', @wallet.id, @wallet.id)
elsif params[:category] == 'income'
# @coin_changes = CoinChange.where('to_wallet_id = ?', @wallet.id).limit(100)
scope = @wallet.income
elsif params[:category] == 'outcome'
scope = @wallet.outcome
end
sort = params[:sort_by] || "created_at"
sort_direction = params[:sort_direction] || "desc"
scope = scope.reorder("#{sort} #{sort_direction}") unless scope.nil?
@total = 0
@total = scope.length unless scope.nil?
@coin_changes = kaminari_paginate(scope) unless scope.nil?
end
def balance_chart
user = User.find_by_id(params[:id])
@wallet = user.get_wallet
scope = CoinChange.where('to_wallet_id = ? OR from_wallet_id = ?', @wallet.id, @wallet.id)
t1 = Time.now
t2 = Time.new(t1.year, t1.month, t1.day - 6)
@balance_chart_data = scope.where('created_at > ? AND created_at < ?', t2, t1)
@balance_chart_array = to_array(@balance_chart_data, @wallet.id)
end
def community_data
t1 = Time.now
t2 = Time.new(t1.year, t1.month, t1.day - 6)
coin_changes = CoinChange.where('created_at >= ?', t2)
@community_data_array = community_data_to_array(coin_changes)
end
private
def to_array(data, id)
t1 = Time.now
start_time = Time.new(t1.year, t1.month, t1.day - 6)
end_time = Time.new(start_time.year, start_time.month, start_time.day + 1)
income = Array.new(7, 0) # 收入、支出
outcome = Array.new(7, 0)
date = Array.new(7)
date[0] = Time.new(start_time.year, start_time.month, start_time.day)
index = 0
data.each do |i|
# 更新日期
until (i.created_at >= start_time) && (i.created_at < end_time)
index += 1
start_time = end_time
end_time = Time.new(start_time.year, start_time.month, start_time.day + 1)
date[index] = Time.new(start_time.year, start_time.month, start_time.day)
end
if i.from_wallet_id == id
outcome[index] += i.amount
else
next if params[:sponsor] == true && i.from_wallet_id.nil?
income[index] += i.amount
end
end
until end_time >= Time.now
index += 1
start_time = end_time
end_time = Time.new(start_time.year, start_time.month, start_time.day + 1)
date[index] = Time.new(start_time.year, start_time.month, start_time.day)
end
Array[income, outcome, date]
end
def community_data_to_array(coin_changes)
t1 = Time.now
start_time = Time.new(t1.year, t1.month, t1.day - 6)
nums = Array.new(7, 0)
date = Array.new(7)
end_time = Array.new(7)
# date[0] = Time.new(start_time.year, start_time.month, start_time.day)
index = 0
(0..6).each do |i|
# 更新日期date[i]表示第i天0点
date[i] = Time.new(start_time.year, start_time.month, start_time.day + i)
end_time[i] = Time.new(start_time.year, start_time.month, start_time.day + i+1)
end
coin_changes.each do |cc|
(0..6).each do |i|
if !cc.from_wallet_id.nil? && cc.created_at>=date[i] && cc.created_at<end_time[i]
nums[i] += 1
end
end
end
Array[nums, date]
end
end

View File

@ -0,0 +1,2 @@
module LogHelper
end

View File

@ -0,0 +1,2 @@
module SponsorTiersHelper
end

View File

@ -0,0 +1,2 @@
module SponsorshipsHelper
end

View File

@ -0,0 +1,6 @@
module UpdateHelper
def old_value_to_hash(old_value, params)
params = params.dup.stringify_keys
old_value.attributes.select { |key, value| params.key?(key) }
end
end

View File

@ -0,0 +1,2 @@
module WalletsHelper
end

View File

@ -0,0 +1,15 @@
class MonthlyPaymentWorker
include Sidekiq::Worker
include Sidetiq::Schedulable
recurrence do
minutely(2)
# monthly.day_of_month(12) #每月的12号0点执行
# monthly.day_of_month(23).hour_of_day(20) #每月的12号1点执行
end
def perform(*args)
Sponsorship.monthly_payment
puts Time.now, 'sponsor payment done'
end
end

View File

@ -17,7 +17,7 @@
# disk_directory :string(255) # disk_directory :string(255)
# attachtype :integer default("1") # attachtype :integer default("1")
# is_public :integer default("1") # is_public :integer default("1")
# copy_from :string(255) # copy_from :integer
# quotes :integer default("0") # quotes :integer default("0")
# is_publish :integer default("1") # is_publish :integer default("1")
# publish_time :datetime # publish_time :datetime
@ -26,15 +26,15 @@
# cloud_url :string(255) default("") # cloud_url :string(255) default("")
# course_second_category_id :integer default("0") # course_second_category_id :integer default("0")
# delay_publish :boolean default("0") # delay_publish :boolean default("0")
# link :string(255)
# clone_id :integer
# #
# Indexes # Indexes
# #
# index_attachments_on_author_id (author_id) # index_attachments_on_author_id (author_id)
# index_attachments_on_clone_id (clone_id)
# index_attachments_on_container_id_and_container_type (container_id,container_type) # index_attachments_on_container_id_and_container_type (container_id,container_type)
# index_attachments_on_course_second_category_id (course_second_category_id)
# index_attachments_on_created_on (created_on) # index_attachments_on_created_on (created_on)
# index_attachments_on_is_public (is_public)
# index_attachments_on_quotes (quotes)
# #

View File

@ -39,15 +39,18 @@
# business :boolean default("0") # business :boolean default("0")
# profile_completed :boolean default("0") # profile_completed :boolean default("0")
# laboratory_id :integer # laboratory_id :integer
# is_shixun_marker :boolean default("0") # platform :string(255) default("0")
# admin_visitable :boolean default("0") # gitea_token :string(255)
# collaborator :boolean default("0")
# gitea_uid :integer # gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1") # is_sync_pwd :boolean default("1")
# watchers_count :integer default("0") # watchers_count :integer default("0")
# sponsor_certification :integer default("0")
# sponsor_num :integer default("0")
# sponsored_num :integer default("0")
# sponsor_description :text(65535)
# devops_step :integer default("0") # devops_step :integer default("0")
# gitea_token :string(255) # award_time :datetime
# platform :string(255)
# #
# Indexes # Indexes
# #
@ -55,9 +58,8 @@
# index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher) # index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id) # index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE # index_users_on_login (login)
# index_users_on_mail (mail) UNIQUE # index_users_on_mail (mail)
# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type) # index_users_on_type (type)
# #

19
app/models/coin_change.rb Normal file
View File

@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: coin_changes
#
# id :integer not null, primary key
# amount :integer
# description :string(255)
# reason :string(255)
# to_wallet_id :integer
# from_wallet_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class CoinChange < ApplicationRecord
belongs_to :to_wallet, class_name: 'Wallet'
belongs_to :from_wallet, class_name: 'Wallet', optional: true
validates :amount, presence: true
end

View File

@ -1,18 +1,19 @@
# == Schema Information # == Schema Information
# #
# Table name: edu_settings # Table name: edu_settings
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) # name :string(255)
# value :string(255) # value :string(255)
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# description :string(255) # description :string(255)
# #
# Indexes # Indexes
# #
# index_edu_settings_on_name (name) UNIQUE # index_edu_settings_on_name (name) UNIQUE
# #
class EduSetting < ApplicationRecord class EduSetting < ApplicationRecord
after_commit :expire_value_cache after_commit :expire_value_cache

View File

@ -1,3 +1,24 @@
# == Schema Information
#
# Table name: public_key
#
# id :integer not null, primary key
# owner_id :integer not null
# name :string(255) not null
# fingerprint :string(255) not null
# content :text(65535) not null
# mode :integer default("2"), not null
# type :integer default("1"), not null
# login_source_id :integer default("0"), not null
# created_unix :integer
# updated_unix :integer
#
# Indexes
#
# IDX_public_key_fingerprint (fingerprint)
# IDX_public_key_owner_id (owner_id)
#
class Gitea::PublicKey < Gitea::Base class Gitea::PublicKey < Gitea::Base
self.inheritance_column = nil # FIX The single-table inheritance mechanism failed self.inheritance_column = nil # FIX The single-table inheritance mechanism failed
# establish_connection :gitea_db # establish_connection :gitea_db

View File

@ -6,9 +6,6 @@
# type :integer # type :integer
# status :integer # status :integer
# conflicted_files :text(65535) # conflicted_files :text(65535)
# commits_ahead :integer
# commits_behind :integer
# changed_protected_files :text(65535)
# issue_id :integer # issue_id :integer
# index :integer # index :integer
# head_repo_id :integer # head_repo_id :integer
@ -20,6 +17,11 @@
# merged_commit_id :string(40) # merged_commit_id :string(40)
# merger_id :integer # merger_id :integer
# merged_unix :integer # merged_unix :integer
# commits_ahead :integer
# commits_behind :integer
# changed_protected_files :text(65535)
# commit_num :integer
# changed_files :integer
# #
# Indexes # Indexes
# #

View File

@ -1,3 +1,36 @@
# == Schema Information
#
# Table name: webhook
#
# id :integer not null, primary key
# repo_id :integer
# org_id :integer
# url :text(65535)
# http_method :string(255)
# content_type :integer
# secret :text(65535)
# events :text(65535)
# is_active :boolean
# meta :text(65535)
# last_status :integer
# created_unix :integer
# updated_unix :integer
# is_system_webhook :boolean default("0"), not null
# type :string(16)
# branch_filter :text(65535)
# signature :text(65535)
# is_ssl :boolean
# hook_task_type :integer
#
# Indexes
#
# IDX_webhook_created_unix (created_unix)
# IDX_webhook_is_active (is_active)
# IDX_webhook_org_id (org_id)
# IDX_webhook_repo_id (repo_id)
# IDX_webhook_updated_unix (updated_unix)
#
class Gitea::Webhook < Gitea::Base class Gitea::Webhook < Gitea::Base
serialize :events, JSON serialize :events, JSON
self.inheritance_column = nil self.inheritance_column = nil
@ -10,4 +43,4 @@ class Gitea::Webhook < Gitea::Base
enum hook_task_type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9} enum hook_task_type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9}
enum last_status: {waiting: 0, succeed: 1, fail: 2} enum last_status: {waiting: 0, succeed: 1, fail: 2}
enum content_type: {json: 1, form: 2} enum content_type: {json: 1, form: 2}
end end

View File

@ -1,6 +1,34 @@
class Gitea::WebhookTask < Gitea::Base # == Schema Information
#
# Table name: hook_task
#
# id :integer not null, primary key
# repo_id :integer
# hook_id :integer
# uuid :string(255)
# payload_content :text(65535)
# event_type :string(255)
# is_delivered :boolean
# delivered :integer
# is_succeed :boolean
# request_content :text(65535)
# response_content :text(65535)
# type :string(255)
# url :text(65535)
# signature :text(65535)
# http_method :string(255)
# content_type :integer
# is_ssl :boolean
#
# Indexes
#
# IDX_hook_task_repo_id (repo_id)
#
class Gitea::WebhookTask < Gitea::Base
serialize :payload_content, JSON serialize :payload_content, JSON
serialize :request_content, JSON serialize :request_content, JSON
serialize :response_content, JSON
self.inheritance_column = nil self.inheritance_column = nil
@ -12,7 +40,7 @@ class Gitea::WebhookTask < Gitea::Base
def response_content_json def response_content_json
JSON.parse(response_content) JSON.parse(response_content)
rescue rescue
{} {}
end end
end end

View File

@ -10,7 +10,6 @@
# sync_course :boolean default("0") # sync_course :boolean default("0")
# sync_subject :boolean default("0") # sync_subject :boolean default("0")
# sync_shixun :boolean default("0") # sync_shixun :boolean default("0")
# is_local :boolean default("0")
# #
# Indexes # Indexes
# #

View File

@ -39,15 +39,18 @@
# business :boolean default("0") # business :boolean default("0")
# profile_completed :boolean default("0") # profile_completed :boolean default("0")
# laboratory_id :integer # laboratory_id :integer
# is_shixun_marker :boolean default("0") # platform :string(255) default("0")
# admin_visitable :boolean default("0") # gitea_token :string(255)
# collaborator :boolean default("0")
# gitea_uid :integer # gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1") # is_sync_pwd :boolean default("1")
# watchers_count :integer default("0") # watchers_count :integer default("0")
# sponsor_certification :integer default("0")
# sponsor_num :integer default("0")
# sponsored_num :integer default("0")
# sponsor_description :text(65535)
# devops_step :integer default("0") # devops_step :integer default("0")
# gitea_token :string(255) # award_time :datetime
# platform :string(255)
# #
# Indexes # Indexes
# #
@ -55,9 +58,8 @@
# index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher) # index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id) # index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE # index_users_on_login (login)
# index_users_on_mail (mail) UNIQUE # index_users_on_mail (mail)
# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type) # index_users_on_type (type)
# #

View File

@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: passed_waitlists
#
# id :integer not null, primary key
# applicant_id :string(255)
# integer :string(255)
# reviewer_id :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class PassedWaitlist < ApplicationRecord
belongs_to :applicant, class_name: 'User'
belongs_to :reviewer, class_name: 'User'
end

View File

@ -124,7 +124,7 @@ class Project < ApplicationRecord
has_many :pinned_projects, dependent: :destroy has_many :pinned_projects, dependent: :destroy
has_many :has_pinned_users, through: :pinned_projects, source: :user has_many :has_pinned_users, through: :pinned_projects, source: :user
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
has_many :user_trace_tasks, dependent: :destroy has_many :user_trace_tasks, dependent: :destroy
has_many :project_invite_links, dependent: :destroy has_many :project_invite_links, dependent: :destroy
after_create :incre_user_statistic, :incre_platform_statistic after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members after_save :check_project_members
@ -192,7 +192,7 @@ class Project < ApplicationRecord
end end
end end
def incre_user_statistic 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) 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 end
@ -235,7 +235,7 @@ class Project < ApplicationRecord
unless self.is_public unless self.is_public
self.recommend = false self.recommend = false
self.recommend_index = 0 self.recommend_index = 0
self.is_pinned = false self.is_pinned = false
end end
end end

View File

@ -27,6 +27,7 @@
# #
# Indexes # Indexes
# #
# index_repositories_on_identifier (identifier)
# index_repositories_on_project_id (project_id) # index_repositories_on_project_id (project_id)
# index_repositories_on_user_id (user_id) # index_repositories_on_user_id (user_id)
# #

View File

@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: sponsor_tiers
#
# id :integer not null, primary key
# tier :integer
# created_at :datetime not null
# updated_at :datetime not null
# description :string(255) default("")
# user_id :integer
#
class SponsorTier < ApplicationRecord
belongs_to :user
end

49
app/models/sponsorship.rb Normal file
View File

@ -0,0 +1,49 @@
# == Schema Information
#
# Table name: sponsorships
#
# id :integer not null, primary key
# amount :integer
# visible :integer
# sponsor_id :integer
# developer_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# accumulate :integer default("0")
#
class Sponsorship < ApplicationRecord
belongs_to :sponsor, class_name: 'User'
belongs_to :developer, class_name: 'User'
validates :amount, presence: true
def stop
stopped_sponsorship = StoppedSponsorship.new(developer_id: developer_id, sponsor_id: sponsor_id, start_time: created_at, amount: amount, visible: visible, accumulate: accumulate)
stopped_sponsorship.save && destroy
end
def pay
sponsor_wallet = sponsor.get_wallet
developer_wallet = developer.get_wallet
success = false
Wallet.transaction do
success = sponsor_wallet.pay(amount)
if success
developer_wallet.receive(amount)
update(accumulate: self.accumulate += amount)
reason = "#{sponsor.full_name}#{developer.full_name}的赞助支付。"
coinchange = CoinChange.new(amount: amount, reason: reason, to_wallet_id: developer_wallet.id, from_wallet_id: sponsor_wallet.id)
return true if coinchange.save
end
end
success
end
def self.monthly_payment
sponsorships = Sponsorship.all
sponsorships.each do |s|
s.stop unless s.pay
end
end
end

26
app/models/statistic.rb Normal file
View File

@ -0,0 +1,26 @@
# == Schema Information
#
# Table name: statistics
#
# id :integer not null, primary key
# dau :integer
# created_at :datetime not null
# updated_at :datetime not null
# wau :integer
# mau :integer
#
class Statistic < ApplicationRecord
def self.record
users = User.all
count = 0
t = Time.now - 1.day
# t = Time.now.at_beginning_of_day
users.each do |u|
if !u.last_login_on.nil? && u.last_login_on >= t
count += 1
end
end
Statistic.create(dau: count)
end
end

View File

@ -0,0 +1,20 @@
# == Schema Information
#
# Table name: stopped_sponsorships
#
# id :integer not null, primary key
# amount :integer
# sponsor_id :integer
# developer_id :integer
# created_at :datetime not null
# updated_at :datetime not null
# start_time :datetime
# visible :integer
# accumulate :integer default("0")
#
class StoppedSponsorship < ApplicationRecord
belongs_to :sponsor, class_name: 'User'
belongs_to :developer, class_name: 'User'
validates :amount, presence: true
end

View File

@ -1,18 +1,19 @@
# == Schema Information # == Schema Information
# #
# Table name: tokens # Table name: tokens
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer default("0"), not null # user_id :integer default("0"), not null
# action :string(30) default(""), not null # action :string(30) default(""), not null
# value :string(40) default(""), not null # value :string(40) default(""), not null
# created_on :datetime not null # created_on :datetime not null
# #
# Indexes # Indexes
# #
# index_tokens_on_user_id (user_id) # index_tokens_on_user_id (user_id)
# tokens_value (value) UNIQUE # tokens_value (value) UNIQUE
# #
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or

View File

@ -39,15 +39,18 @@
# business :boolean default("0") # business :boolean default("0")
# profile_completed :boolean default("0") # profile_completed :boolean default("0")
# laboratory_id :integer # laboratory_id :integer
# is_shixun_marker :boolean default("0") # platform :string(255) default("0")
# admin_visitable :boolean default("0") # gitea_token :string(255)
# collaborator :boolean default("0")
# gitea_uid :integer # gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1") # is_sync_pwd :boolean default("1")
# watchers_count :integer default("0") # watchers_count :integer default("0")
# sponsor_certification :integer default("0")
# sponsor_num :integer default("0")
# sponsored_num :integer default("0")
# sponsor_description :text(65535)
# devops_step :integer default("0") # devops_step :integer default("0")
# gitea_token :string(255) # award_time :datetime
# platform :string(255)
# #
# Indexes # Indexes
# #
@ -55,9 +58,8 @@
# index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher) # index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id) # index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE # index_users_on_login (login)
# index_users_on_mail (mail) UNIQUE # index_users_on_mail (mail)
# index_users_on_phone (phone) UNIQUE
# index_users_on_type (type) # index_users_on_type (type)
# #
@ -161,6 +163,18 @@ class User < Owner
has_many :project_trends, dependent: :destroy has_many :project_trends, dependent: :destroy
has_many :oauths , dependent: :destroy has_many :oauths , dependent: :destroy
# sponsor
has_many :as_sponsors, class_name: 'Sponsorship', foreign_key: 'sponsor_id', dependent: :destroy
has_many :as_sponsored, class_name: 'Sponsorship', foreign_key: 'developer_id', dependent: :destroy
has_many :stopped_sponsors, class_name: 'StoppedSponsorship', foreign_key: 'sponsor_id', dependent: :destroy
has_many :stopped_sponsored, class_name: 'StoppedSponsorship', foreign_key: 'developer_id', dependent: :destroy
has_many :sponsor_tier, dependent: :destroy
has_one :wallet, dependent: :destroy
has_many :waitlist, class_name: 'Waitlist', foreign_key: 'reviewer_id'
has_many :passed_waitlist, class_name: 'PassedWaitlist', foreign_key: 'reviewer_id' #as reviewer
has_one :application, class_name: 'Waitlist', foreign_key: 'applicant_id'
has_one :passed_application, class_name: 'PassedWaitlist', foreign_key: 'applicant_id'
has_many :organization_users, dependent: :destroy has_many :organization_users, dependent: :destroy
has_many :organizations, through: :organization_users has_many :organizations, through: :organization_users
has_many :pinned_projects, dependent: :destroy has_many :pinned_projects, dependent: :destroy
@ -646,6 +660,7 @@ class User < Owner
# Returns the user who matches the given autologin +key+ or nil # Returns the user who matches the given autologin +key+ or nil
def self.try_to_autologin(key) def self.try_to_autologin(key)
user = Token.find_active_user('autologin', key) user = Token.find_active_user('autologin', key)
# user.daily_reward if user
user.update(last_login_on: Time.now) if user user.update(last_login_on: Time.now) if user
user user
end end
@ -817,6 +832,36 @@ class User < Owner
laboratory_id.present? && laboratory_id != 1 laboratory_id.present? && laboratory_id != 1
end end
def get_wallet
if wallet.nil?
Wallet.transaction(isolation: :serializable) do
if wallet.nil?
create_wallet(balance: 100)
reason = "系统初始赠送"
CoinChange.create(amount: 100, reason: reason, to_wallet_id: wallet.id)
end
end
end
wallet
end
def daily_reward
if !Rails.application.config_for(:configuration)["sponsor"]
return
end
t1 = Time.now
t2 = Time.new(t1.year, t1.month, t1.day)
if(award_time.nil? or t2 > award_time)
self.update_column(:award_time, Time.now)
amount = 2
user_wallet = get_wallet
user_wallet.receive(amount)
reason = "每日登录奖励"
CoinChange.create(amount: amount, reason: reason, to_wallet_id: user_wallet.id)
end
end
def profile_is_completed? def profile_is_completed?
self.nickname.present? && self.mail.present? self.nickname.present? && self.mail.present?
end end

View File

@ -12,9 +12,7 @@
# #
# Indexes # Indexes
# #
# index_user_actions_on_ip (ip) # index_user_actions_on_ip (ip)
# index_user_actions_on_user_id (user_id)
# index_user_actions_on_user_id_and_action_type (user_id,action_type)
# #
class UserAction < ApplicationRecord class UserAction < ApplicationRecord

View File

@ -10,13 +10,10 @@
# updated_at :datetime not null # updated_at :datetime not null
# register_status :integer default("0") # register_status :integer default("0")
# action_status :integer default("0") # action_status :integer default("0")
# is_delete :boolean default("0")
# user_id :integer
# #
# Indexes # Indexes
# #
# index_user_agents_on_ip (ip) # index_user_agents_on_ip (ip) UNIQUE
# index_user_agents_on_user_id (user_id)
# #
class UserAgent < ApplicationRecord class UserAgent < ApplicationRecord

16
app/models/waitlist.rb Normal file
View File

@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: waitlists
#
# id :integer not null, primary key
# applicant_id :string(255)
# integer :string(255)
# reviewer_id :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class Waitlist < ApplicationRecord
belongs_to :applicant, class_name: 'User'
belongs_to :reviewer, class_name: 'User', optional: true
end

42
app/models/wallet.rb Normal file
View File

@ -0,0 +1,42 @@
# == Schema Information
#
# Table name: wallets
#
# id :integer not null, primary key
# balance :integer
# user_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Wallet < ApplicationRecord
belongs_to :user
has_many :outcome, class_name: 'CoinChange', foreign_key: 'from_wallet_id', dependent: :destroy
has_many :income, class_name: 'CoinChange', foreign_key: 'to_wallet_id', dependent: :destroy
validates :balance, presence: true
@@wallet_lock = Mutex.new
def receive(amount)
with_lock do
self.balance += amount
save!
end
end
def pay(amount)
with_lock do
if self.balance < amount
reload
return false
else
self.balance -= amount
save!
end
end
true
end
def self.wallet_lock
@@wallet_lock
end
end

View File

@ -0,0 +1 @@
json.array! @file_list

View File

@ -0,0 +1,13 @@
<%= simple_form_for(@sponsor_tier) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :tier %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>

View File

@ -0,0 +1,2 @@
json.extract! sponsor_tier, :id, :tier, :description, :created_at, :updated_at
json.url sponsor_tier_url(sponsor_tier, format: :json)

View File

@ -0,0 +1,6 @@
<h1>Editing Sponsor Tier</h1>
<%= render 'form', sponsor_tier: @sponsor_tier %>
<%= link_to 'Show', @sponsor_tier %> |
<%= link_to 'Back', sponsor_tiers_path %>

View File

@ -0,0 +1 @@
json.array! @sponsor_tiers, partial: "sponsor_tiers/sponsor_tier", as: :sponsor_tier

View File

@ -0,0 +1,5 @@
<h1>New Sponsor Tier</h1>
<%= render 'form', sponsor_tier: @sponsor_tier %>
<%= link_to 'Back', sponsor_tiers_path %>

View File

@ -0,0 +1,9 @@
<p id="notice"><%= notice %></p>
<p>
<strong>Tier:</strong>
<%= @sponsor_tier.tier %>
</p>
<%= link_to 'Edit', edit_sponsor_tier_path(@sponsor_tier) %> |
<%= link_to 'Back', sponsor_tiers_path %>

View File

@ -0,0 +1,9 @@
json.tier do
json.partial! "sponsor_tiers/sponsor_tier", sponsor_tier: @sponsor_tier
end
if @check_sponsorship.nil? || @check_sponsorship.length.zero?
json.is_sponsoring false
else
json.is_sponsoring true
json.sponsorship_id @check_sponsorship[0].id
end

View File

@ -0,0 +1,16 @@
<%= simple_form_for(@sponsorship) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.input :amount %>
<%= f.input :visible %>
<%= f.input :sponsor_id %>
<%= f.input :developer_id %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>

View File

@ -0,0 +1,2 @@
json.extract! sponsorship, :id, :amount, :visible, :sponsor_id, :developer_id, :created_at, :updated_at, :accumulate
json.url sponsorship_url(sponsorship, format: :json)

View File

@ -0,0 +1,12 @@
json.sponsor do
json.array! (0..6).each do |i|
json.y @community_data_array[0][i]
json.x @community_data_array[2][i].to_date
end
end
json.sponsored do
json.array! (0..6).each do |i|
json.y @community_data_array[1][i]
json.x @community_data_array[2][i].to_date
end
end

View File

@ -0,0 +1,6 @@
<h1>Editing Sponsorship</h1>
<%= render 'form', sponsorship: @sponsorship %>
<%= link_to 'Show', @sponsorship %> |
<%= link_to 'Back', sponsorships_path %>

View File

@ -0,0 +1,33 @@
<p id="notice"><%= notice %></p>
<h1>Sponsorships</h1>
<table>
<thead>
<tr>
<th>Amount</th>
<th>Visible</th>
<th>Sponsor</th>
<th>Developer</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @sponsorships.each do |sponsorship| %>
<tr>
<td><%= sponsorship.amount %></td>
<td><%= sponsorship.visible %></td>
<td><%= sponsorship.sponsor_id %></td>
<td><%= sponsorship.developer_id %></td>
<td><%= link_to 'Show', sponsorship %></td>
<td><%= link_to 'Edit', edit_sponsorship_path(sponsorship) %></td>
<td><%= link_to 'Destroy', sponsorship, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Sponsorship', new_sponsorship_path %>

View File

@ -0,0 +1 @@
json.array! @sponsorships, partial: "sponsorships/sponsorship", as: :sponsorship

View File

@ -0,0 +1,5 @@
<h1>New Sponsorship</h1>
<%= render 'form', sponsorship: @sponsorship %>
<%= link_to 'Back', sponsorships_path %>

View File

@ -0,0 +1,24 @@
<p id="notice"><%= notice %></p>
<p>
<strong>Amount:</strong>
<%= @sponsorship.amount %>
</p>
<p>
<strong>Visible:</strong>
<%= @sponsorship.visible %>
</p>
<p>
<strong>Sponsor:</strong>
<%= @sponsorship.sponsor_id %>
</p>
<p>
<strong>Developer:</strong>
<%= @sponsorship.developer_id %>
</p>
<%= link_to 'Edit', edit_sponsorship_path(@sponsorship) %> |
<%= link_to 'Back', sponsorships_path %>

View File

@ -0,0 +1 @@
json.partial! "sponsorships/sponsorship", sponsorship: @sponsorship

View File

@ -0,0 +1,21 @@
json.count @total
json.sponsorships do
json.array! @sponsorships do |sponsorship|
json.id sponsorship.id
json.start_time sponsorship.created_at.to_date
# json.stop_time '-'
if sponsorship.visible.zero?
json.visible false
else
json.visible true
end
json.amount sponsorship.amount
sponsor = sponsorship.sponsor
json.image_url url_to_avatar(sponsor)
json.username sponsor.full_name
json.user_id sponsor.id
json.login sponsor.login
json.accumulate sponsorship.accumulate
json.sponsor_id sponsorship.sponsor.id
end
end

View File

@ -0,0 +1,21 @@
json.count @total
json.sponsorships do
json.array! @sponsorships do |sponsorship|
json.id sponsorship.id
json.start_time sponsorship.created_at.to_date
# json.stop_time '-'
if sponsorship.visible.zero?
json.visible false
else
json.visible true
end
json.amount sponsorship.amount
sponsor = sponsorship.developer
json.image_url url_to_avatar(sponsor)
json.username sponsor.full_name
json.user_id sponsor.id
json.login sponsor.login
json.accumulate sponsorship.accumulate
json.sponsor_id sponsorship.sponsor.id
end
end

View File

@ -0,0 +1,11 @@
json.array! @stopped_sponsorships do |sponsorship|
json.id sponsorship.id
json.amount sponsorship.amount
json.visible sponsorship.visible
json.sponsor_id sponsorship.sponsor_id
json.developer_id sponsorship.developer_id
json.start_time sponsorship.start_time
json.created_at sponsorship.created_at
json.updated_at sponsorship.updated_at
json.accumulate sponsorship.accumulate
end

View File

@ -0,0 +1,21 @@
json.count @total
json.sponsorships do
json.array! @stopped_sponsorships do |sponsorship|
json.id sponsorship.id
json.start_time sponsorship.start_time.to_date
json.stop_time sponsorship.created_at.to_date
if sponsorship.visible.zero?
json.visible false
else
json.visible true
end
json.amount sponsorship.amount
sponsor = sponsorship.sponsor
json.image_url url_to_avatar(sponsor)
json.username sponsor.full_name
json.user_id sponsor.id
json.login sponsor.login
json.accumulate sponsorship.accumulate
json.sponsor_id sponsorship.sponsor.id
end
end

View File

@ -0,0 +1,21 @@
json.count @total
json.sponsorships do
json.array! @stopped_sponsorships do |sponsorship|
json.id sponsorship.id
json.start_time sponsorship.start_time.to_date
json.stop_time sponsorship.created_at.to_date
if sponsorship.visible.zero?
json.visible false
else
json.visible true
end
json.amount sponsorship.amount
sponsor = sponsorship.developer
json.image_url url_to_avatar(sponsor)
json.username sponsor.full_name
json.user_id sponsor.id
json.login sponsor.login
json.accumulate sponsorship.accumulate
json.sponsor_id sponsorship.sponsor.id
end
end

View File

@ -15,6 +15,7 @@ json.phone @user.phone
# json.email @user.mail # json.email @user.mail
json.profile_completed @user.profile_is_completed? json.profile_completed @user.profile_is_completed?
json.professional_certification @user.professional_certification json.professional_certification @user.professional_certification
json.sponsor_description @user.sponsor_description
json.devops_step @user.devops_step json.devops_step @user.devops_step
json.ci_certification @user.ci_certification? json.ci_certification @user.ci_certification?
json.email @user.mail json.email @user.mail

View File

@ -15,4 +15,5 @@ json.city @user.show_location ? @user.city : nil
json.custom_department @user.show_department ? @user.custom_department : nil json.custom_department @user.show_department ? @user.custom_department : nil
json.super_description @user.show_super_description ? @user.super_description : nil json.super_description @user.show_super_description ? @user.super_description : nil
json.show_super_description @user.show_super_description json.show_super_description @user.show_super_description
json.description @user.description json.description @user.description
json.sponsor_description @user.sponsor_description

View File

@ -0,0 +1,2 @@
<h1>Wallets#balance</h1>
<p>Find me in app/views/wallets/balance.html.erb</p>

View File

@ -0,0 +1 @@
json.balance @wallet.balance

View File

@ -0,0 +1,12 @@
json.income do
json.array! (0..6).each do |i|
json.y @balance_chart_array[0][i]
json.x @balance_chart_array[2][i].to_date
end
end
json.outcome do
json.array! (0..6).each do |i|
json.y @balance_chart_array[1][i]
json.x @balance_chart_array[2][i].to_date
end
end

View File

@ -0,0 +1,25 @@
json.balance @wallet.balance
json.count @total
json.coin_changes do
json.array! @coin_changes do |coin_change|
from_user = if coin_change.from_wallet.nil?
nil
else
coin_change.from_wallet.user
end
to_user = coin_change.to_wallet.user
json.amount coin_change.amount
if !from_user.nil?
json.from_user from_user.full_name
json.from_user_login from_user.login
else
json.from_user '系统'
json.from_user_login '-'
end
json.to_user to_user.full_name
json.to_user_login to_user.login
json.description coin_change.description
json.reason coin_change.reason
json.date coin_change.created_at.to_date
end
end

View File

@ -0,0 +1,4 @@
json.array! (0..6).each do |i|
json.y @community_data_array[0][i]
json.x @community_data_array[1][i].to_date
end

View File

@ -1,12 +1,12 @@
development: #development:
adapter: redis # adapter: redis
url: redis://localhost:6379 # url: redis://localhost:6379
test: #test:
adapter: redis # adapter: redis
url: redis://localhost:6379 # url: redis://localhost:6379
production: #production:
adapter: redis # adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379" } %> # url: <%#= ENV.fetch("REDIS_URL") { "redis://localhost:6379" } %>
channel_prefix: forgeplus_production # channel_prefix: forgeplus_production

View File

@ -55,6 +55,9 @@ Rails.application.configure do
# Suppress logger output for asset requests. # Suppress logger output for asset requests.
config.assets.quiet = true config.assets.quiet = true
# config.logger = Logger.new("#{Rails.root}/log/#{Rails.env}#{Date.today.to_s}.log", "daily")
# config.logger.level = Logger::INFO
# config.assets.prefix = '/dev-assets' # config.assets.prefix = '/dev-assets'
# Raises error for missing translations # Raises error for missing translations

View File

@ -1,3 +1,3 @@
redis_config = Rails.application.config_for(:redis) redis_config = Rails.application.config_for(:redis)
cache_url = redis_config["url"] || 'redis://localhost:6379' cache_url = redis_config["url"] || 'redis://localhost:6379'
$redis_cache = Redis.new(url: cache_url, db: 2) # $redis_cache = Redis.new(url: cache_url, db: 2)

View File

@ -0,0 +1,9 @@
require 'multi_logger'
formatter = Proc.new{|severity, time, progname, msg|
formatted_severity = sprintf("%-5s",severity.to_s)
formatted_time = time.strftime("%Y-%m-%d %H:%M:%S")
# "[#{formatted_severity} #{formatted_time} #{$$}] #{msg.to_s.strip}\n"
"#{msg.to_s.strip}\n"
}
MultiLogger.add_logger('user_trace', formatter: formatter, shift_age: 'daily')
Rails.logger.user_trace.level = Logger::INFO

View File

@ -35,6 +35,28 @@ Rails.application.routes.draw do
resources :edu_settings resources :edu_settings
scope '/api' do scope '/api' do
get 'wallets/balance'
get 'wallets/coin_changes'
get 'wallets/balance_chart'
get 'sponsorships/community_data'
get 'wallets/community_data'
get 'log/list', to: 'log#list'
# post 'log/download', to: 'log#download'
match 'log/download/:filename' => 'log#download', :constraints => { filename: /[0-z\.]+/ }, via:[:get]
resources :sponsor_tiers, only: [:index, :show, :create, :update, :destroy]
resources :sponsorships, only: [:index, :show, :create, :update, :destroy] do
collection do
get :sponsored
get :sponsoring
get :stopped_sponsored
get :stopped_sponsoring
get :stopped
end
end
resources :topics, only: [:index] resources :topics, only: [:index]
namespace :ci do namespace :ci do
resources :languages, only: [:index, :show] do resources :languages, only: [:index, :show] do
@ -141,9 +163,9 @@ Rails.application.routes.draw do
delete :quit delete :quit
end end
end end
resources :team_projects, only: [:index, :create, :destroy] do resources :team_projects, only: [:index, :create, :destroy] do
collection do collection do
post :create_all post :create_all
delete :destroy_all delete :destroy_all
end end
end end
@ -242,6 +264,7 @@ Rails.application.routes.draw do
get :projects get :projects
get :watch_users get :watch_users
get :fan_users get :fan_users
put :update_sponsor_description
get :hovercard get :hovercard
put :update_image put :update_image
get :get_image get :get_image
@ -449,11 +472,11 @@ Rails.application.routes.draw do
end end
end end
namespace :traces do namespace :traces do
resources :trace_users, only: [:create] resources :trace_users, only: [:create]
scope "/:owner/:repo" do scope "/:owner/:repo" do
resource :projects, path: '/', only: [:index] do resource :projects, path: '/', only: [:index] do
member do member do
post :tasks post :tasks
get :task_results get :task_results
get :reload_task get :reload_task
@ -664,15 +687,15 @@ Rails.application.routes.draw do
post :cancel post :cancel
end end
end end
resources :project_invite_links, only: [:index] do resources :project_invite_links, only: [:index] do
collection do collection do
get :current_link get :current_link
post :generate_link post :generate_link
get :show_link get :show_link
post :redirect_link post :redirect_link
end end
end end
resources :webhooks, except: [:show, :new] do resources :webhooks, except: [:show, :new] do
member do member do
get :tasks get :tasks
post :test post :test
@ -768,12 +791,12 @@ Rails.application.routes.draw do
resources :project_licenses resources :project_licenses
resources :project_ignores resources :project_ignores
resources :reversed_keywords resources :reversed_keywords
resources :system_notifications do resources :system_notifications do
member do member do
get :history get :history
end end
end end
resources :message_templates, only: [:index, :new, :create, :edit, :update] do resources :message_templates, only: [:index, :new, :create, :edit, :update] do
collection do collection do
get :init_data get :init_data
end end
@ -944,7 +967,7 @@ Rails.application.routes.draw do
resources :nps do resources :nps do
post :switch_change, on: :collection post :switch_change, on: :collection
end end
resources :feedbacks, only: [:index, :destroy] do resources :feedbacks, only: [:index, :destroy] do
get :new_history, on: :member get :new_history, on: :member
post :create_history, on: :member post :create_history, on: :member
end end

41
config/schedule.rb Normal file
View File

@ -0,0 +1,41 @@
# Use this file to easily define all of your cron jobs.
#
# It's helpful, but not entirely necessary to understand cron before proceeding.
# http://en.wikipedia.org/wiki/Cron
# Example:
#
# set :output, "/path/to/my/cron_log.log"
#
# every 2.hours do
# command "/usr/bin/some_great_command"
# runner "MyModel.some_method"
# rake "some:great:rake:task"
# end
#
# every 4.days do
# runner "AnotherModel.prune_old_records"
# end
# Learn more: http://github.com/javan/whenever
#
set :environment, :development
every '0 1 20 * *' do
runner 'Sponsorship.monthly_payment'
end
every '0 2 * * *' do
runner 'Statistic.record'
end
# every 1.month, at: 'January 20th 10:00am' do
# runner 'Sponsorship.monthly_payment'
# end
# #######################################################
# * * * * * command to be executed
# - - - - -
# | | | | |
# | | | | +----- day of week (0 - 6) (Sunday=0)
# | | | +------- month (1 - 12)
# | | +--------- day of month (1 - 31)
# | +----------- hour (0 - 23)
# +------------- min (0 - 59)
# #######################################################

View File

@ -0,0 +1,8 @@
class AddColumnToTableUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :description, :string, default: ""
add_column :users, :sponsor_certification, :integer, default: 0
add_column :users, :sponsor_num, :integer, default: 0
add_column :users, :sponsored_num, :integer, default: 0
end
end

View File

@ -0,0 +1,12 @@
class CreateSponsorships < ActiveRecord::Migration[5.2]
def change
create_table :sponsorships do |t|
t.integer :amount
t.integer :visible
t.integer :sponsor_id
t.integer :developer_id
t.timestamps
end
end
end

View File

@ -0,0 +1,9 @@
class CreateSponsorTiers < ActiveRecord::Migration[5.2]
def change
create_table :sponsor_tiers do |t|
t.integer :tier
t.timestamps
end
end
end

View File

@ -0,0 +1,6 @@
class AddColumnToSponsorTiers < ActiveRecord::Migration[5.2]
def change
add_column :sponsor_tiers, :description, :string, default: ""
add_column :sponsor_tiers, :user_id, :integer
end
end

View File

@ -0,0 +1,11 @@
class CreateStoppedSponsorships < ActiveRecord::Migration[5.2]
def change
create_table :stopped_sponsorships do |t|
t.integer :amount
t.integer :sponsor_id
t.integer :developer_id
t.timestamps
end
end
end

View File

@ -0,0 +1,10 @@
class CreateWallets < ActiveRecord::Migration[5.2]
def change
create_table :wallets do |t|
t.integer :balance
t.integer :user_id
t.timestamps
end
end
end

View File

@ -0,0 +1,13 @@
class CreateCoinChanges < ActiveRecord::Migration[5.2]
def change
create_table :coin_changes do |t|
t.integer :amount
t.string :description
t.string :reason
t.integer :to_wallet_id
t.integer :from_wallet_id
t.timestamps
end
end
end

View File

@ -0,0 +1,12 @@
class CreateWaitlists < ActiveRecord::Migration[5.2]
def change
create_table :waitlists do |t|
t.string :applicant_id
t.string :integer
t.string :reviewer_id
t.string :integer
t.timestamps
end
end
end

Some files were not shown because too many files have changed in this diff Show More