diff --git a/.gitignore b/.gitignore
index 4a01bd5ec..d0186c4a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,7 +10,7 @@
# Ignore lock config file
*.log
-
+.env
# mac
*.DS_Store
.bashrc
@@ -84,4 +84,5 @@ redis_data/
dump.rdb
.tags*
ceshi_user.xlsx
-public/trace_task_results
\ No newline at end of file
+public/trace_task_results
+public/项目活跃度排行.xls
\ No newline at end of file
diff --git a/app/controllers/admins/dashboards_controller.rb b/app/controllers/admins/dashboards_controller.rb
index 2c01c8bd0..1e13621e9 100644
--- a/app/controllers/admins/dashboards_controller.rb
+++ b/app/controllers/admins/dashboards_controller.rb
@@ -28,6 +28,41 @@ class Admins::DashboardsController < Admins::BaseController
@day_new_project_count = Project.where(created_on: today).count
@weekly_new_project_count = Project.where(created_on: current_week).count
@month_new_project_count = Project.where(created_on: current_month).count
+
+ # 总的平台用户数
+ # 总的平台项目数
+ # 总的平台组织数
+ # 总的平台Issue数、评论数、PR数、Commit数
+ @user_count = User.count
+ @project_count = Project.count
+ @organization_count = Organization.count
+ @issue_count = Issue.count
+ @comment_count = Journal.count
+ @pr_count = PullRequest.count
+ @commit_count = CommitLog.count
+
+ @subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数"]
+ @subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload"]
+ @subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count]
+
+
+ tongji_service = Baidu::TongjiService.new
+ @access_token = tongji_service.access_token
+ Rails.logger.info "baidu_tongji_auth access_token ===== #{@access_token}"
+ # @overview_data = tongji_service.api_overview
+ last_date = DailyPlatformStatistic.order(:date).last
+ start_date = last_date.date
+ end_date = Time.now
+ if @access_token.present?
+ @overview_data = tongji_service.overview_batch_add(start_date, end_date)
+ tongji_service.source_from_batch_add(start_date, end_date)
+ end
+
+ @current_week_statistic = DailyPlatformStatistic.where(date: current_week)
+ @pre_week_statistic = DailyPlatformStatistic.where(date: pre_week)
+
+
+
end
def month_active_user
@@ -42,6 +77,19 @@ class Admins::DashboardsController < Admins::BaseController
render_ok(data: data)
end
+ def baidu_tongji
+ tongji_service = Baidu::TongjiService.new
+ redirect_to tongji_service.code_url
+ end
+
+ def baidu_tongji_auth
+ if params[:code].present?
+ tongji_service = Baidu::TongjiService.new
+ tongji_service.get_access_token(params[:code])
+ end
+ redirect_to "/admins/"
+ end
+
def evaluate
names = []
data = []
@@ -63,8 +111,12 @@ class Admins::DashboardsController < Admins::BaseController
Time.now.beginning_of_day..Time.now.end_of_day
end
- def current_week
+ def pre_7_days
7.days.ago.end_of_day..Time.now.end_of_day
+ end
+
+ def current_week
+ Time.now.beginning_of_week..Time.now.end_of_day
end
def current_month
@@ -72,6 +124,7 @@ class Admins::DashboardsController < Admins::BaseController
end
def pre_week
- 14.days.ago.end_of_day..7.days.ago.end_of_day
+ # 14.days.ago.end_of_day..7.days.ago.end_of_day
+ Time.now.prev_week..Time.now.prev_week.end_of_week
end
end
\ No newline at end of file
diff --git a/app/controllers/admins/identity_verifications_controller.rb b/app/controllers/admins/identity_verifications_controller.rb
index 51d5e423c..26dc35d3f 100644
--- a/app/controllers/admins/identity_verifications_controller.rb
+++ b/app/controllers/admins/identity_verifications_controller.rb
@@ -15,6 +15,7 @@ class Admins::IdentityVerificationsController < Admins::BaseController
def update
if @identity_verification.update(update_params)
+ UserAction.create(action_id: @identity_verification.id, action_type: "UpdateIdentityVerifications", user_id: current_user.id, :ip => request.remote_ip, data_bank: @identity_verification.attributes.to_json)
redirect_to admins_identity_verifications_path
flash[:success] = "更新成功"
else
diff --git a/app/controllers/admins/projects_rank_controller.rb b/app/controllers/admins/projects_rank_controller.rb
index c4f968da4..e4d8046e0 100644
--- a/app/controllers/admins/projects_rank_controller.rb
+++ b/app/controllers/admins/projects_rank_controller.rb
@@ -1,16 +1,55 @@
class Admins::ProjectsRankController < Admins::BaseController
-
def index
- @rank_date = rank_date
- deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
- $redis_cache.zrem("v2-project-rank-#{rank_date}", deleted_data) unless deleted_data.blank?
- @date_rank = $redis_cache.zrevrange("v2-project-rank-#{rank_date}", 0, -1, withscores: true)
+ @statistics = DailyProjectStatistic.where("date >= ? AND date <= ?", begin_date, end_date)
+ @statistics = @statistics.group(:project_id).select("project_id,
+ sum(score) as score,
+ sum(visits) as visits,
+ sum(watchers) as watchers,
+ sum(praises) as praises,
+ sum(forks) as forks,
+ sum(issues) as issues,
+ sum(pullrequests) as pullrequests,
+ sum(commits) as commits").includes(:project)
+ @statistics = @statistics.order("#{sort_by} #{sort_direction}")
+ export_excel(@statistics.limit(50))
end
private
- def rank_date
- params.fetch(:date, Date.today.to_s)
+ def begin_date
+ params.fetch(:begin_date, (Date.today-7.days).to_s)
+ end
+
+ def end_date
+ params.fetch(:end_date, Date.today.to_s)
+ end
+
+ def sort_by
+ DailyProjectStatistic.column_names.include?(params.fetch(:sort_by, "score")) ? params.fetch(:sort_by, "score") : "score"
+ end
+
+ def sort_direction
+ %w(desc asc).include?(params.fetch(:sort_direction, "desc")) ? params.fetch(:sort_direction, "desc") : "desc"
+ end
+
+ def export_excel(data)
+ book = Spreadsheet::Workbook.new
+ sheet = book.create_worksheet :name => "项目活跃度排行"
+ sheet.row(0).concat %w(排名 项目全称 项目地址 得分 访问数 关注数 点赞数 fork数 疑修数 合并请求数 提交数)
+ data.each_with_index do |d, index|
+ sheet[index+1,0] = index+1
+ sheet[index+1,1] = "#{d&.project&.owner&.real_name}/#{d&.project&.name}"
+ sheet[index+1,2] = "#{Rails.application.config_for(:configuration)['platform_url']}/#{d&.project&.owner&.login}/#{d&.project&.identifier}"
+ sheet[index+1,3] = d.score
+ sheet[index+1,4] = d.visits
+ sheet[index+1,5] = d.watchers
+ sheet[index+1,6] = d.praises
+ sheet[index+1,7] = d.forks
+ sheet[index+1,8] = d.issues
+ sheet[index+1,9] = d.pullrequests
+ sheet[index+1,10] = d.commits
+ end
+ book.write "#{Rails.root}/public/项目活跃度排行.xls"
end
end
\ No newline at end of file
diff --git a/app/controllers/admins/site_pages_controller.rb b/app/controllers/admins/site_pages_controller.rb
index f0e05e71d..306c91627 100644
--- a/app/controllers/admins/site_pages_controller.rb
+++ b/app/controllers/admins/site_pages_controller.rb
@@ -29,8 +29,12 @@ class Admins::SitePagesController < Admins::BaseController
end
def update
- @site_page.update(update_params)
- flash[:success] = '保存成功'
+ if update_params[:state] == "false" && update_params[:state_description].blank?
+ flash[:danger] = '关闭站点理由不能为空'
+ else
+ @site_page.update(update_params)
+ flash[:success] = '保存成功'
+ end
render 'edit'
end
diff --git a/app/controllers/admins/system_notifications_controller.rb b/app/controllers/admins/system_notifications_controller.rb
index e2081f1a2..33f3f20f1 100644
--- a/app/controllers/admins/system_notifications_controller.rb
+++ b/app/controllers/admins/system_notifications_controller.rb
@@ -25,7 +25,7 @@ class Admins::SystemNotificationsController < Admins::BaseController
@notification = SystemNotification.new(notification_params)
if @notification.save
redirect_to admins_system_notifications_path
- flash[:success] = '系统消息创建成功'
+ flash[:success] = '系统公告创建成功'
else
redirect_to admins_system_notifications_path
flash[:danger] = @notification.errors.full_messages.join(",")
@@ -37,7 +37,7 @@ class Admins::SystemNotificationsController < Admins::BaseController
if @notification.update_attributes(notification_params)
format.html do
redirect_to admins_system_notifications_path
- flash[:success] = '系统消息更新成功'
+ flash[:success] = '系统公告更新成功'
end
format.js {render_ok}
else
@@ -53,10 +53,10 @@ class Admins::SystemNotificationsController < Admins::BaseController
def destroy
if @notification.destroy
redirect_to admins_system_notifications_path
- flash[:success] = "系统消息删除成功"
+ flash[:success] = "系统公告删除成功"
else
redirect_to admins_system_notifications_path
- flash[:danger] = "系统消息删除失败"
+ flash[:danger] = "系统公告删除失败"
end
end
diff --git a/app/controllers/site_pages_controller.rb b/app/controllers/site_pages_controller.rb
index 903e037db..085f1b027 100644
--- a/app/controllers/site_pages_controller.rb
+++ b/app/controllers/site_pages_controller.rb
@@ -17,23 +17,31 @@ class SitePagesController < ApplicationController
end
def create
- return normal_status(-1, "你还未开通Page服务,无法进行部署") unless current_user.website_permission
- return normal_status(-1, "你已使用了 #{params[:identifier]} 作为page标识") if Page.exists?(identifier: params[:identifier], user: current_user)
- return normal_status(-1, "该仓库已开通Page服务") if Page.exists?(project: @project)
+ return normal_status(-1, '你还未开通Page服务,无法进行部署') unless current_user.website_permission
+ return normal_status(-1, '你已开通Page服务') if Page.exists?(user: current_user)
+ return normal_status(-1, '该仓库已开通Page服务') if Page.exists?(project: @project)
@page = Page.new(create_params)
@page.user = current_user
@page.project = @project
@page.save
end
+ def update
+ return normal_status(-1, '你还未开通Page服务') unless current_user.website_permission
+ return normal_status(-1, '你还未开通Page站点') unless Page.exists?(user: current_user)
+ @page = Page.find_by(user: current_user)
+ @page.update(language_frame: params[:language_frame])
+ render_ok
+ end
+
def build
- return normal_status(-1, "你还未开通Page服务,无法进行部署") unless current_user.website_permission
- return normal_status(-1, "该仓库还未开通Page服务,无法进行部署") unless Page.exists?(project: @project)
+ return normal_status(-1, '你还未开通Page服务,无法进行部署') unless current_user.website_permission
+ return normal_status(-1, '该仓库还未开通Page服务,无法进行部署') unless Page.exists?(project: @project)
@page = Page.find params[:id]
return normal_status(-1, @page.state_description) unless @page.state
response_str = @page.deploy_page(params[:branch])
- data = JSON.parse(response_str)["result"] || data = JSON.parse(response_str)["error"]
- if data.to_s.include?("部署成功")
+ data = JSON.parse(response_str)['result'] || (data = JSON.parse(response_str)['error'])
+ if data.to_s.include?('部署成功')
@page.update(last_build_at: Time.now, build_state: true, last_build_info: data)
else
@page.update(build_state:false, last_build_info: data)
@@ -42,22 +50,22 @@ class SitePagesController < ApplicationController
end
def softbot_build
- branch = params[:ref].split("/").last
+ branch = params[:ref].split('/').last
user = User.find_by_login params[:repository][:owner][:login]
- return normal_status(-1, "你还未开通Page服务,无法进行部署") unless user.website_permission
+ return normal_status(-1, '你还未开通Page服务,无法进行部署') unless user.website_permission
project = Project.where(identifier: params[:repository][:name],user_id: user.id)
- return normal_status(-1, "你没有权限操作") if project.owner?(user)
- return normal_status(-1, "该仓库还未开通Page服务,无法进行部署") if Page.exists?(user: user, project: project)
+ return normal_status(-1, '你没有权限操作') if project.owner?(user)
+ return normal_status(-1, '该仓库还未开通Page服务,无法进行部署') if Page.exists?(user: user, project: project)
@page = Page.find_by(user: user, project: project)
response_str = @page.deploy_page(branch)
- data = JSON.parse(response_str)["result"]
+ data = JSON.parse(response_str)['result']
if data.nil?
- data = JSON.parse(response_str)["error"]
+ data = JSON.parse(response_str)['error']
end
- if data.include?("部署成功")
+ if data.include?('部署成功')
@page.update(last_build_at: Time.now, build_state: true, last_build_info: data)
else
@page.update(build_state:false, last_build_info: data)
@@ -85,7 +93,7 @@ class SitePagesController < ApplicationController
end
def theme_params
- params[:language_frame] || "hugo"
+ params[:language_frame] || 'hugo'
end
def create_params
diff --git a/app/forms/organizations/create_form.rb b/app/forms/organizations/create_form.rb
index 2163f477e..1f40350b3 100644
--- a/app/forms/organizations/create_form.rb
+++ b/app/forms/organizations/create_form.rb
@@ -1,12 +1,12 @@
class Organizations::CreateForm < BaseForm
- NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
+ NAME_REGEX = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*$/ #只含有数字、字母、下划线不能以下划线开头和结尾
attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname, :original_name
validates :name, :nickname, :visibility, presence: true
validates :name, :nickname, length: { maximum: 100 }
validates :location, length: { maximum: 50 }
validates :description, length: { maximum: 200 }
- validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
+ validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符" }
validate do
check_name(name) unless name.blank? || name == original_name
diff --git a/app/jobs/daily_platform_statistics_job.rb b/app/jobs/daily_platform_statistics_job.rb
new file mode 100644
index 000000000..5610f304b
--- /dev/null
+++ b/app/jobs/daily_platform_statistics_job.rb
@@ -0,0 +1,44 @@
+# 按天获取百度统计数据,pv,访问,ip和来源分类占比
+# 其他统计:前一周用户留存率
+class DailyPlatformStatisticsJob < ApplicationJob
+ queue_as :default
+
+ def perform(*args)
+ Rails.logger.info("*********开始统计*********")
+
+ tongji_service = Baidu::TongjiService.new
+ access_token = tongji_service.access_token
+ Rails.logger.info "job baidu_tongji_auth access_token ===== #{access_token}"
+ ActiveJob::Base.logger.info "job baidu_tongji_auth access_token ===== #{access_token}"
+ # 从最后一个记录日期开始,如果遗漏日期数据可以补充数据
+ last_date = DailyPlatformStatistic.order(:date).last
+ start_date = last_date.date
+ end_date = Time.now
+ if access_token.present?
+ tongji_service.overview_batch_add(start_date, end_date)
+
+ # 本周访问来源占比,每天记录一次,如果遗漏日期数据可以补充数据
+ tongji_service.source_from_batch_add(start_date, end_date)
+ end
+ # 周用户留存率
+ pre_week_user_ids = User.where(created_on: pre_week).pluck(:id).uniq
+ weekly_keep_user_count = User.where(id: pre_week_user_ids).where(last_login_on: current_week).count
+ weekly_keep_rate = format("%.2f", pre_week_user_ids.size > 0 ? weekly_keep_user_count.to_f / pre_week_user_ids.size : 0)
+
+ job_date = 1.days.ago
+ daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: job_date)
+ daily_statistic.weekly_keep_rate = weekly_keep_rate
+ daily_statistic.save
+ end
+
+ private
+
+ def current_week
+ Time.now.beginning_of_week..Time.now.end_of_day
+ end
+
+ def pre_week
+ # 7.days.ago.beginning_of_week..7.days.ago.beginning_of_week.end_of_week
+ Time.now.prev_week..Time.now.prev_week.end_of_week
+ end
+end
diff --git a/app/jobs/daily_project_statistics_job.rb b/app/jobs/daily_project_statistics_job.rb
new file mode 100644
index 000000000..ad606f137
--- /dev/null
+++ b/app/jobs/daily_project_statistics_job.rb
@@ -0,0 +1,33 @@
+class DailyProjectStatisticsJob < ApplicationJob
+ queue_as :cache
+
+ def perform
+ date = (Date.today - 1.days).to_s
+ daily_data_keys = $redis_cache.keys("v2-project-statistic:*-#{date}")
+ daily_data_keys.each do |key|
+ result = $redis_cache.hgetall(key)
+ project_id = key.gsub('v2-project-statistic:', '').gsub("-#{date}", '')
+ next unless Project.find_by_id(project_id).present?
+ visits = result["visits"].to_i
+ watchers = result["watchers"].to_i
+ praises = result["praises"].to_i
+ forks = result["forks"].to_i
+ issues = result["issues"].to_i
+ pullrequests = result["pullrequests"].to_i
+ commits = result["commits"].to_i
+ score = visits *1 + watchers *5 + praises * 5 + forks * 10 + issues *5 + pullrequests * 10 + commits * 5
+ DailyProjectStatistic.create!(
+ project_id: project_id,
+ date: date,
+ score: score ,
+ visits: visits,
+ watchers: watchers,
+ praises: praises,
+ forks: forks,
+ issues: issues,
+ pullrequests: pullrequests,
+ commits: commits
+ )
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index 810474609..9fd858bf3 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -1,44 +1,45 @@
-# == Schema Information
-#
-# Table name: attachments
-#
-# id :integer not null, primary key
-# container_id :integer
-# container_type :string(30)
-# filename :string(255) default(""), not null
-# disk_filename :string(255) default(""), not null
-# filesize :integer default("0"), not null
-# content_type :string(255) default("")
-# digest :string(60) default(""), not null
-# downloads :integer default("0"), not null
-# author_id :integer default("0"), not null
-# created_on :datetime
-# description :text(65535)
-# disk_directory :string(255)
-# attachtype :integer default("1")
-# is_public :integer default("1")
-# copy_from :integer
-# quotes :integer default("0")
-# is_publish :integer default("1")
-# publish_time :datetime
-# resource_bank_id :integer
-# unified_setting :boolean default("1")
-# cloud_url :string(255) default("")
-# course_second_category_id :integer default("0")
-# delay_publish :boolean default("0")
-# memo_image :boolean default("0")
-# extra_type :integer default("0")
-# uuid :string(255)
-#
-# Indexes
-#
-# index_attachments_on_author_id (author_id)
-# 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_is_public (is_public)
-# index_attachments_on_quotes (quotes)
-#
+# == Schema Information
+#
+# Table name: attachments
+#
+# id :integer not null, primary key
+# container_id :integer
+# container_type :string(30)
+# filename :string(255) default(""), not null
+# disk_filename :string(255) default(""), not null
+# filesize :integer default("0"), not null
+# content_type :string(255) default("")
+# digest :string(60) default(""), not null
+# downloads :integer default("0"), not null
+# author_id :integer default("0"), not null
+# created_on :datetime
+# description :text(65535)
+# disk_directory :string(255)
+# attachtype :integer default("1")
+# is_public :integer default("1")
+# copy_from :integer
+# quotes :integer default("0")
+# is_publish :integer default("1")
+# publish_time :datetime
+# resource_bank_id :integer
+# unified_setting :boolean default("1")
+# cloud_url :string(255) default("")
+# course_second_category_id :integer default("0")
+# delay_publish :boolean default("0")
+# memo_image :boolean default("0")
+# extra_type :integer default("0")
+# uuid :string(255)
+#
+# Indexes
+#
+# index_attachments_on_author_id (author_id)
+# 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_is_public (is_public)
+# index_attachments_on_quotes (quotes)
+#
+
diff --git a/app/models/daily_platform_statistic.rb b/app/models/daily_platform_statistic.rb
new file mode 100644
index 000000000..a904d9b1e
--- /dev/null
+++ b/app/models/daily_platform_statistic.rb
@@ -0,0 +1,24 @@
+# == Schema Information
+#
+# Table name: daily_platform_statistics
+#
+# id :integer not null, primary key
+# date :date
+# pv :integer default("0")
+# visitor :integer default("0")
+# ip :integer default("0")
+# weekly_keep_rate :float(24) default("0")
+# source_through :float(24) default("0")
+# source_link :float(24) default("0")
+# source_search :float(24) default("0")
+# source_custom :float(24) default("0")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_daily_platform_statistics_on_date (date) UNIQUE
+#
+
+class DailyPlatformStatistic < ApplicationRecord
+end
diff --git a/app/models/daily_project_statistic.rb b/app/models/daily_project_statistic.rb
new file mode 100644
index 000000000..f7fc0aad7
--- /dev/null
+++ b/app/models/daily_project_statistic.rb
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: daily_project_statistics
+#
+# id :integer not null, primary key
+# project_id :integer
+# date :string(255)
+# visits :integer default("0")
+# watchers :integer default("0")
+# praises :integer default("0")
+# forks :integer default("0")
+# issues :integer default("0")
+# pullrequests :integer default("0")
+# commits :integer default("0")
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_daily_project_statistics_on_date (date)
+# index_daily_project_statistics_on_project_id (project_id)
+#
+
+class DailyProjectStatistic < ApplicationRecord
+
+
+ belongs_to :project
+end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index edc743b0e..1c82d7120 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -36,12 +36,17 @@
# blockchain_token_num :integer
# pm_project_id :integer
# pm_sprint_id :integer
+# pm_issue_type :integer
+# time_scale :decimal(10, 2) default("0.00")
+# child_count :integer default("0")
+# changer_id :integer
#
# Indexes
#
# index_issues_on_assigned_to_id (assigned_to_id)
# index_issues_on_author_id (author_id)
# index_issues_on_category_id (category_id)
+# index_issues_on_changer_id (changer_id)
# index_issues_on_created_on (created_on)
# index_issues_on_fixed_version_id (fixed_version_id)
# index_issues_on_priority_id (priority_id)
diff --git a/app/models/issue_tag.rb b/app/models/issue_tag.rb
index a3782abaf..f5f0abbd8 100644
--- a/app/models/issue_tag.rb
+++ b/app/models/issue_tag.rb
@@ -14,6 +14,7 @@
# gid :integer
# gitea_url :string(255)
# pull_requests_count :integer default("0")
+# pm_project_id :integer
#
# Indexes
#
diff --git a/app/models/journal.rb b/app/models/journal.rb
index c22dcaeec..4ee37714b 100644
--- a/app/models/journal.rb
+++ b/app/models/journal.rb
@@ -27,6 +27,7 @@
#
# index_journals_on_created_on (created_on)
# index_journals_on_journalized_id (journalized_id)
+# index_journals_on_parent_id (parent_id)
# index_journals_on_review_id (review_id)
# index_journals_on_user_id (user_id)
# journals_journalized_id (journalized_id,journalized_type)
diff --git a/app/models/organization.rb b/app/models/organization.rb
index cb829626e..237efbfe9 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -64,7 +64,7 @@
class Organization < Owner
alias_attribute :name, :login
- NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾
+ NAME_REGEX = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*$/ #只含有数字、字母、下划线不能以下划线开头和结尾
default_scope { where(type: "Organization") }
@@ -79,7 +79,7 @@ class Organization < Owner
validates :login, presence: true
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: "只能含有数字、字母、下划线且不能以下划线开头和结尾" }
+ validates :login, format: { with: NAME_REGEX, multiline: true, message: "只能以数字或字母开头,仅支持横杠、下划线、点三种符号,不允许符号连续排列,长度4-50个字符" }
delegate :description, :website, :location, :repo_admin_change_team_access, :recommend,
:visibility, :max_repo_creation, :num_projects, :num_users, :num_teams,
diff --git a/app/models/page.rb b/app/models/page.rb
index 57a30acad..1c606760e 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -34,6 +34,10 @@ class Page < ApplicationRecord
PageService.genernate_user(user_id)
end
+ before_destroy do
+ PageService.close_site(user_id, identifier)
+ end
+
before_save do
if state_changed? && state == false
PageService.close_site(user_id, identifier)
@@ -46,7 +50,7 @@ class Page < ApplicationRecord
def url
@deploy_domain = EduSetting.find_by_name("site_page_deploy_domain").try(:value)
- "http://#{user.login}.#{@deploy_domain}/#{identifier}"
+ "http://#{identifier}"
end
def build_script_path
diff --git a/app/models/project.rb b/app/models/project.rb
index 5f9fcef68..34e981508 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -136,6 +136,7 @@ class Project < ApplicationRecord
has_many :project_topic_ralates, dependent: :destroy
has_many :project_topics, through: :project_topic_ralates
has_many :commit_logs, dependent: :destroy
+ has_many :daily_project_statistics, dependent: :destroy
after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
diff --git a/app/models/user.rb b/app/models/user.rb
index 8f1e29547..8ffa5b181 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -189,7 +189,7 @@ class User < Owner
has_many :user_clas, :dependent => :destroy
has_many :clas, through: :user_clas
- has_many :pages, :dependent => :destroy
+ has_one :page, :dependent => :destroy
# Groups and active users
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
@@ -773,7 +773,7 @@ class User < Owner
def check_website_permission
if website_permission_changed? && website_permission == false
- self.pages.update_all(state: false, state_description:"因违规使用,现关闭Page服务")
+ self.page.update(state: false, state_description:"因违规使用,现关闭Page服务")
PageService.close_site(self.id)
end
end
diff --git a/app/services/api/v1/issues/list_service.rb b/app/services/api/v1/issues/list_service.rb
index 184eaa4f1..983e97c18 100644
--- a/app/services/api/v1/issues/list_service.rb
+++ b/app/services/api/v1/issues/list_service.rb
@@ -60,13 +60,31 @@ class Api::V1::Issues::ListService < ApplicationService
issues = issues.where(author_id: author_id) if author_id.present?
# issue_tag_ids
- issues = issues.ransack(issue_tags_value_cont: issue_tag_ids.sort!.join(',')).result unless issue_tag_ids.blank?
+ if issue_tag_ids.present?
+ if issue_tag_ids.include?('-1')
+ issues = issues.where(issue_tags_value: nil).or(issues.where(issue_tags_value: ""))
+ else
+ issues = issues.ransack(issue_tags_value_cont: issue_tag_ids.sort!.join(',')).result
+ end
+ end
# milestone_id
- issues = issues.where(fixed_version_id: milestone_id) if milestone_id.present?
+ if milestone_id.present?
+ if milestone_id.to_i == -1
+ issues = issues.where(fixed_version_id: nil)
+ else
+ issues = issues.where(fixed_version_id: milestone_id)
+ end
+ end
# assigner_id
- issues = issues.joins(:assigners).where(users: {id: assigner_id}) if assigner_id.present?
+ if assigner_id.present?
+ if assigner_id.to_i == -1
+ issues = issues.left_joins(:assigners).where(users: {id: nil})
+ else
+ issues = issues.joins(:assigners).where(users: {id: assigner_id})
+ end
+ end
# status_id
issues = issues.where(status_id: status_id) if status_id.present? && category != 'closed'
diff --git a/app/services/baidu/tongji_service.rb b/app/services/baidu/tongji_service.rb
new file mode 100644
index 000000000..8a611cd0f
--- /dev/null
+++ b/app/services/baidu/tongji_service.rb
@@ -0,0 +1,221 @@
+module Baidu
+ class TongjiService < ApplicationService
+ attr_reader :client_id, :client_secret, :site_id
+ # login、code、password、password_confirmation
+ def initialize
+ @client_id = "6dMO2kqKUaMZkBrMaUMxQSNAT49v0Mjq"
+ @client_secret = "qvWqF33AOmGs1tPCgsROvis9EQCuNmd3"
+ @site_id = 18657013
+ end
+
+ def call
+
+ end
+
+
+ def init_overview_data_by(start_date = nil, end_date = nil)
+ start_date = Time.now.prev_year.beginning_of_year if start_date.nil?
+ end_date = Time.now
+ Rails.logger.info("*********开始百度统计-概览:#{start_date}-#{end_date}*********")
+ sql_connection = ActiveRecord::Base.connection
+ sql_connection.begin_db_transaction
+
+ # 如果存在数据 先清空
+ # sql_connection.execute("delete from daily_platform_statistics where date between '#{start_date}' and '#{end_date}'")
+ multiple_days_data = overview_multiple_days_data(start_date, end_date)
+ if multiple_days_data.present?
+ sql = "replace into daily_platform_statistics (date,pv,visitor,ip,created_at,updated_at) values #{multiple_days_data.join(",")}"
+ sql_connection.execute(sql)
+ end
+ sql_connection.commit_db_transaction
+ Rails.logger.info("*********结束百度统计-概览:#{start_date}-#{end_date}*********")
+ end
+
+ def init_source_from_data_by(start_date = nil, end_date = nil)
+ start_date = Time.now.prev_year.beginning_of_year if start_date.nil?
+ end_date = Time.now
+ Rails.logger.info("*********开始百度统计-来源:#{start_date}-#{end_date}*********")
+ source_from_batch_add(start_date, end_date)
+ Rails.logger.info("*********结束百度统计-来源:#{start_date}-#{end_date}*********")
+ end
+
+ # 按日期获取来源数据
+ def source_from_batch_add(start_date,end_date)
+ # 补充更新开始时间的当天数据
+ source_from_by_date(start_date)
+ diff_days(start_date, end_date).times.each do |t|
+ new_start_date = start_date + (t + 1).days
+ source_from_by_date(new_start_date)
+ end
+ # 补充更新最后时间一天数据
+ source_from_by_date(end_date)
+ end
+
+ # 按天获取来源数据
+ def source_from_by_date(start_date)
+ return [] unless access_token.present? && start_date.present?
+ source_from_data = api("source/all/a", start_date, start_date, "pv_count,visitor_count,ip_count")
+ source_from = []
+ source_from_data['items'][1].each_with_index do |source, index|
+ source_from.push(((source[0].to_f / source_from_data['sum'][0][0].to_f) * 100).round(2))
+ end
+ daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: start_date)
+ daily_statistic.source_through = source_from[0]
+ daily_statistic.source_link = source_from[1]
+ daily_statistic.source_search = source_from[2]
+ daily_statistic.source_custom = source_from[3]
+ daily_statistic.save
+ end
+
+ def diff_days(start_date, end_date)
+ (end_date.beginning_of_day.to_i - start_date.beginning_of_day.to_i) / (24 * 3600)
+ end
+
+ def overview_batch_add(start_date, end_date)
+ return [] unless access_token.present? && start_date.present? && end_date.present?
+ start_date = Time.now - 1.days if start_date.strftime("%Y%m%d") == end_date.strftime("%Y%m%d")
+ overview_data = api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count")
+ overview_data['items'][0].each_with_index do |date, index|
+ pv = overview_data['items'][1][index][0]
+ visitor = overview_data['items'][1][index][1]
+ ip = overview_data['items'][1][index][2]
+ job_date = date[0].to_s.gsub("/", "-")
+ daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: job_date)
+ daily_statistic.date = job_date
+ daily_statistic.pv = pv
+ daily_statistic.visitor = visitor
+ daily_statistic.ip = ip
+ daily_statistic.save
+ end
+ overview_data
+ end
+
+ def overview_multiple_days_data(start_date, end_date)
+ return [] unless access_token.present? && start_date.present? && end_date.present?
+ overview_data = api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count")
+ data = []
+ created_at = Time.now.strftime("%Y-%m-%d 00:00:00")
+ overview_data['items'][0].each_with_index do |date, index|
+ pv = overview_data['items'][1][index][0]
+ visitor = overview_data['items'][1][index][1]
+ ip = overview_data['items'][1][index][2]
+ data.push("('#{date[0].to_s.gsub("/", "-")}', #{pv.to_s.gsub("--","0")}, #{visitor.to_s.gsub("--","0")}, #{ip.to_s.gsub("--","0")},\"#{created_at}\",\"#{created_at}\")")
+ end
+ data
+ end
+
+ def code_url
+ "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=#{client_id}&redirect_uri=oob&scope=basic&display=popup"
+ end
+
+ def oauth_url(code)
+ "http://openapi.baidu.com/oauth/2.0/token?grant_type=authorization_code&code=#{code}&client_id=#{client_id}&client_secret=#{client_secret}&redirect_uri=oob"
+ end
+
+ def get_access_token(code)
+ uri = URI.parse(oauth_url(code))
+ response = Net::HTTP.get_response(uri)
+ Rails.logger.info "baidu_tongji_auth response.body ===== #{response.body}"
+ if response.code.to_i == 200
+ data = JSON.parse(response.body)
+ access_token = data['access_token']
+ refresh_token = data['refresh_token']
+ expires_in = data['expires_in']
+ if access_token.present?
+ Rails.cache.write("baidu_tongji_auth/access_token", access_token, expires_in: expires_in)
+ Rails.cache.write("baidu_tongji_auth/refresh_token", refresh_token, expires_in: 1.year)
+ end
+ end
+ end
+
+ def refresh_access_token
+ url = "http://openapi.baidu.com/oauth/2.0/token?grant_type=refresh_token&refresh_token=#{refresh_token}&client_id=#{client_id}&client_secret=#{client_secret}"
+ uri = URI.parse(url)
+ response = Net::HTTP.get_response(uri)
+ Rails.logger.info "baidu_tongji_auth response.body ===== #{response.body}"
+ if response.code.to_i == 200
+ data = JSON.parse(response.body)
+ access_token = data['access_token']
+ refresh_token = data['refresh_token']
+ expires_in = data['expires_in']
+ if access_token.present?
+ Rails.cache.write("baidu_tongji_auth/access_token", access_token, expires_in: expires_in)
+ Rails.cache.write("baidu_tongji_auth/refresh_token", refresh_token, expires_in: 1.year)
+ end
+ end
+ end
+
+ def access_token
+ access_token = Rails.cache.read("baidu_tongji_auth/access_token")
+ if access_token.blank?
+ refresh_access_token
+ access_token = Rails.cache.read("baidu_tongji_auth/access_token")
+ end
+ access_token
+ end
+
+ def refresh_token
+ refresh_token = Rails.cache.read("baidu_tongji_auth/refresh_token")
+ # 如果刷新token失效,access_token也重置
+ if refresh_token.blank?
+ Rails.cache.delete("baidu_tongji_auth/access_token")
+ end
+ refresh_token
+ end
+
+ # 网站概况(趋势数据)
+ def api_overview
+ start_date = Time.now.beginning_of_week
+ end_date = Time.now
+ start_date = Time.now - 1.days if start_date.strftime("%Y%m%d") == end_date.strftime("%Y%m%d")
+ api("overview/getTimeTrendRpt", start_date, end_date, "pv_count,visitor_count,ip_count")
+ end
+
+ # 网站概况(来源网站、搜索词、入口页面、受访页面)
+ def api_overview_getCommonTrackRpt
+ start_date = Time.now.beginning_of_week
+ end_date = Time.now
+ api("overview/getCommonTrackRpt", start_date, end_date, "pv_count")
+ end
+
+ # 全部来源
+ def source_from
+ start_date = Time.now.beginning_of_week
+ end_date = Time.now
+ api("source/all/a", start_date, end_date, "pv_count,visitor_count,ip_count")
+ end
+
+ def api(api_method, start_date, end_date, metrics = nil)
+ start_date_fmt = start_date.strftime("%Y%m%d")
+ end_date_fmt = end_date.strftime("%Y%m%d")
+ api_url = "https://openapi.baidu.com/rest/2.0/tongji/report/getData?access_token=#{access_token}&site_id=#{site_id}&method=#{api_method}&start_date=#{start_date_fmt}&end_date=#{end_date_fmt}&metrics=#{metrics}"
+ data = url_http_post(api_url, {})
+ data['result']
+ end
+
+ def url_http_post(api_url, params)
+ Rails.logger.info "api_url==#{api_url}"
+ uri = URI.parse(api_url)
+ http = Net::HTTP.new uri.host, uri.port
+ http.open_timeout = 60
+ http.read_timeout = 60
+ if uri.scheme == 'https'
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ http.use_ssl = true
+ end
+ begin
+ request = Net::HTTP::Post.new(uri)
+ request.set_form_data(params) if params.present?
+ request['Content-Type'] = 'application/json;charset=utf-8'
+ # request['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'
+ response = http.start { |http| http.request(request) }
+ Rails.logger.info "api response.body==#{response.body}"
+ JSON.parse response.body
+ rescue => err
+ Rails.logger.error("#############api_url:#{api_url},error:#{err.message.size}")
+ # Rails.logger.error("#############api_url:#{api_url},error:#{err.message}")
+ return {}
+ end
+ end
+ end
+end
diff --git a/app/services/page_service.rb b/app/services/page_service.rb
index 687added1..5c166e82c 100644
--- a/app/services/page_service.rb
+++ b/app/services/page_service.rb
@@ -26,7 +26,7 @@ class PageService
Rails.logger.info "################### PageService close_site #{user_id} / #{identifier}"
user = User.find user_id
uri = if identifier.present?
- URI.parse("http://gitlink.#{@deploy_domain}/gitlink_execute_script?key=#{@deploy_key}&script_path=remove_dir&owner=#{user.login.downcase}/#{identifier}/")
+ URI.parse("http://gitlink.#{@deploy_domain}/gitlink_execute_script?key=#{@deploy_key}&script_path=remove_dir&owner=#{user.login.downcase}/*")
else
URI.parse("http://gitlink.#{@deploy_domain}/gitlink_execute_script?key=#{@deploy_key}&script_path=remove_dir&owner=#{user.login.downcase}/")
end
diff --git a/app/views/admins/carousels/index.html.erb b/app/views/admins/carousels/index.html.erb
index 299d1dcfd..e9529c862 100644
--- a/app/views/admins/carousels/index.html.erb
+++ b/app/views/admins/carousels/index.html.erb
@@ -1,6 +1,6 @@
<%
define_admin_breadcrumbs do
- add_admin_breadcrumb('云上实验室', admins_laboratories_path)
+ add_admin_breadcrumb('导航栏配置', admins_laboratories_path)
add_admin_breadcrumb('轮播图')
end
%>
diff --git a/app/views/admins/dashboards/_baidu_tongji.html.erb b/app/views/admins/dashboards/_baidu_tongji.html.erb
new file mode 100644
index 000000000..c59e1acad
--- /dev/null
+++ b/app/views/admins/dashboards/_baidu_tongji.html.erb
@@ -0,0 +1,50 @@
+
+ 数据来源百度统计,本周 [<%= @current_week_statistic.first&.date %> / <%= @current_week_statistic.last&.date %>]
+
+
+
+
+ 日期 |
+ 访问量 |
+ 访客数 |
+ IP数 |
+ 直接访问占比 |
+ 外部链接占比 |
+ 搜索引擎占比 |
+ 自定义 |
+
+
+
+ <% @current_week_statistic.each_with_index do |week, index| %>
+
+ <%= week.date %> |
+ <%= week.pv %> |
+ <%= week.visitor %> |
+ <%= week.ip %> |
+ <%= week.source_through %>% |
+ <%= week.source_link %>% |
+ <%= week.source_search %>% |
+ <%= week.source_custom.to_f %>% |
+
+
+ <% end %>
+
+
+
+
+
+
+
+
+
+
+
+<% unless @access_token.present? && @overview_data.present? %>
+
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/admins/dashboards/_baidu_tongji_api.html.erb b/app/views/admins/dashboards/_baidu_tongji_api.html.erb
new file mode 100644
index 000000000..3a18dc405
--- /dev/null
+++ b/app/views/admins/dashboards/_baidu_tongji_api.html.erb
@@ -0,0 +1,67 @@
+<% if @access_token.present? && @overview_data.present? %>
+
+ 数据来源百度统计,本周 <%= @overview_data['timeSpan'] %>
+
+
+
+
+ 日期 |
+ 访问量 |
+ 访客数 |
+ IP数 |
+
+
+
+ <% pv_count = [] %>
+ <% visitor_count = [] %>
+ <% ip_count = [] %>
+ <% @overview_data['items'][0].each_with_index do |date, index| %>
+ <% pv = @overview_data['items'][1][index][0] %>
+ <% visitor = @overview_data['items'][1][index][1] %>
+ <% ip = @overview_data['items'][1][index][2] %>
+
+ <%= date[0] %> |
+ <%= pv %> |
+ <%= visitor %> |
+ <%= ip %> |
+
+
+ <% pv_count.push(pv) %>
+ <% visitor_count.push(visitor) %>
+ <% ip_count.push(ip) %>
+ <% end %>
+
+ 合计 |
+ <%= pv_count %> |
+ <%= visitor_count %> |
+ <%= ip_count %> |
+
+
+
+
+
+
+
+ 直接访问占比 |
+ 外部链接占比 |
+ 搜索引擎占比 |
+ 自定义 |
+
+
+
+
+ <% @source_from_data['items'][1].each_with_index do |source, index| %>
+ <%= ((source[0].to_f / @source_from_data['sum'][0][0].to_f) * 100).round(2).to_s %>% |
+ <% end %>
+
+
+
+<% else %>
+
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/admins/dashboards/index.html.erb b/app/views/admins/dashboards/index.html.erb
index 2d86b4b6c..35593f169 100644
--- a/app/views/admins/dashboards/index.html.erb
+++ b/app/views/admins/dashboards/index.html.erb
@@ -1,6 +1,35 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('概览', admins_path) %>
<% end %>
+
+ <%= render partial: 'admins/dashboards/baidu_tongji' %>
\ No newline at end of file
diff --git a/app/views/admins/laboratories/index.html.erb b/app/views/admins/laboratories/index.html.erb
index 8811f4ab3..adf34d6f4 100644
--- a/app/views/admins/laboratories/index.html.erb
+++ b/app/views/admins/laboratories/index.html.erb
@@ -1,5 +1,5 @@
<% define_admin_breadcrumbs do %>
- <% add_admin_breadcrumb('云上实验室') %>
+ <% add_admin_breadcrumb('导航栏配置') %>
<% end %>