forgeplus/app/controllers/users/statistics_controller.rb

453 lines
21 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Users::StatisticsController < Users::BaseController
before_action :preload_develop_data, only: [:develop]
before_action :preload_badge_data, only: [:badges]
# 近期活动统计
def activity
date_range = (1.week.ago.to_date..Date.today).to_a
commit_request = Gitea::User::HeadmapService.call(observed_user.login, 1.week.ago.to_date.to_time.to_i, Date.today.to_time.to_i)
commit_data = commit_request[2]
@date_data = []
@issue_data = []
@pull_request_data = []
@commit_data = []
date_range.each do |date|
@date_data << date.strftime("%Y.%m.%d")
@issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size
@pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size
date_commit_data = commit_data.blank? ? nil : commit_data.select{|item| item["timestamp"] == date.to_time.to_i}
@commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i)
end
render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data}
end
###############change###############
# 用户badges 接口 url 路径为/api/users/:user_id/statistic/badges
# 三类
# 第一类 贡献类
# 1. 用户累积获得高星
# 2. 用户关注数超过10人
# 3. 用户的累积获赞人数
# 4. 用户连续一周有commit
# 5. 用户累积pr数
# 第二类 活动类
# 第三类 特殊类
def badges
badges_visable = Array.new
@badges_dic.each do |key,value|
if value > 0
#与describe同理此处应该再增加一个 url字典
describe = @badges_describe_dic[key]
badges_visable.append({"#{key}":value, "describe":describe})
end
end
render :json => {list: badges_visable, count: badges_visable.size}
end
###############change###############
# 开发能力
def develop
if params[:start_time].present? && params[:end_time].present?
# 影响力
@influence = (60.0 + @follow_count / (@follow_count + 10.0) * 40.0).to_i
@platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 10.0) * 40.0).to_i
# 贡献度
@contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 10.0) * 40.0).to_i
@platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 10.0) * 40.0).to_i
# 活跃度
@activity = (60.0 + @issues_count / (@issues_count + 10.0) * 40.0).to_i
@platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 10.0) * 40.0).to_i
# 项目经验
@experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count
@experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i
@platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count
@platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i
# 语言能力
@language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i
@platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i
# 语言百分比
@languages_percent = Hash.new
for key in @project_languages_count.keys do
@languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2)
end
@platform_languages_percent = Hash.new
for key in @platform_project_languages_count.keys do
@platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2)
end
# 各门语言分数
@each_language_score = Hash.new
for key in @project_languages_count.keys do
@each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i
end
@platform_each_language_score = Hash.new
for key in @platform_project_languages_count.keys do
@platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i
end
else
# 影响力
@influence = (60.0 + @follow_count / (@follow_count + 20.0) * 40.0).to_i
@platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 20.0) * 40.0).to_i
# 贡献度
@contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 20.0) * 40.0).to_i
@platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 20.0) * 40.0).to_i
# 活跃度
@activity = (60.0 + @issues_count / (@issues_count + 80.0) * 40.0).to_i
@platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 80.0) * 40.0).to_i
# 项目经验
@experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count
@experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i
@platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count
@platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i
# 语言能力
@language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i
@platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i
# 语言百分比
@languages_percent = Hash.new
for key in @project_languages_count.keys do
@languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2)
end
# @platform_languages_percent = Hash.new
# for key in @platform_project_languages_count.keys do
# @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2)
# end
# 各门语言分数
@each_language_score = Hash.new
for key in @project_languages_count.keys do
@each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i
end
# @platform_each_language_score = Hash.new
# for key in @platform_project_languages_count.keys do
# @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i
# end
end
end
# 角色定位
def role
full_member_projects = observed_user.full_member_projects
owner_projects = filter_member_projects_by_role("Owner")
manager_projects = filter_member_projects_by_role("Manager").where.not(id: owner_projects.ids)
developer_projects = filter_member_projects_by_role("Developer").where.not(id: owner_projects.ids + manager_projects.ids)
reporter_projects = filter_member_projects_by_role("Reporter").where.not(id: owner_projects.ids + manager_projects.ids + developer_projects.ids)
@full_member_projects_count = full_member_projects.size
@owner_projects_count = owner_projects.size
@manager_projects_count = manager_projects.size
@developer_projects_count = developer_projects.size
@reporter_projects_count = reporter_projects.size
end
# 专业定位
def major
# 参与项目
join_normal_projects_sql = Project.members_projects(observed_user.id).to_sql
join_org_projects_sql = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observed_user.id}).to_sql
# 关注项目
star_projects_sql = Project.joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observed_user.id}).to_sql
# fork项目
fork_projects_sql = Project.where(id: observed_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)).to_sql
major_projects = Project.from("( #{ join_normal_projects_sql} UNION #{ join_org_projects_sql } UNION #{ star_projects_sql } UNION #{fork_projects_sql}) AS projects").distinct
categories = ProjectCategory.joins(:projects).merge(Project.where(id: time_filter(major_projects, 'created_on'))).distinct.pluck(:name)
render :json => {categories: categories}
end
private
def time_filter(collection, time_field)
if params[:start_time].present? && params[:end_time].present?
return collection.where("#{time_field} > ? AND #{time_field} < ?", Time.at(params[:start_time].to_i).beginning_of_day, Time.at(params[:end_time].to_i).end_of_day)
else
return collection
end
rescue
return collection
end
def filter_member_projects_by_role(role)
case role
when 'Owner'
normal_projects_sql = Project.joins(members: :roles).where(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql
org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "owner"}, team_users: {user_id: observed_user.id}).to_sql
when "Manager"
normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql
org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "admin"}, team_users: {user_id: observed_user.id}).to_sql
when "Developer"
normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Developer'}).to_sql
org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "write"}, team_users: {user_id: observed_user.id}).to_sql
when "Reporter"
normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Reporter'}).to_sql
org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "read"}, team_users: {user_id: observed_user.id}).to_sql
end
return time_filter(Project.from("( #{normal_projects_sql} UNION #{org_projects_sql} ) AS projects").distinct, 'created_on')
end
def preload_develop_data
if params[:start_time].present? && params[:end_time].present?
# 用户被follow数量
@follow_count = time_filter(Watcher.where(watchable: observed_user), 'created_at').count
@platform_follow_count = time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count
# 用户pr数量
@pullrequest_count = time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count
@platform_pullrequest_count = time_filter(PullRequest, 'created_at').count
# 用户issue数量
@issues_count = time_filter(Issue.where(author_id: observed_user.id), 'created_on').count
@platform_issues_count = time_filter(Issue, 'created_on').count
# 用户总项目数
@project_count = time_filter(Project.where(user_id:observed_user.id), 'created_on').count
@platform_project_count = time_filter(Project, 'created_on').count
# 用户项目被fork数量
@fork_count = time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count")
@platform_fork_count = time_filter(Project, 'created_on').sum("forked_count")
# 用户项目关注数
@project_watchers_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count")
@platform_project_watchers_count = time_filter(Project, 'created_on').sum("watchers_count")
# 用户项目点赞数
@project_praises_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count")
@platform_project_praises_count = time_filter(Project, 'created_on').sum("praises_count")
# 用户不同语言项目数量
@project_languages_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count
@platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count
else
@platform_result = Cache::V2::PlatformStatisticService.new.read
@user_result = Cache::V2::UserStatisticService.new(observed_user.id).read
# 用户被follow数量
@follow_count = @user_result["follow-count"].to_i
@platform_follow_count = @platform_result["follow-count"].to_i
# 用户pr数量
@pullrequest_count = @user_result["pullrequest-count"].to_i
@platform_pullrequest_count = @platform_result["pullrequest-count"].to_i
# 用户issue数量
@issues_count = @user_result["issue-count"].to_i
@platform_issues_count = @platform_result["issue-count"].to_i
# 用户总项目数
@project_count = @user_result["project-count"].to_i
@platform_project_count = @platform_result["project-count"].to_i
# 用户项目被fork数量
@fork_count = @user_result["fork-count"].to_i
@platform_fork_count = @platform_result["fork-count"].to_i
# 用户项目关注数
@project_watchers_count = @user_result["project-watcher-count"].to_i
@platform_project_watchers_count = @platform_result["project-watcher-count"].to_i
# 用户项目点赞数
@project_praises_count = @user_result["project-praise-count"].to_i
@platform_project_praises_count = @platform_result["project-praise-count"].to_i
# 用户不同语言项目数量
@project_languages_count = JSON.parse(@user_result["project-language"])
@platform_project_languages_count = JSON.parse(@platform_result["project-language"])
end
end
end
def count_filter(collection, count_field, countf)
return collection.where("#{count_field} >= ?", countf)
end
# 判断是否拥有
def judge_have(judged, count)
return judged >= count ? 1 : 0
end
# 判断等级
def judge_level(judged, low, mid, high)
if judged < low
return 0
elsif judged < mid
return 1
elsif judged < high
return 2
else
return 3
end
end
###############change###############
# 用户badges 接口 url 路径为/api/users/:user_id/statistic/badges
# 三类
# 第一类 贡献类
# 2.用户有项目获得高星
# 3.用户有数个高星项目
# 4.用户拥有一个点赞数很高的项目
# 5.用户拥有数个点赞数很高的项目
# 6. 用户关注数超过10人
# 7. 用户的累积获赞人数
# 8. 用户累积pr数
# 第二类 活动类
# 第三类 活跃类
# 1. 用户拥有10个项目以上
# 2. 用户连续一周/月有commit
# 3. 用户涨粉迅速
def preload_badge_data
badge_describe
cache_describe
#加载缓存资源
load_redis
#存放用户获得的徽章字典
@badges_dic = Hash.new(0)
# 有些数据可以考虑直接从缓存中读取,由于题目要求不能破坏原本的函数,暂时缓存写了直接查询,
# 例如 Watcher.where(watchable: observed_user).count 可以用@user_result["follow-count"]来替代
#
@user_result = Cache::V2::UserStatisticService.new(observed_user.id).read
# 用户项目获得的徽章
#用户语言数量 y
# 用户项目数量 y
project_count = @user_result["project-count"].to_i
if project_count > 10
@badges_dic["project_count"] = project_count
end
# 用户点赞数量 y
# 用户项目被follow数量
praises_project_count = count_filter(Project.where(user_id:observed_user.id), 'praises_count' , 10).count
praises_project = Project.where(user_id:observed_user.id).maximum('praises_count')
watchers_project_count = count_filter(Project.where(user_id:observed_user.id), 'watchers_count' , 10).count
watchers_project = Project.where(user_id:observed_user.id).maximum('watchers_count')
# 项目数
@many_projects = judge_have(project_count, 5)
redis_judge_reload @many_projects_cache, @many_projects
@badges_dic["many_projects"] = $redis_cache.hget(user_statistic_key, @many_projects_cache).to_i
# 用户有超过五个以上的高点赞项目
@manyParisesProject = judge_have(praises_project_count, 5)
redis_judge_reload @manyParisesProject_cache, @manyParisesProject
@badges_dic["manyParisesProject"] = $redis_cache.hget(user_statistic_key, @manyParisesProject_cache).to_i
#用户有一个点赞数很高的项目 金/银/铜
@parises_project = judge_level(praises_project, 3, 5, 10)
redis_judge_reload @many_projects_cache, @parises_project
@badges_dic["parises_project"] = $redis_cache.hget(user_statistic_key, @parises_project_cache).to_i
# 用户有超过五个以上的高关注项目
@manyWatchersProject = judge_have(watchers_project_count, 5)
redis_judge_reload @manyWatchersProject_cache, @manyWatchersProject
@badges_dic["manyWatchersProject"] = $redis_cache.hget(user_statistic_key, @manyWatchersProject_cache).to_i
#用户有一个关注数很高的项目 金/银/铜
@watchers_project = judge_level(watchers_project, 3, 5, 10)
redis_judge_reload @watchers_project_cache, @watchers_project
@badges_dic["watchers_project"] = $redis_cache.hget(user_statistic_key, @watchers_project_cache).to_i
# 用户被follow数量 y
fans = Watcher.where(watchable: observed_user).count
# 用户pr数量 y
pr = PullRequest.where(user_id: observed_user.id).count
# 用户issue数量 y
issue = Issue.where(author_id: observed_user.id).count
#用户有关注数很多 金/银/铜
@many_fans = judge_level(fans, 5, 50, 100)
redis_judge_reload @many_fans_cache, @many_fans
@badges_dic["many_fans"] = $redis_cache.hget(user_statistic_key, @many_fans_cache).to_i
#用户pr很多 金/银/铜
@many_pr = judge_level(pr, 5, 50, 100)
redis_judge_reload @many_pr_cache, @many_pr
@badges_dic["many_pr"] = $redis_cache.hget(user_statistic_key, @many_pr_cache).to_i
#用户issue很多 金/银/铜
@many_issue = judge_level(issue, 5, 50, 100)
redis_judge_reload @many_issue_cache, @many_issue
@badges_dic["many_issue"] = $redis_cache.hget(user_statistic_key, @many_issue_cache).to_i
#一周内活跃
commit_request = Gitea::User::HeadmapService.call(observed_user.login, 1.week.ago.to_date.to_time.to_i, Date.today.to_time.to_i)
commit_data = commit_request[2]
active_commit = commit_data.select{|item| item["contributions"] >= 1}.size
@active_in_week = active_commit == 7 ? 1 : 0
@badges_dic["active_in_week"] = $redis_cache.hget(user_statistic_key, @active_in_week_cache).to_i
#TODO fans_raise_quickly
end
def user_statistic_key
"user:#{@user_id}"
end
def redis_judge_reload(judge_cache, new_value)
if $redis_cache.hget(user_statistic_key, judge_cache).to_i != new_value
$redis_cache.del(user_statistic_key)
updateService judge_cache, new_value
load_redis
end
end
def cache_describe
@many_projects_cache = "many_projects"
@manyParisesProject_cache = "manyParisesProject"
@parises_project_cache = "parises_project"
@manyWatchersProject_cache = "manyWatchersProject"
@watchers_project_cache = "watchers_project"
@many_fans_cache = "many_fans"
@many_pr_cache = "many_pr"
@many_issue_cache = "many_issue"
@active_in_week_cache = "active_in_week"
end
def badge_describe
@badges_describe_dic = Hash.new(0)
@badges_describe_dic["many_projects"] = "参与了多个project"
@badges_describe_dic["manyParisesProject"] = "有多个点赞数高的project"
@badges_describe_dic["parises_project"] = "有一个项目获得了很高的点赞数!"
@badges_describe_dic["manyWatchersProject"] = "有多个关注三诉讼诉讼诉讼诉讼诉讼诉讼数高的project"
@badges_describe_dic["watchers_project"] = "有一个项目获得了很高的关注数!"
@badges_describe_dic["watchers_project"] = "有一个项目获得了很高的关注数!"
@badges_describe_dic["many_fans"] = "粉丝数很多!"
@badges_describe_dic["many_fans"] = "贡献了很多pr"
@badges_describe_dic["many_pr"] = "贡献了很多issue"
@badges_describe_dic["many_issue"] = "粉丝数很多!"
@badges_describe_dic["active_in_week"] = "一周活跃打卡成就!"
end
def load_redis
@badge = Badge.find_or_create_by(user_id: observed_user.id)
$redis_cache.hset(user_statistic_key, @many_projects_cache, @badge.many_projects)
$redis_cache.hset(user_statistic_key, @manyParisesProject_cache, @badge.manyParisesProject)
$redis_cache.hset(user_statistic_key, @parises_project_cache, @badge.parises_project)
$redis_cache.hset(user_statistic_key, @manyWatchersProject_cache, @badge.manyWatchersProject)
$redis_cache.hset(user_statistic_key, @watchers_project_cache, @badge.watchers_project)
$redis_cache.hset(user_statistic_key, @many_fans_cache, @badge.many_fans)
$redis_cache.hset(user_statistic_key, @many_pr_cache, @badge.many_pr)
$redis_cache.hset(user_statistic_key, @many_issue_cache, @badge.many_issue)
$redis_cache.hset(user_statistic_key, @active_in_week_cache, @badge.active_in_week)
end
def updateService(update_name, update_value)
#添加事务,如果更新失败则回滚
ActiveRecord::Base.transaction do
@badge = Badge.find_or_create_by!(user_id: observed_user.id)
@badge.update_attributes!(update_name => update_value)
@badge.save!
end
end